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

Commit fa4467c2 authored by William Leshner's avatar William Leshner Committed by Android (Google) Code Review
Browse files

Merge "Adopt IVisualQueryRecognitionStatusListener for visual query detection." into udc-qpr-dev

parents 7b1b0468 8bbce682
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -917,4 +917,7 @@
    "$packageName" part that will be replaced by the code with the package name of the target app.
    -->
    <string name="config_appStoreAppLinkTemplate" translatable="false"></string>

    <!-- Flag controlling whether visual query attention detection has been enabled. -->
    <bool name="config_enableVisualQueryAttentionDetection">false</bool>
</resources>
+76 −2
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import android.service.voice.VoiceInteractionSession;
import android.util.Log;

import com.android.internal.app.AssistUtils;
import com.android.internal.app.IVisualQueryDetectionAttentionListener;
import com.android.internal.app.IVisualQueryRecognitionStatusListener;
import com.android.internal.app.IVoiceInteractionSessionListener;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -39,10 +41,13 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.util.settings.SecureSettings;

import javax.inject.Inject;

import dagger.Lazy;

import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

/**
 * Class to manage everything related to assist in SystemUI.
 */
@@ -78,6 +83,18 @@ public class AssistManager {
        void hide();
    }

    /**
     * An interface for a listener that receives notification that visual query attention has
     * either been gained or lost.
     */
    public interface VisualQueryAttentionListener {
        /** Called when visual query attention has been gained. */
        void onAttentionGained();

        /** Called when visual query attention has been lost. */
        void onAttentionLost();
    }

    private static final String TAG = "AssistManager";

    // Note that VERBOSE logging may leak PII (e.g. transcription contents).
