Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b1abc4b authored by Ziyang Cheng's avatar Ziyang Cheng
Browse files

Expose SoundTriggerManager apis as SystemApi

-Expose RecognitionConfig as SystemApi.

API-Coverage-Bug:342000018

Bug: 339267254
Flag: android.media.soundtrigger.manager_api
Test: Successfully load the generic sound model and verify
      sound trigger event could be triggered correctly on
      Pixel Watch devices.
Change-Id: I5a55638fd492688d19f9a3f7c27581e5b7724e0d
parent 223c40c1
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -6822,6 +6822,17 @@ package android.hardware.soundtrigger {
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.ModuleProperties> CREATOR;
  }
  @FlaggedApi("android.media.soundtrigger.manager_api") public static final class SoundTrigger.RecognitionConfig implements android.os.Parcelable {
    method public int describeContents();
    method public int getAudioCapabilities();
    method @NonNull public byte[] getData();
    method @NonNull public java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra> getKeyphrases();
    method public boolean isAllowMultipleTriggers();
    method public boolean isCaptureRequested();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.RecognitionConfig> CREATOR;
  }
  public static class SoundTrigger.RecognitionEvent {
    method @Nullable public android.media.AudioFormat getCaptureFormat();
    method public int getCaptureSession();
@@ -7772,10 +7783,16 @@ package android.media.soundtrigger {
    method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void deleteModel(java.util.UUID);
    method public int getDetectionServiceOperationsTimeout();
    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
    method @FlaggedApi("android.media.soundtrigger.manager_api") @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int getModelState(@NonNull java.util.UUID);
    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModuleProperties getModuleProperties();
    method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int getParameter(@NonNull java.util.UUID, int);
    method @FlaggedApi("android.media.soundtrigger.manager_api") @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public boolean isRecognitionActive(@NonNull java.util.UUID);
    method @FlaggedApi("android.media.soundtrigger.manager_api") @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int loadSoundModel(@NonNull android.hardware.soundtrigger.SoundTrigger.SoundModel);
    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModelParamRange queryParameter(@Nullable java.util.UUID, int);
    method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int setParameter(@Nullable java.util.UUID, int, int);
    method @FlaggedApi("android.media.soundtrigger.manager_api") @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int startRecognition(@NonNull java.util.UUID, @Nullable android.os.Bundle, @NonNull android.content.ComponentName, @NonNull android.hardware.soundtrigger.SoundTrigger.RecognitionConfig);
    method @FlaggedApi("android.media.soundtrigger.manager_api") @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int stopRecognition(@NonNull java.util.UUID);
    method @FlaggedApi("android.media.soundtrigger.manager_api") @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int unloadSoundModel(@NonNull java.util.UUID);
    method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
  }
+2 −11
Original line number Diff line number Diff line
@@ -1885,17 +1885,9 @@ package android.hardware.soundtrigger {
    ctor public SoundTrigger.ModuleProperties(int, @NonNull String, @NonNull String, @NonNull String, int, @NonNull String, int, int, int, int, boolean, int, boolean, int, boolean, int);
  }

  public static final class SoundTrigger.RecognitionConfig implements android.os.Parcelable {
  @FlaggedApi("android.media.soundtrigger.manager_api") public static final class SoundTrigger.RecognitionConfig implements android.os.Parcelable {
    ctor public SoundTrigger.RecognitionConfig(boolean, boolean, @Nullable android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra[], @Nullable byte[], int);
    ctor public SoundTrigger.RecognitionConfig(boolean, boolean, @Nullable android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra[], @Nullable byte[]);
    method public int describeContents();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.RecognitionConfig> CREATOR;
    field public final boolean allowMultipleTriggers;
    field public final int audioCapabilities;
    field public final boolean captureRequested;
    field @NonNull public final byte[] data;
    field @NonNull public final android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra[] keyphrases;
  }

  public static class SoundTrigger.RecognitionEvent {
@@ -2216,7 +2208,7 @@ package android.media.soundtrigger {
  public class SoundTriggerInstrumentation.RecognitionSession {
    method public void clearRecognitionCallback();
    method public int getAudioSession();
    method @NonNull public android.hardware.soundtrigger.SoundTrigger.RecognitionConfig getRecognitionConfig();
    method @FlaggedApi("android.media.soundtrigger.manager_api") @NonNull public android.hardware.soundtrigger.SoundTrigger.RecognitionConfig getRecognitionConfig();
    method public void setRecognitionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.soundtrigger.SoundTriggerInstrumentation.RecognitionCallback);
    method public void triggerAbortRecognition();
    method public void triggerRecognitionEvent(@NonNull byte[], @Nullable java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
@@ -2227,7 +2219,6 @@ package android.media.soundtrigger {
    method @NonNull public android.media.soundtrigger.SoundTriggerManager createManagerForModule(@NonNull android.hardware.soundtrigger.SoundTrigger.ModuleProperties);
    method @NonNull public android.media.soundtrigger.SoundTriggerManager createManagerForTestModule();
    method @NonNull public static java.util.List<android.hardware.soundtrigger.SoundTrigger.ModuleProperties> listModuleProperties();
    method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int loadSoundModel(@NonNull android.hardware.soundtrigger.SoundTrigger.SoundModel);
  }

  public static class SoundTriggerManager.Model {
+7 −7
Original line number Diff line number Diff line
@@ -155,16 +155,16 @@ public class ConversionUtil {
    public static RecognitionConfig api2aidlRecognitionConfig(
            SoundTrigger.RecognitionConfig apiConfig) {
        RecognitionConfig aidlConfig = new RecognitionConfig();
        aidlConfig.captureRequested = apiConfig.captureRequested;
        // apiConfig.allowMultipleTriggers is ignored by the lower layers.
        aidlConfig.captureRequested = apiConfig.isCaptureRequested();
        // apiConfig.isAllowMultipleTriggers() is ignored by the lower layers.
        aidlConfig.phraseRecognitionExtras =
                new PhraseRecognitionExtra[apiConfig.keyphrases.length];
        for (int i = 0; i < apiConfig.keyphrases.length; ++i) {
                new PhraseRecognitionExtra[apiConfig.getKeyphrases().size()];
        for (int i = 0; i < apiConfig.getKeyphrases().size(); ++i) {
            aidlConfig.phraseRecognitionExtras[i] = api2aidlPhraseRecognitionExtra(
                    apiConfig.keyphrases[i]);
                    apiConfig.getKeyphrases().get(i));
        }
        aidlConfig.data = Arrays.copyOf(apiConfig.data, apiConfig.data.length);
        aidlConfig.audioCapabilities = api2aidlAudioCapabilities(apiConfig.audioCapabilities);
        aidlConfig.data = Arrays.copyOf(apiConfig.getData(), apiConfig.getData().length);
        aidlConfig.audioCapabilities = api2aidlAudioCapabilities(apiConfig.getAudioCapabilities());
        return aidlConfig;
    }

+104 −54
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.UUID;
@@ -1513,50 +1514,56 @@ public class SoundTrigger {
     *  A RecognitionConfig is provided to
     *  {@link SoundTriggerModule#startRecognition(int, RecognitionConfig)} to configure the
     *  recognition request.
     *
     *  @hide
     */
    @TestApi
    @FlaggedApi(android.media.soundtrigger.Flags.FLAG_MANAGER_API)
    public static final class RecognitionConfig implements Parcelable {
        /** True if the DSP should capture the trigger sound and make it available for further
         * capture. */
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        public final boolean captureRequested;
        /**
         * True if the service should restart listening after the DSP triggers.
         * Note: This config flag is currently used at the service layer rather than by the DSP.
         */
        public final boolean allowMultipleTriggers;
        /** List of all keyphrases in the sound model for which recognition should be performed with
         * options for each keyphrase. */
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        @NonNull
        @SuppressLint("ArrayReturn")
        public final KeyphraseRecognitionExtra keyphrases[];
        /** Opaque data for use by system applications who know about voice engine internals,
         * typically during enrollment. */
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        @NonNull
        public final byte[] data;
        private final boolean mCaptureRequested;
        private final boolean mAllowMultipleTriggers;
        private final KeyphraseRecognitionExtra mKeyphrases[];
        private final byte[] mData;
        @ModuleProperties.AudioCapabilities
        private final int mAudioCapabilities;

        /**
         * Bit field encoding of the AudioCapabilities
         * supported by the firmware.
         * Constructor for {@link RecognitionConfig} with {@code audioCapabilities} describes a
         * config that can be used by
         * {@link SoundTriggerModule#startRecognition(int, RecognitionConfig)}
         *
         * @param captureRequested Whether the DSP should capture the trigger sound.
         * @param allowMultipleTriggers Whether the service should restart listening after the DSP
         *                              triggers.
         * @param keyphrases List of keyphrases in the sound model.
         * @param data Opaque data for use by system applications who know about voice engine
         *             internals, typically during enrollment.
         * @param audioCapabilities Bit field encoding of the AudioCapabilities.
         *
         * @hide
         */
        @ModuleProperties.AudioCapabilities
        public final int audioCapabilities;

        @TestApi
        public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers,
                @SuppressLint("ArrayReturn") @Nullable KeyphraseRecognitionExtra[] keyphrases,
                @Nullable byte[] data, int audioCapabilities) {
            this.captureRequested = captureRequested;
            this.allowMultipleTriggers = allowMultipleTriggers;
            this.keyphrases = keyphrases != null ? keyphrases : new KeyphraseRecognitionExtra[0];
            this.data = data != null ? data : new byte[0];
            this.audioCapabilities = audioCapabilities;
            this.mCaptureRequested = captureRequested;
            this.mAllowMultipleTriggers = allowMultipleTriggers;
            this.mKeyphrases = keyphrases != null ? keyphrases : new KeyphraseRecognitionExtra[0];
            this.mData = data != null ? data : new byte[0];
            this.mAudioCapabilities = audioCapabilities;
        }

        /**
         * Constructor for {@link RecognitionConfig} without audioCapabilities. The
         * audioCapabilities is set to 0.
         *
         * @param captureRequested Whether the DSP should capture the trigger sound.
         * @param allowMultipleTriggers Whether the service should restart listening after the DSP
         *                              triggers.
         * @param keyphrases List of keyphrases in the sound model.
         * @param data Opaque data for use by system applications.
         *
         * @hide
         */
        @UnsupportedAppUsage
        @TestApi
        public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers,
                @SuppressLint("ArrayReturn") @Nullable KeyphraseRecognitionExtra[] keyphrases,
                @Nullable byte[] data) {
@@ -1574,9 +1581,52 @@ public class SoundTrigger {
            }
        };

        /**
         * Returns whether the DSP should capture the trigger sound and make it available for
         * further capture.
         */
        public boolean isCaptureRequested() {
            return mCaptureRequested;
        }

        /**
         * Returns whether the service should restart listening after the DSP triggers.
         *
         * <p><b>Note:</b> This config flag is currently used at the service layer rather than by
         * the DSP.
         */
        public boolean isAllowMultipleTriggers() {
            return mAllowMultipleTriggers;
        }

        /**
         * Gets all keyphrases in the sound model for which recognition should be performed with
         * options for each keyphrase.
         */
        @NonNull
        public List<KeyphraseRecognitionExtra> getKeyphrases() {
            return Arrays.asList(mKeyphrases);
        }

        /**
         * Opaque data.
         *
         * <p>For use by system applications who knows about voice engine internals, typically
         * during enrollment.
         */
        @NonNull
        public byte[] getData() {
            return mData;
        }

        /** Bit field encoding of the AudioCapabilities supported by the firmware. */
        public int getAudioCapabilities() {
            return mAudioCapabilities;
        }

        private static RecognitionConfig fromParcel(Parcel in) {
            boolean captureRequested = in.readByte() == 1;
            boolean allowMultipleTriggers = in.readByte() == 1;
            boolean captureRequested = in.readBoolean();
            boolean allowMultipleTriggers = in.readBoolean();
            KeyphraseRecognitionExtra[] keyphrases =
                    in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
            byte[] data = in.readBlob();
@@ -1587,11 +1637,11 @@ public class SoundTrigger {

        @Override
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            dest.writeByte((byte) (captureRequested ? 1 : 0));
            dest.writeByte((byte) (allowMultipleTriggers ? 1 : 0));
            dest.writeTypedArray(keyphrases, flags);
            dest.writeBlob(data);
            dest.writeInt(audioCapabilities);
            dest.writeBoolean(mCaptureRequested);
            dest.writeBoolean(mAllowMultipleTriggers);
            dest.writeTypedArray(mKeyphrases, flags);
            dest.writeBlob(mData);
            dest.writeInt(mAudioCapabilities);
        }

        @Override
@@ -1601,10 +1651,10 @@ public class SoundTrigger {

        @Override
        public String toString() {
            return "RecognitionConfig [captureRequested=" + captureRequested
                    + ", allowMultipleTriggers=" + allowMultipleTriggers + ", keyphrases="
                    + Arrays.toString(keyphrases) + ", data=" + Arrays.toString(data)
                    + ", audioCapabilities=" + Integer.toHexString(audioCapabilities) + "]";
            return "RecognitionConfig [captureRequested=" + mCaptureRequested
                    + ", allowMultipleTriggers=" + mAllowMultipleTriggers + ", keyphrases="
                    + Arrays.toString(mKeyphrases) + ", data=" + Arrays.toString(mData)
                    + ", audioCapabilities=" + Integer.toHexString(mAudioCapabilities) + "]";
        }

        @Override
@@ -1616,19 +1666,19 @@ public class SoundTrigger {
            if (!(obj instanceof RecognitionConfig))
                return false;
            RecognitionConfig other = (RecognitionConfig) obj;
            if (captureRequested != other.captureRequested) {
            if (mCaptureRequested != other.mCaptureRequested) {
                return false;
            }
            if (allowMultipleTriggers != other.allowMultipleTriggers) {
            if (mAllowMultipleTriggers != other.mAllowMultipleTriggers) {
                return false;
            }
            if (!Arrays.equals(keyphrases, other.keyphrases)) {
            if (!Arrays.equals(mKeyphrases, other.mKeyphrases)) {
                return false;
            }
            if (!Arrays.equals(data, other.data)) {
            if (!Arrays.equals(mData, other.mData)) {
                return false;
            }
            if (audioCapabilities != other.audioCapabilities) {
            if (mAudioCapabilities != other.mAudioCapabilities) {
                return false;
            }
            return true;
@@ -1638,11 +1688,11 @@ public class SoundTrigger {
        public final int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + (captureRequested ? 1 : 0);
            result = prime * result + (allowMultipleTriggers ? 1 : 0);
            result = prime * result + Arrays.hashCode(keyphrases);
            result = prime * result + Arrays.hashCode(data);
            result = prime * result + audioCapabilities;
            result = prime * result + (mCaptureRequested ? 1 : 0);
            result = prime * result + (mAllowMultipleTriggers ? 1 : 0);
            result = prime * result + Arrays.hashCode(mKeyphrases);
            result = prime * result + Arrays.hashCode(mData);
            result = prime * result + mAudioCapabilities;
            return result;
        }
    }
+2 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.media.soundtrigger;

import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -328,6 +329,7 @@ public final class SoundTriggerInstrumentation {
         * Get the recognition config used to start this recognition.
         * @return - The config passed to the HAL for startRecognition.
         */
        @FlaggedApi(Flags.FLAG_MANAGER_API)
        public @NonNull SoundTrigger.RecognitionConfig getRecognitionConfig() {
            return mRecognitionConfig;
        }
Loading