/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.ambientcontext; import android.annotation.BinderThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.Service; import android.app.ambientcontext.AmbientContextEvent; import android.app.ambientcontext.AmbientContextEventRequest; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteCallback; import android.util.Slog; import java.util.Objects; import java.util.function.Consumer; /** * Abstract base class for {@link AmbientContextEvent} detection service. * *

A service that provides requested ambient context events to the system. * The system's default AmbientContextDetectionService implementation is configured in * {@code config_defaultAmbientContextDetectionService}. If this config has no value, a stub is * returned. * * See: {@code AmbientContextManagerService}. * *

 * {@literal
 * 
 * }
 * 
* * @hide */ @SystemApi public abstract class AmbientContextDetectionService extends Service { private static final String TAG = AmbientContextDetectionService.class.getSimpleName(); /** * The {@link Intent} that must be declared as handled by the service. To be supported, the * service must also require the * {@link android.Manifest.permission#BIND_AMBIENT_CONTEXT_DETECTION_SERVICE} * permission so that other applications can not abuse it. */ public static final String SERVICE_INTERFACE = "android.service.ambientcontext.AmbientContextDetectionService"; @Nullable @Override public final IBinder onBind(@NonNull Intent intent) { if (SERVICE_INTERFACE.equals(intent.getAction())) { return new IAmbientContextDetectionService.Stub() { /** {@inheritDoc} */ @Override public void startDetection( @NonNull AmbientContextEventRequest request, String packageName, RemoteCallback detectionResultCallback, RemoteCallback statusCallback) { Objects.requireNonNull(request); Objects.requireNonNull(packageName); Objects.requireNonNull(detectionResultCallback); Objects.requireNonNull(statusCallback); Consumer detectionResultConsumer = result -> { Bundle bundle = new Bundle(); bundle.putParcelable( AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY, result); detectionResultCallback.sendResult(bundle); }; Consumer statusConsumer = status -> { Bundle bundle = new Bundle(); bundle.putParcelable( AmbientContextDetectionServiceStatus .STATUS_RESPONSE_BUNDLE_KEY, status); statusCallback.sendResult(bundle); }; AmbientContextDetectionService.this.onStartDetection( request, packageName, detectionResultConsumer, statusConsumer); Slog.d(TAG, "startDetection " + request); } /** {@inheritDoc} */ @Override public void stopDetection(String packageName) { Objects.requireNonNull(packageName); AmbientContextDetectionService.this.onStopDetection(packageName); } /** {@inheritDoc} */ @Override public void queryServiceStatus( @AmbientContextEvent.EventCode int[] eventTypes, String packageName, RemoteCallback callback) { Objects.requireNonNull(eventTypes); Objects.requireNonNull(packageName); Objects.requireNonNull(callback); Consumer consumer = response -> { Bundle bundle = new Bundle(); bundle.putParcelable( AmbientContextDetectionServiceStatus .STATUS_RESPONSE_BUNDLE_KEY, response); callback.sendResult(bundle); }; AmbientContextDetectionService.this.onQueryServiceStatus( eventTypes, packageName, consumer); } }; } return null; } /** * Called when a client app requests starting detection of the events in the request. The * implementation should keep track of whether the user has explicitly consented to detecting * the events using on-going ambient sensor (e.g. microphone), and agreed to share the * detection results with this client app. If the user has not consented, the detection * should not start, and the statusConsumer should get a response with STATUS_ACCESS_DENIED. * If the user has made the consent and the underlying services are available, the * implementation should start detection and provide detected events to the * detectionResultConsumer. If the type of event needs immediate attention, the implementation * should send result as soon as detected. Otherwise, the implementation can bulk send response. * The ongoing detection will keep running, until onStopDetection is called. If there were * previously requested detection from the same package, regardless of the type of events in * the request, the previous request will be replaced with the new request. * * @param request The request with events to detect. * @param packageName the requesting app's package name * @param detectionResultConsumer the consumer for the detected event * @param statusConsumer the consumer for the service status. */ @BinderThread public abstract void onStartDetection( @NonNull AmbientContextEventRequest request, @NonNull String packageName, @NonNull Consumer detectionResultConsumer, @NonNull Consumer statusConsumer); /** * Stops detection of the events. Events that are not being detected will be ignored. * * @param packageName stops detection for the given package. */ public abstract void onStopDetection(@NonNull String packageName); /** * Called when a query for the detection status occurs. The implementation should check * the detection status of the requested events for the package, and provide results in a * {@link AmbientContextDetectionServiceStatus} for the consumer. * * @param eventTypes The events to check for status. * @param packageName the requesting app's package name * @param consumer the consumer for the query results */ @BinderThread public abstract void onQueryServiceStatus( @NonNull int[] eventTypes, @NonNull String packageName, @NonNull Consumer consumer); }