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.ambientcontext; 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.content.Intent; 27 import android.os.Bundle; 28 import android.os.IBinder; 29 import android.os.RemoteCallback; 30 import android.util.Slog; 31 32 import java.util.Objects; 33 import java.util.function.Consumer; 34 35 /** 36 * Abstract base class for {@link AmbientContextEvent} detection service. 37 * 38 * <p> A service that provides requested ambient context events to the system. 39 * The system's default AmbientContextDetectionService implementation is configured in 40 * {@code config_defaultAmbientContextDetectionService}. If this config has no value, a stub is 41 * returned. 42 * 43 * See: {@code AmbientContextManagerService}. 44 * 45 * <pre> 46 * {@literal 47 * <service android:name=".YourAmbientContextDetectionService" 48 * android:permission="android.permission.BIND_AMBIENT_CONTEXT_DETECTION_SERVICE"> 49 * </service>} 50 * </pre> 51 * 52 * @hide 53 */ 54 @SystemApi 55 public abstract class AmbientContextDetectionService extends Service { 56 private static final String TAG = AmbientContextDetectionService.class.getSimpleName(); 57 58 /** 59 * The {@link Intent} that must be declared as handled by the service. To be supported, the 60 * service must also require the 61 * {@link android.Manifest.permission#BIND_AMBIENT_CONTEXT_DETECTION_SERVICE} 62 * permission so that other applications can not abuse it. 63 */ 64 public static final String SERVICE_INTERFACE = 65 "android.service.ambientcontext.AmbientContextDetectionService"; 66 67 @Nullable 68 @Override onBind(@onNull Intent intent)69 public final IBinder onBind(@NonNull Intent intent) { 70 if (SERVICE_INTERFACE.equals(intent.getAction())) { 71 return new IAmbientContextDetectionService.Stub() { 72 /** {@inheritDoc} */ 73 @Override 74 public void startDetection( 75 @NonNull AmbientContextEventRequest request, String packageName, 76 RemoteCallback detectionResultCallback, RemoteCallback statusCallback) { 77 Objects.requireNonNull(request); 78 Objects.requireNonNull(packageName); 79 Objects.requireNonNull(detectionResultCallback); 80 Objects.requireNonNull(statusCallback); 81 Consumer<AmbientContextDetectionResult> detectionResultConsumer = 82 result -> { 83 Bundle bundle = new Bundle(); 84 bundle.putParcelable( 85 AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY, 86 result); 87 detectionResultCallback.sendResult(bundle); 88 }; 89 Consumer<AmbientContextDetectionServiceStatus> statusConsumer = 90 status -> { 91 Bundle bundle = new Bundle(); 92 bundle.putParcelable( 93 AmbientContextDetectionServiceStatus 94 .STATUS_RESPONSE_BUNDLE_KEY, 95 status); 96 statusCallback.sendResult(bundle); 97 }; 98 AmbientContextDetectionService.this.onStartDetection( 99 request, packageName, detectionResultConsumer, statusConsumer); 100 Slog.d(TAG, "startDetection " + request); 101 } 102 103 /** {@inheritDoc} */ 104 @Override 105 public void stopDetection(String packageName) { 106 Objects.requireNonNull(packageName); 107 AmbientContextDetectionService.this.onStopDetection(packageName); 108 } 109 110 /** {@inheritDoc} */ 111 @Override 112 public void queryServiceStatus( 113 @AmbientContextEvent.EventCode int[] eventTypes, 114 String packageName, 115 RemoteCallback callback) { 116 Objects.requireNonNull(eventTypes); 117 Objects.requireNonNull(packageName); 118 Objects.requireNonNull(callback); 119 Consumer<AmbientContextDetectionServiceStatus> consumer = 120 response -> { 121 Bundle bundle = new Bundle(); 122 bundle.putParcelable( 123 AmbientContextDetectionServiceStatus 124 .STATUS_RESPONSE_BUNDLE_KEY, 125 response); 126 callback.sendResult(bundle); 127 }; 128 AmbientContextDetectionService.this.onQueryServiceStatus( 129 eventTypes, packageName, consumer); 130 } 131 }; 132 } 133 return null; 134 } 135 136 /** 137 * Called when a client app requests starting detection of the events in the request. The 138 * implementation should keep track of whether the user has explicitly consented to detecting 139 * the events using on-going ambient sensor (e.g. microphone), and agreed to share the 140 * detection results with this client app. If the user has not consented, the detection 141 * should not start, and the statusConsumer should get a response with STATUS_ACCESS_DENIED. 142 * If the user has made the consent and the underlying services are available, the 143 * implementation should start detection and provide detected events to the 144 * detectionResultConsumer. If the type of event needs immediate attention, the implementation 145 * should send result as soon as detected. Otherwise, the implementation can bulk send response. 146 * The ongoing detection will keep running, until onStopDetection is called. If there were 147 * previously requested detection from the same package, regardless of the type of events in 148 * the request, the previous request will be replaced with the new request. 149 * 150 * @param request The request with events to detect. 151 * @param packageName the requesting app's package name 152 * @param detectionResultConsumer the consumer for the detected event 153 * @param statusConsumer the consumer for the service status. 154 */ 155 @BinderThread 156 public abstract void onStartDetection( 157 @NonNull AmbientContextEventRequest request, 158 @NonNull String packageName, 159 @NonNull Consumer<AmbientContextDetectionResult> detectionResultConsumer, 160 @NonNull Consumer<AmbientContextDetectionServiceStatus> statusConsumer); 161 162 /** 163 * Stops detection of the events. Events that are not being detected will be ignored. 164 * 165 * @param packageName stops detection for the given package. 166 */ 167 public abstract void onStopDetection(@NonNull String packageName); 168 169 /** 170 * Called when a query for the detection status occurs. The implementation should check 171 * the detection status of the requested events for the package, and provide results in a 172 * {@link AmbientContextDetectionServiceStatus} for the consumer. 173 * 174 * @param eventTypes The events to check for status. 175 * @param packageName the requesting app's package name 176 * @param consumer the consumer for the query results 177 */ 178 @BinderThread 179 public abstract void onQueryServiceStatus( 180 @NonNull int[] eventTypes, 181 @NonNull String packageName, 182 @NonNull Consumer<AmbientContextDetectionServiceStatus> consumer); 183 } 184