Adopt IVisualQueryRecognitionStatusListener for visual query detection.

This fixed an issue with reconnecting to visual query detection service.

Bug: 294609153
Test: atest AssistantAttentionConditionTest
Test: atest DreamOverlayStateControllerTest
Test: atest DreamOverlayStatusBarViewControllerTest
Change-Id: I4ccb9343709f589ff27777edfbe6c92b41c3f123
This commit is contained in:
Will Leshner
2023-08-09 15:23:52 -07:00
parent a13e078b93
commit 8bbce6820a
4 changed files with 103 additions and 88 deletions

View File

@@ -914,4 +914,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>

View File

@@ -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();
}

View File

@@ -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);
}
}

View File

@@ -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());
public void testAttentionChangedTriggersCondition() {
final ArgumentCaptor<VisualQueryAttentionListener> argumentCaptor =
ArgumentCaptor.forClass(VisualQueryAttentionListener.class);
verify(mAssistManager).addVisualQueryAttentionListener(argumentCaptor.capture());
when(mDreamOverlayStateController.isDreamOverlayStatusBarVisible()).thenReturn(true);
callbackCaptor.getValue().onStateChanged();
final ArgumentCaptor<IVisualQueryDetectionAttentionListener> listenerCaptor =
ArgumentCaptor.forClass(IVisualQueryDetectionAttentionListener.class);
verify(mAssistUtils).enableVisualQueryDetection(listenerCaptor.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));