@@ -127,6 +144,23 @@ public class AssistManager {
    private final SecureSettings mSecureSettings;

    private final DeviceProvisionedController mDeviceProvisionedController;

    private final List<VisualQueryAttentionListener> mVisualQueryAttentionListeners =
            new ArrayList<>();

    private final IVisualQueryDetectionAttentionListener mVisualQueryDetectionAttentionListener =
            new IVisualQueryDetectionAttentionListener.Stub() {
        @Override
        public void onAttentionGained() {
            mVisualQueryAttentionListeners.forEach(VisualQueryAttentionListener::onAttentionGained);
        }

        @Override
        public void onAttentionLost() {
            mVisualQueryAttentionListeners.forEach(VisualQueryAttentionListener::onAttentionLost);
        }
    };

    private final CommandQueue mCommandQueue;
    protected final AssistUtils mAssistUtils;

@@ -157,6 +191,7 @@ public class AssistManager {
        mSecureSettings = secureSettings;

        registerVoiceInteractionSessionListener();
        registerVisualQueryRecognitionStatusListener();

        mUiController = defaultUiController;

@@ -266,6 +301,24 @@ public class AssistManager {
        mAssistUtils.hideCurrentSession();
    }

    /**
     * Add the given {@link VisualQueryAttentionListener} to the list of listeners awaiting
     * notification of gaining/losing visual query attention.
     */
    public void addVisualQueryAttentionListener(VisualQueryAttentionListener listener) {
        if (!mVisualQueryAttentionListeners.contains(listener)) {
            mVisualQueryAttentionListeners.add(listener);
        }
    }

    /**
     * Remove the given {@link VisualQueryAttentionListener} from the list of listeners awaiting
     * notification of gaining/losing visual query attention.
     */
    public void removeVisualQueryAttentionListener(VisualQueryAttentionListener listener) {
        mVisualQueryAttentionListeners.remove(listener);
    }

    private void startAssistInternal(Bundle args, @NonNull ComponentName assistComponent,
            boolean isService) {
        if (isService) {
@@ -326,6 +379,27 @@ public class AssistManager {
                null, null);
    }

    private void registerVisualQueryRecognitionStatusListener() {
        if (!mContext.getResources()
                .getBoolean(R.bool.config_enableVisualQueryAttentionDetection)) {
            return;
        }

        mAssistUtils.subscribeVisualQueryRecognitionStatus(
                new IVisualQueryRecognitionStatusListener.Stub() {
                    @Override
                    public void onStartPerceiving() {
                        mAssistUtils.enableVisualQueryDetection(
                                mVisualQueryDetectionAttentionListener);
                    }

                    @Override
                    public void onStopPerceiving() {
                        mAssistUtils.disableVisualQueryDetection();
                    }
                });
    }

    public void launchVoiceAssistFromKeyguard() {
        mAssistUtils.launchVoiceAssistFromKeyguard();
    }
+9 −45
Original line number Diff line number Diff line
@@ -16,10 +16,9 @@

package com.android.systemui.dreams.conditions;

import com.android.internal.app.AssistUtils;
import com.android.internal.app.IVisualQueryDetectionAttentionListener;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.assist.AssistManager.VisualQueryAttentionListener;
import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.shared.condition.Condition;

import javax.inject.Inject;
@@ -30,12 +29,10 @@ import kotlinx.coroutines.CoroutineScope;
 * {@link AssistantAttentionCondition} provides a signal when assistant has the user's attention.
 */
public class AssistantAttentionCondition extends Condition {
    private final DreamOverlayStateController mDreamOverlayStateController;
    private final AssistUtils mAssistUtils;
    private boolean mEnabled;
    private final AssistManager mAssistManager;

    private final IVisualQueryDetectionAttentionListener mVisualQueryDetectionAttentionListener =
            new IVisualQueryDetectionAttentionListener.Stub() {
    private final VisualQueryAttentionListener mVisualQueryAttentionListener =
            new VisualQueryAttentionListener() {
        @Override
        public void onAttentionGained() {
            updateCondition(true);
@@ -47,59 +44,26 @@ public class AssistantAttentionCondition extends Condition {
        }
    };

    private final DreamOverlayStateController.Callback mCallback =
            new DreamOverlayStateController.Callback() {
        @Override
        public void onStateChanged() {
            if (mDreamOverlayStateController.isDreamOverlayStatusBarVisible()) {
                enableVisualQueryDetection();
            } else {
                disableVisualQueryDetection();
            }
        }
    };

    @Inject
    public AssistantAttentionCondition(
            @Application CoroutineScope scope,
            DreamOverlayStateController dreamOverlayStateController,
            AssistUtils assistUtils) {
            AssistManager assistManager) {
        super(scope);
        mDreamOverlayStateController = dreamOverlayStateController;
        mAssistUtils = assistUtils;
        mAssistManager = assistManager;
    }

    @Override
    protected void start() {
        mDreamOverlayStateController.addCallback(mCallback);
        mAssistManager.addVisualQueryAttentionListener(mVisualQueryAttentionListener);
    }

    @Override
    protected void stop() {
        disableVisualQueryDetection();
        mDreamOverlayStateController.removeCallback(mCallback);
        mAssistManager.removeVisualQueryAttentionListener(mVisualQueryAttentionListener);
    }

    @Override
    protected int getStartStrategy() {
        return START_EAGERLY;
    }

    private void enableVisualQueryDetection() {
        if (mEnabled) {
            return;
        }
        mEnabled = true;
        mAssistUtils.enableVisualQueryDetection(mVisualQueryDetectionAttentionListener);
    }

    private void disableVisualQueryDetection() {
        if (!mEnabled) {
            return;
        }
        mEnabled = false;
        mAssistUtils.disableVisualQueryDetection();
        // Make sure the condition is set to false as well.
        updateCondition(false);
    }
}
+15 −41
Original line number Diff line number Diff line
@@ -22,17 +22,14 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.os.RemoteException;
import android.testing.AndroidTestingRunner;

import androidx.test.filters.SmallTest;

import com.android.internal.app.AssistUtils;
import com.android.internal.app.IVisualQueryDetectionAttentionListener;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.assist.AssistManager.VisualQueryAttentionListener;
import com.android.systemui.shared.condition.Condition;

import org.junit.Before;
@@ -50,9 +47,7 @@ public class AssistantAttentionConditionTest extends SysuiTestCase {
    @Mock
    Condition.Callback mCallback;
    @Mock
    AssistUtils mAssistUtils;
    @Mock
    DreamOverlayStateController mDreamOverlayStateController;
    AssistManager mAssistManager;
    @Mock
    CoroutineScope mScope;

@@ -62,55 +57,34 @@ public class AssistantAttentionConditionTest extends SysuiTestCase {
    public void setup() {
        MockitoAnnotations.initMocks(this);

        mAssistantAttentionCondition =
                new AssistantAttentionCondition(mScope, mDreamOverlayStateController, mAssistUtils);
        mAssistantAttentionCondition = new AssistantAttentionCondition(mScope, mAssistManager);
        // Adding a callback also starts the condition.
        mAssistantAttentionCondition.addCallback(mCallback);
    }

    @Test
    public void testEnableVisualQueryDetection() {
        final ArgumentCaptor<DreamOverlayStateController.Callback> argumentCaptor =
                ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
        verify(mDreamOverlayStateController).addCallback(argumentCaptor.capture());

        when(mDreamOverlayStateController.isDreamOverlayStatusBarVisible()).thenReturn(true);
        argumentCaptor.getValue().onStateChanged();

        verify(mAssistUtils).enableVisualQueryDetection(any());
        verify(mAssistManager).addVisualQueryAttentionListener(
                any(VisualQueryAttentionListener.class));
    }

    @Test
    public void testDisableVisualQueryDetection() {
        final ArgumentCaptor<DreamOverlayStateController.Callback> argumentCaptor =
                ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
        verify(mDreamOverlayStateController).addCallback(argumentCaptor.capture());

        when(mDreamOverlayStateController.isDreamOverlayStatusBarVisible()).thenReturn(true);
        argumentCaptor.getValue().onStateChanged();
        when(mDreamOverlayStateController.isDreamOverlayStatusBarVisible()).thenReturn(false);
        argumentCaptor.getValue().onStateChanged();

        verify(mAssistUtils).disableVisualQueryDetection();
        mAssistantAttentionCondition.stop();
        verify(mAssistManager).removeVisualQueryAttentionListener(
                any(VisualQueryAttentionListener.class));
    }

    @Test
    public void testAttentionChangedTriggersCondition() throws RemoteException {
        final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCaptor =
                ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
        verify(mDreamOverlayStateController).addCallback(callbackCaptor.capture());

        when(mDreamOverlayStateController.isDreamOverlayStatusBarVisible()).thenReturn(true);
        callbackCaptor.getValue().onStateChanged();

        final ArgumentCaptor<IVisualQueryDetectionAttentionListener> listenerCaptor =
                ArgumentCaptor.forClass(IVisualQueryDetectionAttentionListener.class);
        verify(mAssistUtils).enableVisualQueryDetection(listenerCaptor.capture());
    public void testAttentionChangedTriggersCondition() {
        final ArgumentCaptor<VisualQueryAttentionListener> argumentCaptor =
                ArgumentCaptor.forClass(VisualQueryAttentionListener.class);
        verify(mAssistManager).addVisualQueryAttentionListener(argumentCaptor.capture());

        listenerCaptor.getValue().onAttentionGained();
        argumentCaptor.getValue().onAttentionGained();
        assertThat(mAssistantAttentionCondition.isConditionMet()).isTrue();

        listenerCaptor.getValue().onAttentionLost();
        argumentCaptor.getValue().onAttentionLost();
        assertThat(mAssistantAttentionCondition.isConditionMet()).isFalse();

        verify(mCallback, times(2)).onConditionChanged(eq(mAssistantAttentionCondition));