diff options
| author | 2022-12-18 21:14:43 +0000 | |
|---|---|---|
| committer | 2022-12-30 01:07:16 +0000 | |
| commit | 40aceb5f39e0e8a49b96495b2182b402e4da2017 (patch) | |
| tree | 36be9b5f556d04d9da29b314818ebc8794472dab | |
| parent | 71d7b807bcfe1d9ad2740a18c1cd56f53becf052 (diff) | |
Add SandboxedDetectionServiceBase interface
Added a common interface for both HotwordDetectionService and the
upcoming VisualQueryDectionService that handles baisc functionalities of
initializing the service. Also comes with several refactorization
renaming on relative javadoc to replace hotword detection context into a more general term sandboxed detection.
Bug: 261631429
Test: atest CtsVoiceInteractionTestCases
Change-Id: I1a76f223b14807d972764fbca38207350469ba53
| -rw-r--r-- | core/api/system-current.txt | 15 | ||||
| -rw-r--r-- | core/api/test-current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/service/voice/HotwordDetectionService.java | 63 | ||||
| -rw-r--r-- | core/java/android/service/voice/HotwordDetector.java | 31 | ||||
| -rw-r--r-- | core/java/android/service/voice/SandboxedDetectionServiceBase.java | 119 | 
5 files changed, 165 insertions, 65 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 50c3c78ce9d4..c1b304f39868 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -12399,17 +12399,17 @@ package android.service.voice {      method @NonNull public android.service.voice.HotwordDetectedResult.Builder setScore(int);    } -  public abstract class HotwordDetectionService extends android.app.Service { +  public abstract class HotwordDetectionService extends android.app.Service implements android.service.voice.SandboxedDetectionServiceBase {      ctor public HotwordDetectionService(); -    method public static int getMaxCustomInitializationStatus(); +    method @Deprecated public static int getMaxCustomInitializationStatus();      method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);      method public void onDetect(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload, long, @NonNull android.service.voice.HotwordDetectionService.Callback);      method public void onDetect(@NonNull android.service.voice.HotwordDetectionService.Callback);      method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @NonNull android.service.voice.HotwordDetectionService.Callback);      method public void onStopDetection();      method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer); -    field public static final int INITIALIZATION_STATUS_SUCCESS = 0; // 0x0 -    field public static final int INITIALIZATION_STATUS_UNKNOWN = 100; // 0x64 +    field @Deprecated public static final int INITIALIZATION_STATUS_SUCCESS = 0; // 0x0 +    field @Deprecated public static final int INITIALIZATION_STATUS_UNKNOWN = 100; // 0x64      field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService";    } @@ -12456,6 +12456,13 @@ package android.service.voice {      method @NonNull public android.service.voice.HotwordRejectedResult.Builder setConfidenceLevel(int);    } +  public interface SandboxedDetectionServiceBase { +    method public static int getMaxCustomInitializationStatus(); +    method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer); +    field public static final int INITIALIZATION_STATUS_SUCCESS = 0; // 0x0 +    field public static final int INITIALIZATION_STATUS_UNKNOWN = 100; // 0x64 +  } +    public class VoiceInteractionService extends android.app.Service {      method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);      method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, android.service.voice.AlwaysOnHotwordDetector.Callback); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 1cfd64466911..bb2af73c2b1f 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2560,7 +2560,7 @@ package android.service.voice {      method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setKeyphraseRecognitionExtras(@NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);    } -  public abstract class HotwordDetectionService extends android.app.Service { +  public abstract class HotwordDetectionService extends android.app.Service implements android.service.voice.SandboxedDetectionServiceBase {      field public static final boolean ENABLE_PROXIMITY_RESULT = true;    } diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java index a47c09662a51..f3d4809a19a8 100644 --- a/core/java/android/service/voice/HotwordDetectionService.java +++ b/core/java/android/service/voice/HotwordDetectionService.java @@ -33,7 +33,6 @@ import android.content.Intent;  import android.hardware.soundtrigger.SoundTrigger;  import android.media.AudioFormat;  import android.media.AudioSystem; -import android.os.Bundle;  import android.os.IBinder;  import android.os.IRemoteCallback;  import android.os.ParcelFileDescriptor; @@ -72,22 +71,13 @@ import java.util.function.IntConsumer;   * @hide   */  @SystemApi -public abstract class HotwordDetectionService extends Service { +public abstract class HotwordDetectionService extends Service +        implements SandboxedDetectionServiceBase {      private static final String TAG = "HotwordDetectionService";      private static final boolean DBG = false;      private static final long UPDATE_TIMEOUT_MILLIS = 20000; -    /** @hide */ -    public static final String KEY_INITIALIZATION_STATUS = "initialization_status"; - -    /** -     * The maximum number of initialization status for some application specific failed reasons. -     * -     * @hide -     */ -    public static final int MAXIMUM_NUMBER_OF_INITIALIZATION_STATUS_CUSTOM_ERROR = 2; -      /**       * Feature flag for Attention Service.       * @@ -98,14 +88,22 @@ public abstract class HotwordDetectionService extends Service {      /**       * Indicates that the updated status is successful. +     * +     * @deprecated Replaced with {@link SandboxedDetectionServiceBase#INITIALIZATION_STATUS_SUCCESS}       */ -    public static final int INITIALIZATION_STATUS_SUCCESS = 0; +    @Deprecated +    public static final int INITIALIZATION_STATUS_SUCCESS = +            SandboxedDetectionServiceBase.INITIALIZATION_STATUS_SUCCESS;      /**       * Indicates that the callback wasn’t invoked within the timeout.       * This is used by system. +     * +     * @deprecated Replaced with {@link SandboxedDetectionServiceBase#INITIALIZATION_STATUS_UNKNOWN}       */ -    public static final int INITIALIZATION_STATUS_UNKNOWN = 100; +    @Deprecated +    public static final int INITIALIZATION_STATUS_UNKNOWN = +            SandboxedDetectionServiceBase.INITIALIZATION_STATUS_UNKNOWN;      /**       * Source for the given audio stream. @@ -254,8 +252,11 @@ public abstract class HotwordDetectionService extends Service {       * Note: The value 0 is reserved for success.       *       * @hide +     * @deprecated Replaced with +     * {@link SandboxedDetectionServiceBase#getMaxCustomInitializationStatus()}       */      @SystemApi +    @Deprecated      public static int getMaxCustomInitializationStatus() {          return MAXIMUM_NUMBER_OF_INITIALIZATION_STATUS_CUSTOM_ERROR;      } @@ -305,21 +306,10 @@ public abstract class HotwordDetectionService extends Service {       * {@link AlwaysOnHotwordDetector#updateState(PersistableBundle, SharedMemory)} requests an       * update of the hotword detection parameters.       * -     * @param options Application configuration data to provide to the -     * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable objects or -     * other contents that can be used to communicate with other processes. -     * @param sharedMemory The unrestricted data blob to provide to the -     * {@link HotwordDetectionService}. Use this to provide the hotword models data or other -     * such data to the trusted process. -     * @param callbackTimeoutMillis Timeout in milliseconds for the operation to invoke the -     * statusCallback. -     * @param statusCallback Use this to return the updated result; the allowed values are -     * {@link #INITIALIZATION_STATUS_SUCCESS}, 1<->{@link #getMaxCustomInitializationStatus()}. -     * This is non-null only when the {@link HotwordDetectionService} is being initialized; and it -     * is null if the state is updated after that. -     * +     * {@inheritDoc}       * @hide       */ +    @Override      @SystemApi      public void onUpdateState(              @Nullable PersistableBundle options, @@ -371,23 +361,8 @@ public abstract class HotwordDetectionService extends Service {      private void onUpdateStateInternal(@Nullable PersistableBundle options,              @Nullable SharedMemory sharedMemory, IRemoteCallback callback) { -        IntConsumer intConsumer = null; -        if (callback != null) { -            intConsumer = -                    value -> { -                        if (value > getMaxCustomInitializationStatus()) { -                            throw new IllegalArgumentException( -                                    "The initialization status is invalid for " + value); -                        } -                        try { -                            Bundle status = new Bundle(); -                            status.putInt(KEY_INITIALIZATION_STATUS, value); -                            callback.sendResult(status); -                        } catch (RemoteException e) { -                            throw e.rethrowFromSystemServer(); -                        } -                    }; -        } +        IntConsumer intConsumer = +                SandboxedDetectionServiceBase.createInitializationStatusConsumer(callback);          onUpdateState(options, sharedMemory, UPDATE_TIMEOUT_MILLIS, intConsumer);      } diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java index b7f7d54fc055..669c22b73edc 100644 --- a/core/java/android/service/voice/HotwordDetector.java +++ b/core/java/android/service/voice/HotwordDetector.java @@ -35,7 +35,7 @@ import android.util.AndroidException;  import java.io.PrintWriter;  /** - * Basic functionality for hotword detectors. + * Basic functionality for sandboxed detectors.   *   * @hide   */ @@ -81,7 +81,7 @@ public interface HotwordDetector {      int DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE = 2;      /** -     * Starts hotword recognition. +     * Starts sandboxed detection recognition.       * <p>       * On calling this, the system streams audio from the device microphone to this application's       * {@link HotwordDetectionService}. Audio is streamed until {@link #stopRecognition()} is @@ -107,7 +107,7 @@ public interface HotwordDetector {      boolean startRecognition() throws IllegalDetectorStateException;      /** -     * Stops hotword recognition. +     * Stops sandboxed detection recognition.       *       * @return {@code true} if the request to stop recognition succeeded       * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 @@ -142,14 +142,13 @@ public interface HotwordDetector {              @Nullable PersistableBundle options) throws IllegalDetectorStateException;      /** -     * Set configuration and pass read-only data to hotword detection service. +     * Set configuration and pass read-only data to sandboxed detection service.       * -     * @param options Application configuration data to provide to the -     *         {@link HotwordDetectionService}. PersistableBundle does not allow any remotable -     *         objects or other contents that can be used to communicate with other processes. -     * @param sharedMemory The unrestricted data blob to provide to the -     *         {@link HotwordDetectionService}. Use this to provide the hotword models data or other -     *         such data to the trusted process. +     * @param options Application configuration data to provide to sandboxed detection services. +     * PersistableBundle does not allow any remotable objects or other contents that can be used to +     * communicate with other processes. +     * @param sharedMemory The unrestricted data blob to provide to sandboxed detection services. +     * Use this to provide model data or other such data to the trusted process.       * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33       *         or above and the detector is not able to perform the operation based on the       *         underlying state. This can be thrown even if the state has been checked before @@ -157,19 +156,19 @@ public interface HotwordDetector {       *         and the state of the detector can change concurrently to the caller calling this       *         method.       * @throws IllegalStateException if this HotwordDetector wasn't specified to use a -     *         {@link HotwordDetectionService} when it was created. +     *         sandboxed detection service when it was created.       */      void updateState(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory)              throws IllegalDetectorStateException;      /** -     * Invalidates this hotword detector so that any future calls to this result +     * Invalidates this detector so that any future calls to this result       * in an {@link IllegalStateException} when a caller has a target SDK below API level 33       * or an {@link IllegalDetectorStateException} when a caller has a target SDK of API level 33       * or above.       *       * <p>If there are no other {@link HotwordDetector} instances linked to the -     * {@link HotwordDetectionService}, the service will be shutdown. +     * sandboxed detection service, the service will be shutdown.       */      default void destroy() {          throw new UnsupportedOperationException("Not implemented. Must override in a subclass."); @@ -249,9 +248,9 @@ public interface HotwordDetector {           * short amount of time to report its initialization state.           *           * @param status Info about initialization state of {@link HotwordDetectionService}; the -         * allowed values are {@link HotwordDetectionService#INITIALIZATION_STATUS_SUCCESS}, -         * 1<->{@link HotwordDetectionService#getMaxCustomInitializationStatus()}, -         * {@link HotwordDetectionService#INITIALIZATION_STATUS_UNKNOWN}. +         * allowed values are {@link SandboxedDetectionServiceBase#INITIALIZATION_STATUS_SUCCESS}, +         * 1<->{@link SandboxedDetectionServiceBase#getMaxCustomInitializationStatus()}, +         * {@link SandboxedDetectionServiceBase#INITIALIZATION_STATUS_UNKNOWN}.           */          void onHotwordDetectionServiceInitialized(int status); diff --git a/core/java/android/service/voice/SandboxedDetectionServiceBase.java b/core/java/android/service/voice/SandboxedDetectionServiceBase.java new file mode 100644 index 000000000000..43331642bd1e --- /dev/null +++ b/core/java/android/service/voice/SandboxedDetectionServiceBase.java @@ -0,0 +1,119 @@ +/* + * 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.voice; + +import android.annotation.DurationMillisLong; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Bundle; +import android.os.IRemoteCallback; +import android.os.PersistableBundle; +import android.os.RemoteException; +import android.os.SharedMemory; + +import java.util.function.IntConsumer; + +/** + * Base for all sandboxed detection services, providing a common interface for initialization. + * + * @hide + */ +@SystemApi +public interface SandboxedDetectionServiceBase { + +    /** +     * Indicates that the updated status is successful. +     */ +    int INITIALIZATION_STATUS_SUCCESS = 0; + +    /** +     * Indicates that the callback wasn’t invoked within the timeout. +     * This is used by system. +     */ +    int INITIALIZATION_STATUS_UNKNOWN = 100; + +    /** @hide */ +    String KEY_INITIALIZATION_STATUS = "initialization_status"; + +    /** +     * The maximum number of initialization status for some application specific failed reasons. +     * +     * @hide +     */ +    int MAXIMUM_NUMBER_OF_INITIALIZATION_STATUS_CUSTOM_ERROR = 2; + +    /** +     * Returns the maximum number of initialization status for some application specific failed +     * reasons. +     * +     * Note: The value 0 is reserved for success. +     */ +    static int getMaxCustomInitializationStatus() { +        return MAXIMUM_NUMBER_OF_INITIALIZATION_STATUS_CUSTOM_ERROR; +    } + +    /** +     * Creates a {@link IntConsumer} that sends the initialization status to the +     * {@link VoiceInteractionService} via {@link IRemoteCallback}. +     * +     * @hide +     */ +    static IntConsumer createInitializationStatusConsumer(IRemoteCallback callback) { +        IntConsumer intConsumer = null; +        if (callback != null) { +            intConsumer = +                    value -> { +                        if (value > SandboxedDetectionServiceBase +                                .getMaxCustomInitializationStatus()) { +                            throw new IllegalArgumentException( +                                    "The initialization status is invalid for " + value); +                        } +                        try { +                            Bundle status = new Bundle(); +                            status.putInt(KEY_INITIALIZATION_STATUS, value); +                            callback.sendResult(status); +                        } catch (RemoteException e) { +                            throw e.rethrowFromSystemServer(); +                        } +                    }; +        } +        return intConsumer; +    } + +    /** +     * Called when sandboxed detectors that extend {@link HotwordDetector} are created or +     * {@link HotwordDetector#updateState(PersistableBundle, SharedMemory)} requests an +     * update of the sandboxed detection parameters. +     * +     * @param options Application configuration data to provide to sandboxed detection services. +     * PersistableBundle does not allow any remotable objects or other contents that can be used to +     * communicate with other processes. +     * @param sharedMemory The unrestricted data blob to provide to sandboxed detection services. +     * Use this to provide model data or other such data to the trusted process. +     * @param callbackTimeoutMillis Timeout in milliseconds for the operation to invoke the +     * statusCallback. +     * @param statusCallback Use this to return the updated result; the allowed values are +     * {@link #INITIALIZATION_STATUS_SUCCESS}, 1<->{@link #getMaxCustomInitializationStatus()}. +     * This is non-null only when sandboxed detection services are being initialized; and it +     * is null if the state is updated after that. +     */ +    void onUpdateState( +            @Nullable PersistableBundle options, +            @Nullable SharedMemory sharedMemory, +            @DurationMillisLong long callbackTimeoutMillis, +            @Nullable IntConsumer statusCallback); +}  |