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

Commit 1ddd35c8 authored by lpeter's avatar lpeter Committed by charleschen
Browse files

Support multiple detectors in VoiceInteractionManagerService

It is possible the Assistant application would like to have
multiple detectors to support different quick phrases at a
given time.

Currently, there is a limitation that only a single detector can
be active at a given time. So we need to change the logic to
support multiple detectors in framework voice interaction, but
all detectors will use the same trusted hotword service.

For multiple detector, we only support one Dsp trusted hotword
detector and one software hotword detector at the same time.

Test: atest CtsVoiceInteractionTestCases
Bug: 193232191
Bug: 243598246
Change-Id: Iee37fbd05d39d8bece685276e59989327ac4c2d1
parent 3001d9d5
Loading
Loading
Loading
Loading
+15 −6
Original line number Diff line number Diff line
@@ -25,7 +25,9 @@ import android.app.ActivityThread;
import android.app.compat.CompatChanges;
import android.media.AudioFormat;
import android.media.permission.Identity;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
@@ -49,19 +51,20 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
    private final IVoiceInteractionManagerService mManagerService;
    private final Handler mHandler;
    private final HotwordDetector.Callback mCallback;
    private final int mDetectorType;
    private Consumer<AbstractHotwordDetector> mOnDestroyListener;
    private final AtomicBoolean mIsDetectorActive;
    /**
     * A token which is used by voice interaction system service to identify different detectors.
     */
    private final IBinder mToken = new Binder();

    AbstractHotwordDetector(
            IVoiceInteractionManagerService managerService,
            HotwordDetector.Callback callback,
            int detectorType) {
            HotwordDetector.Callback callback) {
        mManagerService = managerService;
        // TODO: this needs to be supplied from above
        mHandler = new Handler(Looper.getMainLooper());
        mCallback = callback;
        mDetectorType = detectorType;
        mIsDetectorActive = new AtomicBoolean(true);
    }

@@ -94,6 +97,7 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
                    audioStream,
                    audioFormat,
                    options,
                    mToken,
                    new BinderCallback(mHandler, mCallback));
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
@@ -111,7 +115,7 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
        }
        throwIfDetectorIsNoLongerActive();
        try {
            mManagerService.updateState(options, sharedMemory);
            mManagerService.updateState(options, sharedMemory, mToken);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -128,7 +132,7 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
        Identity identity = new Identity();
        identity.packageName = ActivityThread.currentOpPackageName();
        try {
            mManagerService.initAndVerifyDetector(identity, options, sharedMemory, callback,
            mManagerService.initAndVerifyDetector(identity, options, sharedMemory, mToken, callback,
                    detectorType);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -151,6 +155,11 @@ abstract class AbstractHotwordDetector implements HotwordDetector {
            return;
        }
        mIsDetectorActive.set(false);
        try {
            mManagerService.destroyDetector(mToken);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        synchronized (mLock) {
            mOnDestroyListener.accept(this);
        }
+1 −3
Original line number Diff line number Diff line
@@ -765,9 +765,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
            KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
            IVoiceInteractionManagerService modelManagementService, int targetSdkVersion,
            boolean supportHotwordDetectionService) {
        super(modelManagementService, callback,
                supportHotwordDetectionService ? DETECTOR_TYPE_TRUSTED_HOTWORD_DSP
                        : DETECTOR_TYPE_NORMAL);
        super(modelManagementService, callback);

        mHandler = new MyHandler();
        mText = text;
+1 −1
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
            IVoiceInteractionManagerService managerService,
            AudioFormat audioFormat,
            HotwordDetector.Callback callback) {
        super(managerService, callback, DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE);
        super(managerService, callback);

        mManagerService = managerService;
        mAudioFormat = audioFormat;
+13 −1
Original line number Diff line number Diff line
@@ -252,11 +252,13 @@ interface IVoiceInteractionManagerService {
     * @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 token Use this to identify which detector calls this method.
     */
    @EnforcePermission("MANAGE_HOTWORD_DETECTION")
    void updateState(
            in PersistableBundle options,
            in SharedMemory sharedMemory);
            in SharedMemory sharedMemory,
            in IBinder token);

    /**
     * Set configuration and pass read-only data to hotword detection service when creating
@@ -272,6 +274,7 @@ interface IVoiceInteractionManagerService {
     * @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 token Use this to identify which detector calls this method.
     * @param callback Use this to report {@link HotwordDetectionService} status.
     * @param detectorType Indicate which detector is used.
     */
@@ -280,9 +283,17 @@ interface IVoiceInteractionManagerService {
            in Identity originatorIdentity,
            in PersistableBundle options,
            in SharedMemory sharedMemory,
            in IBinder token,
            in IHotwordRecognitionStatusCallback callback,
            int detectorType);

    /**
     * Destroy the detector callback.
     *
     * @param token Indicate which callback will be destroyed.
     */
    void destroyDetector(in IBinder token);

    /**
     * Requests to shutdown hotword detection service.
     */
@@ -298,6 +309,7 @@ interface IVoiceInteractionManagerService {
        in ParcelFileDescriptor audioStream,
        in AudioFormat audioFormat,
        in PersistableBundle options,
        in IBinder token,
        in IMicrophoneHotwordDetectionVoiceInteractionCallback callback);

    /**
+5 −3
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.annotation.NonNull;
import android.content.Context;
import android.hardware.soundtrigger.SoundTrigger;
import android.media.permission.Identity;
import android.os.IBinder;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SharedMemory;
@@ -74,12 +75,13 @@ final class DspTrustedHotwordDetectorSession extends HotwordDetectorSession {

    DspTrustedHotwordDetectorSession(
            @NonNull HotwordDetectionConnection.ServiceConnection remoteHotwordDetectionService,
            @NonNull Object lock, @NonNull Context context,
            @NonNull Object lock, @NonNull Context context, @NonNull IBinder token,
            @NonNull IHotwordRecognitionStatusCallback callback, int voiceInteractionServiceUid,
            Identity voiceInteractorIdentity,
            @NonNull ScheduledExecutorService scheduledExecutorService, boolean logging) {
        super(remoteHotwordDetectionService, lock, context, callback, voiceInteractionServiceUid,
                voiceInteractorIdentity, scheduledExecutorService, logging);
        super(remoteHotwordDetectionService, lock, context, token, callback,
                voiceInteractionServiceUid, voiceInteractorIdentity, scheduledExecutorService,
                logging);
    }

    @SuppressWarnings("GuardedBy")
Loading