1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.service.wearable; 18 19 import android.annotation.BinderThread; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.app.Service; 24 import android.app.ambientcontext.AmbientContextEvent; 25 import android.app.ambientcontext.AmbientContextEventRequest; 26 import android.app.wearable.WearableSensingManager; 27 import android.content.Intent; 28 import android.os.Bundle; 29 import android.os.IBinder; 30 import android.os.ParcelFileDescriptor; 31 import android.os.PersistableBundle; 32 import android.os.RemoteCallback; 33 import android.os.SharedMemory; 34 import android.service.ambientcontext.AmbientContextDetectionResult; 35 import android.service.ambientcontext.AmbientContextDetectionServiceStatus; 36 import android.util.Slog; 37 38 import java.util.Arrays; 39 import java.util.HashSet; 40 import java.util.Objects; 41 import java.util.Set; 42 import java.util.function.Consumer; 43 44 /** 45 * Abstract base class for sensing with wearable devices. An example of this is {@link 46 *AmbientContextEvent} detection. 47 * 48 * <p> A service that provides requested sensing events to the system, such as a {@link 49 *AmbientContextEvent}. The system's default WearableSensingService implementation is configured in 50 * {@code config_defaultWearableSensingService}. If this config has no value, a stub is 51 * returned. 52 * 53 * <p> An implementation of a WearableSensingService should be an isolated service. Using the 54 * "isolatedProcess=true" attribute in the service's configurations. </p> 55 ** 56 * <pre> 57 * {@literal 58 * <service android:name=".YourWearableSensingService" 59 * android:permission="android.permission.BIND_WEARABLE_SENSING_SERVICE" 60 * android:isolatedProcess="true"> 61 * </service>} 62 * </pre> 63 * 64 * <p>The use of "Wearable" here is not the same as the Android Wear platform and should be treated 65 * separately. </p> 66 * 67 * @hide 68 */ 69 @SystemApi 70 public abstract class WearableSensingService extends Service { 71 private static final String TAG = WearableSensingService.class.getSimpleName(); 72 73 /** 74 * The bundle key for this class of object, used in {@code RemoteCallback#sendResult}. 75 * 76 * @hide 77 */ 78 public static final String STATUS_RESPONSE_BUNDLE_KEY = 79 "android.app.wearable.WearableSensingStatusBundleKey"; 80 81 /** 82 * The {@link Intent} that must be declared as handled by the service. To be supported, the 83 * service must also require the 84 * {@link android.Manifest.permission#BIND_WEARABLE_SENSING_SERVICE} 85 * permission so that other applications can not abuse it. 86 */ 87 public static final String SERVICE_INTERFACE = 88 "android.service.wearable.WearableSensingService"; 89 90 @Nullable 91 @Override onBind(@onNull Intent intent)92 public final IBinder onBind(@NonNull Intent intent) { 93 if (SERVICE_INTERFACE.equals(intent.getAction())) { 94 return new IWearableSensingService.Stub() { 95 /** {@inheritDoc} */ 96 @Override 97 public void provideDataStream( 98 ParcelFileDescriptor parcelFileDescriptor, 99 RemoteCallback callback) { 100 Objects.requireNonNull(parcelFileDescriptor); 101 Consumer<Integer> consumer = response -> { 102 Bundle bundle = new Bundle(); 103 bundle.putInt( 104 STATUS_RESPONSE_BUNDLE_KEY, 105 response); 106 callback.sendResult(bundle); 107 }; 108 WearableSensingService.this.onDataStreamProvided( 109 parcelFileDescriptor, consumer); 110 } 111 112 /** {@inheritDoc} */ 113 @Override 114 public void provideData( 115 PersistableBundle data, 116 SharedMemory sharedMemory, 117 RemoteCallback callback) { 118 Objects.requireNonNull(data); 119 Consumer<Integer> consumer = response -> { 120 Bundle bundle = new Bundle(); 121 bundle.putInt( 122 STATUS_RESPONSE_BUNDLE_KEY, 123 response); 124 callback.sendResult(bundle); 125 }; 126 WearableSensingService.this.onDataProvided(data, sharedMemory, consumer); 127 } 128 129 /** {@inheritDoc} */ 130 @Override 131 public void startDetection(@NonNull AmbientContextEventRequest request, 132 String packageName, RemoteCallback detectionResultCallback, 133 RemoteCallback statusCallback) { 134 Objects.requireNonNull(request); 135 Objects.requireNonNull(packageName); 136 Objects.requireNonNull(detectionResultCallback); 137 Objects.requireNonNull(statusCallback); 138 Consumer<AmbientContextDetectionResult> detectionResultConsumer = result -> { 139 Bundle bundle = new Bundle(); 140 bundle.putParcelable( 141 AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY, result); 142 detectionResultCallback.sendResult(bundle); 143 }; 144 Consumer<AmbientContextDetectionServiceStatus> statusConsumer = status -> { 145 Bundle bundle = new Bundle(); 146 bundle.putParcelable( 147 AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY, 148 status); 149 statusCallback.sendResult(bundle); 150 }; 151 WearableSensingService.this.onStartDetection( 152 request, packageName, statusConsumer, detectionResultConsumer); 153 Slog.d(TAG, "startDetection " + request); 154 } 155 156 /** {@inheritDoc} */ 157 @Override 158 public void stopDetection(String packageName) { 159 Objects.requireNonNull(packageName); 160 WearableSensingService.this.onStopDetection(packageName); 161 } 162 163 /** {@inheritDoc} */ 164 @Override 165 public void queryServiceStatus(@AmbientContextEvent.EventCode int[] eventTypes, 166 String packageName, RemoteCallback callback) { 167 Objects.requireNonNull(eventTypes); 168 Objects.requireNonNull(packageName); 169 Objects.requireNonNull(callback); 170 Consumer<AmbientContextDetectionServiceStatus> consumer = response -> { 171 Bundle bundle = new Bundle(); 172 bundle.putParcelable( 173 AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY, 174 response); 175 callback.sendResult(bundle); 176 }; 177 Integer[] events = intArrayToIntegerArray(eventTypes); 178 WearableSensingService.this.onQueryServiceStatus( 179 new HashSet<>(Arrays.asList(events)), packageName, consumer); 180 } 181 182 }; 183 } 184 Slog.w(TAG, "Incorrect service interface, returning null."); 185 return null; 186 } 187 188 /** 189 * Called when a data stream to the wearable is provided. This data stream can be used to obtain 190 * data from a wearable device. It is up to the implementation to maintain the data stream and 191 * close the data stream when it is finished. 192 * 193 * @param parcelFileDescriptor The data stream to the wearable 194 * @param statusConsumer the consumer for the service status. 195 */ 196 @BinderThread 197 public abstract void onDataStreamProvided(@NonNull ParcelFileDescriptor parcelFileDescriptor, 198 @NonNull Consumer<Integer> statusConsumer); 199 200 /** 201 * Called when configurations and read-only data in a {@link PersistableBundle} 202 * can be used by the WearableSensingService and sends the result to the {@link Consumer} 203 * right after the call. It is dependent on the application to define the type of data to 204 * provide. This is used by applications that will also provide an implementation of an isolated 205 * WearableSensingService. If the data was provided successfully 206 * {@link WearableSensingManager#STATUS_SUCCESS} will be provided. 207 * 208 * @param data Application configuration data to provide to the {@link WearableSensingService}. 209 * PersistableBundle does not allow any remotable objects or other contents 210 * that can be used to communicate with other processes. 211 * @param sharedMemory The unrestricted data blob to 212 * provide to the {@link WearableSensingService}. Use this to provide the 213 * sensing models data or other such data to the trusted process. 214 * @param statusConsumer the consumer for the service status. 215 */ 216 @BinderThread 217 public abstract void onDataProvided( 218 @NonNull PersistableBundle data, 219 @Nullable SharedMemory sharedMemory, 220 @NonNull Consumer<Integer> statusConsumer); 221 222 /** 223 * Called when a client app requests starting detection of the events in the request. The 224 * implementation should keep track of whether the user has explicitly consented to detecting 225 * the events using on-going ambient sensor (e.g. microphone), and agreed to share the 226 * detection results with this client app. If the user has not consented, the detection 227 * should not start, and the statusConsumer should get a response with STATUS_ACCESS_DENIED. 228 * If the user has made the consent and the underlying services are available, the 229 * implementation should start detection and provide detected events to the 230 * detectionResultConsumer. If the type of event needs immediate attention, the implementation 231 * should send result as soon as detected. Otherwise, the implementation can batch response. 232 * The ongoing detection will keep running, until onStopDetection is called. If there were 233 * previously requested detections from the same package, regardless of the type of events in 234 * the request, the previous request will be replaced with the new request and pending events 235 * are discarded. 236 * 237 * @param request The request with events to detect. 238 * @param packageName the requesting app's package name 239 * @param statusConsumer the consumer for the service status. 240 * @param detectionResultConsumer the consumer for the detected event 241 */ 242 @BinderThread 243 public abstract void onStartDetection(@NonNull AmbientContextEventRequest request, 244 @NonNull String packageName, 245 @NonNull Consumer<AmbientContextDetectionServiceStatus> statusConsumer, 246 @NonNull Consumer<AmbientContextDetectionResult> detectionResultConsumer); 247 248 /** 249 * Stops detection of the events. Events that are not being detected will be ignored. 250 * 251 * @param packageName stops detection for the given package. 252 */ 253 public abstract void onStopDetection(@NonNull String packageName); 254 255 /** 256 * Called when a query for the detection status occurs. The implementation should check 257 * the detection status of the requested events for the package, and provide results in a 258 * {@link AmbientContextDetectionServiceStatus} for the consumer. 259 * 260 * @param eventTypes The events to check for status. 261 * @param packageName the requesting app's package name 262 * @param consumer the consumer for the query results 263 */ 264 @BinderThread 265 public abstract void onQueryServiceStatus(@NonNull Set<Integer> eventTypes, 266 @NonNull String packageName, 267 @NonNull Consumer<AmbientContextDetectionServiceStatus> consumer); 268 269 @NonNull 270 private static Integer[] intArrayToIntegerArray(@NonNull int[] integerSet) { 271 Integer[] intArray = new Integer[integerSet.length]; 272 int i = 0; 273 for (Integer type : integerSet) { 274 intArray[i++] = type; 275 } 276 return intArray; 277 } 278 } 279