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

Commit ad7dd8fe authored by Ahaan Ugale's avatar Ahaan Ugale Committed by Android (Google) Code Review
Browse files

Merge changes from topics "aohd-invalidate", "eventpayload-data"

* changes:
  API to destroy active detectors
  expose HAL keyphrase trigger extras to EventPayload
  expose HAL keyphrase trigger data to EventPayload
parents 9f6fafe8 935e33f4
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -5176,6 +5176,15 @@ package android.hardware.soundtrigger {
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.Keyphrase> CREATOR;
  }
  public static final class SoundTrigger.KeyphraseRecognitionExtra implements android.os.Parcelable {
    method public int describeContents();
    method public int getCoarseConfidenceLevel();
    method public int getKeyphraseId();
    method public int getRecognitionModes();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra> CREATOR;
  }
  public static final class SoundTrigger.KeyphraseSoundModel extends android.hardware.soundtrigger.SoundTrigger.SoundModel implements android.os.Parcelable {
    ctor public SoundTrigger.KeyphraseSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], @Nullable android.hardware.soundtrigger.SoundTrigger.Keyphrase[], int);
    ctor public SoundTrigger.KeyphraseSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], @Nullable android.hardware.soundtrigger.SoundTrigger.Keyphrase[]);
@@ -11760,8 +11769,13 @@ package android.service.voice {
  public static class AlwaysOnHotwordDetector.EventPayload {
    method @Nullable public android.os.ParcelFileDescriptor getAudioStream();
    method @Nullable public android.media.AudioFormat getCaptureAudioFormat();
    method @Nullable public byte[] getData();
    method public int getDataFormat();
    method @Nullable public android.service.voice.HotwordDetectedResult getHotwordDetectedResult();
    method @Nullable public byte[] getTriggerAudio();
    method @NonNull public java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra> getKeyphraseRecognitionExtras();
    method @Deprecated @Nullable public byte[] getTriggerAudio();
    field public static final int DATA_FORMAT_RAW = 0; // 0x0
    field public static final int DATA_FORMAT_TRIGGER_AUDIO = 1; // 0x1
  }
  public static final class AlwaysOnHotwordDetector.ModelParamRange {
@@ -11832,6 +11846,7 @@ package android.service.voice {
  }
  public interface HotwordDetector {
    method public default void destroy();
    method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition();
    method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle);
    method public boolean stopRecognition();
+17 −0
Original line number Diff line number Diff line
@@ -1279,6 +1279,10 @@ package android.hardware.soundtrigger {
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.KeyphraseMetadata> CREATOR;
  }

  public static final class SoundTrigger.KeyphraseRecognitionExtra implements android.os.Parcelable {
    ctor public SoundTrigger.KeyphraseRecognitionExtra(int, int, int);
  }

  public static final class SoundTrigger.ModelParamRange implements android.os.Parcelable {
    ctor public SoundTrigger.ModelParamRange(int, int);
  }
@@ -2401,6 +2405,19 @@ package android.service.voice {
    method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]);
  }

  public static final class AlwaysOnHotwordDetector.EventPayload.Builder {
    ctor public AlwaysOnHotwordDetector.EventPayload.Builder();
    method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload build();
    method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setAudioStream(@NonNull android.os.ParcelFileDescriptor);
    method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setCaptureAudioFormat(@NonNull android.media.AudioFormat);
    method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setCaptureAvailable(boolean);
    method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setCaptureSession(int);
    method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setData(@NonNull byte[]);
    method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setDataFormat(int);
    method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setHotwordDetectedResult(@NonNull android.service.voice.HotwordDetectedResult);
    method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setKeyphraseRecognitionExtras(@NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
  }

  public final class VisibleActivityInfo implements android.os.Parcelable {
    ctor public VisibleActivityInfo(int, @NonNull android.os.IBinder);
  }
+96 −21
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
import java.util.UUID;

@@ -1578,29 +1579,56 @@ public class SoundTrigger {
    /**
     * Additional data conveyed by a {@link KeyphraseRecognitionEvent}
     * for a key phrase detection.
     */
    public static final class KeyphraseRecognitionExtra implements Parcelable {
        /**
         * The keyphrase ID
         *
         * @hide
         */
    public static class KeyphraseRecognitionExtra implements Parcelable {
        /** The keyphrase ID */
        @UnsupportedAppUsage
        public final int id;

        /** Recognition modes matched for this event */
        /**
         * Recognition modes matched for this event
         *
         * @hide
         */
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        public final int recognitionModes;

        /** Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification
         * is not performed */
        /**
         * Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification
         * is not performed
         *
         * @hide
         */
        @UnsupportedAppUsage
        public final int coarseConfidenceLevel;

        /** Confidence levels for all users recognized (KeyphraseRecognitionEvent) or to
         * be recognized (RecognitionConfig) */
        /**
         * Confidence levels for all users recognized (KeyphraseRecognitionEvent) or to
         * be recognized (RecognitionConfig)
         *
         * @hide
         */
        @UnsupportedAppUsage
        @NonNull
        public final ConfidenceLevel[] confidenceLevels;


        /**
         * @hide
         */
        @TestApi
        public KeyphraseRecognitionExtra(int id, @RecognitionModes int recognitionModes,
                int coarseConfidenceLevel) {
            this(id, recognitionModes, coarseConfidenceLevel, new ConfidenceLevel[0]);
        }

        /**
         * @hide
         */
        @UnsupportedAppUsage
        public KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel,
                @Nullable ConfidenceLevel[] confidenceLevels) {
@@ -1611,7 +1639,47 @@ public class SoundTrigger {
                    confidenceLevels != null ? confidenceLevels : new ConfidenceLevel[0];
        }

        public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseRecognitionExtra> CREATOR
        /**
         * The keyphrase ID associated with this class' additional data
         */
        public int getKeyphraseId() {
            return id;
        }

        /**
         * Recognition modes matched for this event
         */
        @RecognitionModes
        public int getRecognitionModes() {
            return recognitionModes;
        }

        /**
         * Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification
         * is not performed
         *
         * <p>The confidence level is expressed in percent (0% -100%).
         */
        public int getCoarseConfidenceLevel() {
            return coarseConfidenceLevel;
        }

        /**
         * Detected confidence level for users defined in a keyphrase.
         *
         * <p>The confidence level is expressed in percent (0% -100%).
         *
         * <p>The user ID is derived from the system ID
         * {@link android.os.UserHandle#getIdentifier()}.
         *
         * @hide
         */
        @NonNull
        public Collection<ConfidenceLevel> getConfidenceLevels() {
            return Arrays.asList(confidenceLevels);
        }

        public static final @NonNull Parcelable.Creator<KeyphraseRecognitionExtra> CREATOR
                = new Parcelable.Creator<KeyphraseRecognitionExtra>() {
            public KeyphraseRecognitionExtra createFromParcel(Parcel in) {
                return KeyphraseRecognitionExtra.fromParcel(in);
@@ -1632,7 +1700,7 @@ public class SoundTrigger {
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            dest.writeInt(id);
            dest.writeInt(recognitionModes);
            dest.writeInt(coarseConfidenceLevel);
@@ -1657,21 +1725,28 @@ public class SoundTrigger {

        @Override
        public boolean equals(@Nullable Object obj) {
            if (this == obj)
            if (this == obj) {
                return true;
            if (obj == null)
            }
            if (obj == null) {
                return false;
            if (getClass() != obj.getClass())
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            KeyphraseRecognitionExtra other = (KeyphraseRecognitionExtra) obj;
            if (!Arrays.equals(confidenceLevels, other.confidenceLevels))
            if (!Arrays.equals(confidenceLevels, other.confidenceLevels)) {
                return false;
            if (id != other.id)
            }
            if (id != other.id) {
                return false;
            if (recognitionModes != other.recognitionModes)
            }
            if (recognitionModes != other.recognitionModes) {
                return false;
            if (coarseConfidenceLevel != other.coarseConfidenceLevel)
            }
            if (coarseConfidenceLevel != other.coarseConfidenceLevel) {
                return false;
            }
            return true;
        }

@@ -1715,7 +1790,7 @@ public class SoundTrigger {
                    keyphraseExtras != null ? keyphraseExtras : new KeyphraseRecognitionExtra[0];
        }

        public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
        public static final @NonNull Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
                = new Parcelable.Creator<KeyphraseRecognitionEvent>() {
            public KeyphraseRecognitionEvent createFromParcel(Parcel in) {
                return KeyphraseRecognitionEvent.fromParcelForKeyphrase(in);
+42 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.service.voice;

import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;

import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
@@ -34,6 +35,9 @@ import android.util.Slog;
import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVoiceInteractionManagerService;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;

/** Base implementation of {@link HotwordDetector}. */
abstract class AbstractHotwordDetector implements HotwordDetector {
    private static final String TAG = AbstractHotwordDetector.class.getSimpleName();
@@ -45,6 +49,8 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
    private final Handler mHandler;
    private final HotwordDetector.Callback mCallback;
    private final int mDetectorType;
    private Consumer<AbstractHotwordDetector> mOnDestroyListener;
    private final AtomicBoolean mIsDetectorActive;

    AbstractHotwordDetector(
            IVoiceInteractionManagerService managerService,
@@ -55,6 +61,7 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
        mHandler = new Handler(Looper.getMainLooper());
        mCallback = callback;
        mDetectorType = detectorType;
        mIsDetectorActive = new AtomicBoolean(true);
    }

    /**
@@ -70,6 +77,7 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
        if (DEBUG) {
            Slog.i(TAG, "#recognizeHotword");
        }
        throwIfDetectorIsNoLongerActive();

        // TODO: consider closing existing session.

@@ -106,6 +114,7 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
        if (DEBUG) {
            Slog.d(TAG, "updateState()");
        }
        throwIfDetectorIsNoLongerActive();
        synchronized (mLock) {
            updateStateLocked(options, sharedMemory, null /* callback */, mDetectorType);
        }
@@ -126,6 +135,35 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
        }
    }

    void registerOnDestroyListener(Consumer<AbstractHotwordDetector> onDestroyListener) {
        synchronized (mLock) {
            if (mOnDestroyListener != null) {
                throw new IllegalStateException("only one destroy listener can be registered");
            }
            mOnDestroyListener = onDestroyListener;
        }
    }

    @CallSuper
    @Override
    public void destroy() {
        if (!mIsDetectorActive.get()) {
            return;
        }
        mIsDetectorActive.set(false);
        synchronized (mLock) {
            mOnDestroyListener.accept(this);
        }
    }

    protected void throwIfDetectorIsNoLongerActive() {
        if (!mIsDetectorActive.get()) {
            Slog.e(TAG, "attempting to use a destroyed detector which is no longer active");
            throw new IllegalStateException(
                    "attempting to use a destroyed detector which is no longer active");
        }
    }

    private static class BinderCallback
            extends IMicrophoneHotwordDetectionVoiceInteractionCallback.Stub {
        private final Handler mHandler;
@@ -146,7 +184,10 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
            mHandler.sendMessage(obtainMessage(
                    HotwordDetector.Callback::onDetected,
                    mCallback,
                    new AlwaysOnHotwordDetector.EventPayload(audioFormat, hotwordDetectedResult)));
                    new AlwaysOnHotwordDetector.EventPayload.Builder()
                            .setCaptureAudioFormat(audioFormat)
                            .setHotwordDetectedResult(hotwordDetectedResult)
                            .build()));
        }
    }
}
+252 −35

File changed.

Preview size limit exceeded, changes collapsed.

Loading