Implement assistant attention icon in dream overlay status bar.
Bug: 265235507 Test: atest AssistantAttentionConditionTest Test: atest DreamOverlayStateControllerTest Test: atest DreamOverlayStatusBarViewControllerTest Change-Id: Ic184d89a5ca684539ffed7b0dc8582322dc51d2f
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<!--
|
||||
~ Copyright (C) 2023 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="56dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="56"
|
||||
android:viewportHeight="24">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M12 0H44C50.6274 0 56 5.37258 56 12C56 18.6274 50.6274 24 44 24H12C5.37258 24 0 18.6274 0 12C0 5.37258 5.37258 0 12 0Z"
|
||||
/>
|
||||
<path
|
||||
android:pathData="M0 0V24H56V0"
|
||||
android:fillColor="#FFFFFF"
|
||||
/>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -111,5 +111,15 @@
|
||||
android:visibility="gone"
|
||||
android:contentDescription="@string/dream_overlay_status_bar_camera_mic_off" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dream_overlay_assistant_attention_indicator"
|
||||
android:layout_width="@dimen/dream_overlay_grey_chip_width"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
|
||||
android:src="@drawable/dream_overlay_assistant_attention_indicator"
|
||||
android:visibility="gone"
|
||||
android:contentDescription=
|
||||
"@string/dream_overlay_status_bar_assistant_attention_indicator" />
|
||||
|
||||
</LinearLayout>
|
||||
</com.android.systemui.dreams.DreamOverlayStatusBarView>
|
||||
|
||||
@@ -2798,6 +2798,8 @@
|
||||
<string name="dream_overlay_status_bar_mic_off">Mic is off</string>
|
||||
<!-- Content description for the camera and mic off icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
|
||||
<string name="dream_overlay_status_bar_camera_mic_off">Camera and mic are off</string>
|
||||
<!-- Content description for the assistant attention indicator [CHAR LIMIT=NONE] -->
|
||||
<string name="dream_overlay_status_bar_assistant_attention_indicator">Assistant is listening</string>
|
||||
<!-- Content description for the notifications indicator icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
|
||||
<string name="dream_overlay_status_bar_notification_indicator">{count, plural,
|
||||
=1 {# notification}
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.android.systemui.biometrics.AuthController
|
||||
import com.android.systemui.biometrics.UdfpsOverlay
|
||||
import com.android.systemui.clipboardoverlay.ClipboardListener
|
||||
import com.android.systemui.dagger.qualifiers.PerUser
|
||||
import com.android.systemui.dreams.AssistantAttentionMonitor
|
||||
import com.android.systemui.dreams.DreamMonitor
|
||||
import com.android.systemui.globalactions.GlobalActionsComponent
|
||||
import com.android.systemui.keyboard.KeyboardUI
|
||||
@@ -309,4 +310,10 @@ abstract class SystemUICoreStartableModule {
|
||||
@IntoMap
|
||||
@ClassKey(DreamMonitor::class)
|
||||
abstract fun bindDreamMonitor(sysui: DreamMonitor): CoreStartable
|
||||
|
||||
/**Inject into AssistantAttentionMonitor */
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(AssistantAttentionMonitor::class)
|
||||
abstract fun bindAssistantAttentionMonitor(sysui: AssistantAttentionMonitor): CoreStartable
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.dreams;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.CoreStartable;
|
||||
import com.android.systemui.dreams.callbacks.AssistantAttentionCallback;
|
||||
import com.android.systemui.dreams.conditions.AssistantAttentionCondition;
|
||||
import com.android.systemui.shared.condition.Monitor;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* A {@link CoreStartable} to retain a monitor for tracking assistant attention.
|
||||
*/
|
||||
public class AssistantAttentionMonitor implements CoreStartable {
|
||||
private static final String TAG = "AssistAttentionMonitor";
|
||||
|
||||
// We retain a reference to the monitor so it is not garbage-collected.
|
||||
private final Monitor mConditionMonitor;
|
||||
private final AssistantAttentionCondition mAssistantAttentionCondition;
|
||||
private final AssistantAttentionCallback mCallback;
|
||||
|
||||
@Inject
|
||||
public AssistantAttentionMonitor(
|
||||
Monitor monitor,
|
||||
AssistantAttentionCondition assistantAttentionCondition,
|
||||
AssistantAttentionCallback callback) {
|
||||
mConditionMonitor = monitor;
|
||||
mAssistantAttentionCondition = assistantAttentionCondition;
|
||||
mCallback = callback;
|
||||
|
||||
}
|
||||
@Override
|
||||
public void start() {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "started");
|
||||
}
|
||||
|
||||
mConditionMonitor.addSubscription(new Monitor.Subscription.Builder(mCallback)
|
||||
.addCondition(mAssistantAttentionCondition)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,8 @@ public class DreamOverlayStateController implements
|
||||
public static final int STATE_LOW_LIGHT_ACTIVE = 1 << 1;
|
||||
public static final int STATE_DREAM_ENTRY_ANIMATIONS_FINISHED = 1 << 2;
|
||||
public static final int STATE_DREAM_EXIT_ANIMATIONS_RUNNING = 1 << 3;
|
||||
public static final int STATE_HAS_ASSISTANT_ATTENTION = 1 << 4;
|
||||
public static final int STATE_DREAM_OVERLAY_STATUS_BAR_VISIBLE = 1 << 5;
|
||||
|
||||
private static final int OP_CLEAR_STATE = 1;
|
||||
private static final int OP_SET_STATE = 2;
|
||||
@@ -251,6 +253,22 @@ public class DreamOverlayStateController implements
|
||||
return containsState(STATE_DREAM_EXIT_ANIMATIONS_RUNNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether assistant currently has the user's attention.
|
||||
* @return {@code true} if assistant has the user's attention, {@code false} otherwise.
|
||||
*/
|
||||
public boolean hasAssistantAttention() {
|
||||
return containsState(STATE_HAS_ASSISTANT_ATTENTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the dream overlay status bar is currently visible.
|
||||
* @return {@code true} if the status bar is visible, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isDreamOverlayStatusBarVisible() {
|
||||
return containsState(STATE_DREAM_OVERLAY_STATUS_BAR_VISIBLE);
|
||||
}
|
||||
|
||||
private boolean containsState(int state) {
|
||||
return (mState & state) != 0;
|
||||
}
|
||||
@@ -309,6 +327,23 @@ public class DreamOverlayStateController implements
|
||||
STATE_DREAM_EXIT_ANIMATIONS_RUNNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether assistant currently has the user's attention.
|
||||
* @param hasAttention {@code true} if has the user's attention, {@code false} otherwise.
|
||||
*/
|
||||
public void setHasAssistantAttention(boolean hasAttention) {
|
||||
modifyState(hasAttention ? OP_SET_STATE : OP_CLEAR_STATE, STATE_HAS_ASSISTANT_ATTENTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the dream overlay status bar is visible.
|
||||
* @param visible {@code true} if the status bar is visible, {@code false} otherwise.
|
||||
*/
|
||||
public void setDreamOverlayStatusBarVisible(boolean visible) {
|
||||
modifyState(
|
||||
visible ? OP_SET_STATE : OP_CLEAR_STATE, STATE_DREAM_OVERLAY_STATUS_BAR_VISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the available complication types.
|
||||
*/
|
||||
|
||||
@@ -52,7 +52,8 @@ public class DreamOverlayStatusBarView extends ConstraintLayout {
|
||||
STATUS_ICON_CAMERA_DISABLED,
|
||||
STATUS_ICON_MIC_DISABLED,
|
||||
STATUS_ICON_MIC_CAMERA_DISABLED,
|
||||
STATUS_ICON_PRIORITY_MODE_ON
|
||||
STATUS_ICON_PRIORITY_MODE_ON,
|
||||
STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
|
||||
})
|
||||
public @interface StatusIconType {}
|
||||
public static final int STATUS_ICON_NOTIFICATIONS = 0;
|
||||
@@ -62,6 +63,7 @@ public class DreamOverlayStatusBarView extends ConstraintLayout {
|
||||
public static final int STATUS_ICON_MIC_DISABLED = 4;
|
||||
public static final int STATUS_ICON_MIC_CAMERA_DISABLED = 5;
|
||||
public static final int STATUS_ICON_PRIORITY_MODE_ON = 6;
|
||||
public static final int STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE = 7;
|
||||
|
||||
private final Map<Integer, View> mStatusIcons = new HashMap<>();
|
||||
private Context mContext;
|
||||
@@ -132,6 +134,8 @@ public class DreamOverlayStatusBarView extends ConstraintLayout {
|
||||
fetchStatusIconForResId(R.id.dream_overlay_notification_indicator));
|
||||
mStatusIcons.put(STATUS_ICON_PRIORITY_MODE_ON,
|
||||
addDoubleShadow(fetchStatusIconForResId(R.id.dream_overlay_priority_mode)));
|
||||
mStatusIcons.put(STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
|
||||
fetchStatusIconForResId(R.id.dream_overlay_assistant_attention_indicator));
|
||||
|
||||
mSystemStatusViewGroup = findViewById(R.id.dream_overlay_system_status);
|
||||
mExtraSystemStatusViewGroup = findViewById(R.id.dream_overlay_extra_items);
|
||||
|
||||
@@ -113,6 +113,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
||||
mEntryAnimationsFinished =
|
||||
mDreamOverlayStateController.areEntryAnimationsFinished();
|
||||
updateVisibility();
|
||||
updateAssistantAttentionIcon();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -214,6 +215,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
||||
provider -> provider.removeCallback(mNotificationCountCallback));
|
||||
mStatusBarItemsProvider.removeCallback(mStatusBarItemsProviderCallback);
|
||||
mView.removeAllExtraStatusBarItemViews();
|
||||
mDreamOverlayStateController.setDreamOverlayStatusBarVisible(false);
|
||||
mDreamOverlayStateController.removeCallback(mDreamOverlayStateCallback);
|
||||
mTouchInsetSession.clear();
|
||||
|
||||
@@ -270,12 +272,20 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
||||
hasAlarm ? buildAlarmContentDescription(alarm) : null);
|
||||
}
|
||||
|
||||
private void updateAssistantAttentionIcon() {
|
||||
showIcon(DreamOverlayStatusBarView.STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
|
||||
mDreamOverlayStateController.hasAssistantAttention());
|
||||
}
|
||||
|
||||
private void updateVisibility() {
|
||||
if (shouldShowStatusBar()) {
|
||||
mView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mView.setVisibility(View.INVISIBLE);
|
||||
final int currentVisibility = mView.getVisibility();
|
||||
final int newVisibility = shouldShowStatusBar() ? View.VISIBLE : View.INVISIBLE;
|
||||
if (currentVisibility == newVisibility) {
|
||||
return;
|
||||
}
|
||||
|
||||
mView.setVisibility(newVisibility);
|
||||
mDreamOverlayStateController.setDreamOverlayStatusBarVisible(newVisibility == View.VISIBLE);
|
||||
}
|
||||
|
||||
private String buildAlarmContentDescription(AlarmManager.AlarmClockInfo alarm) {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.dreams.callbacks;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.dreams.DreamOverlayStateController;
|
||||
import com.android.systemui.shared.condition.Monitor;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* A callback that informs {@link DreamOverlayStateController} when assistant has the user's
|
||||
* attention.
|
||||
*/
|
||||
public class AssistantAttentionCallback implements Monitor.Callback {
|
||||
private static final String TAG = "AssistAttentionCallback";
|
||||
|
||||
private final DreamOverlayStateController mStateController;
|
||||
|
||||
@Inject
|
||||
public AssistantAttentionCallback(DreamOverlayStateController stateController) {
|
||||
mStateController = stateController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConditionsChanged(boolean allConditionsMet) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "onConditionChanged:" + allConditionsMet);
|
||||
}
|
||||
|
||||
mStateController.setHasAssistantAttention(allConditionsMet);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.dreams.conditions;
|
||||
|
||||
import com.android.internal.app.AssistUtils;
|
||||
import com.android.internal.app.IVisualQueryDetectionAttentionListener;
|
||||
import com.android.systemui.dreams.DreamOverlayStateController;
|
||||
import com.android.systemui.shared.condition.Condition;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* {@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 IVisualQueryDetectionAttentionListener mVisualQueryDetectionAttentionListener =
|
||||
new IVisualQueryDetectionAttentionListener.Stub() {
|
||||
@Override
|
||||
public void onAttentionGained() {
|
||||
updateCondition(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttentionLost() {
|
||||
updateCondition(false);
|
||||
}
|
||||
};
|
||||
|
||||
private final DreamOverlayStateController.Callback mCallback =
|
||||
new DreamOverlayStateController.Callback() {
|
||||
@Override
|
||||
public void onStateChanged() {
|
||||
if (mDreamOverlayStateController.isDreamOverlayStatusBarVisible()) {
|
||||
enableVisualQueryDetection();
|
||||
} else {
|
||||
disableVisualQueryDetection();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Inject
|
||||
public AssistantAttentionCondition(
|
||||
DreamOverlayStateController dreamOverlayStateController,
|
||||
AssistUtils assistUtils) {
|
||||
mDreamOverlayStateController = dreamOverlayStateController;
|
||||
mAssistUtils = assistUtils;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void start() {
|
||||
mDreamOverlayStateController.addCallback(mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stop() {
|
||||
disableVisualQueryDetection();
|
||||
mDreamOverlayStateController.removeCallback(mCallback);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -289,4 +289,36 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
|
||||
verify(mCallback, times(1)).onStateChanged();
|
||||
assertThat(stateController.areEntryAnimationsFinished()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifyDreamOverlayStatusBarVisibleChanged() {
|
||||
final DreamOverlayStateController stateController =
|
||||
new DreamOverlayStateController(mExecutor, true);
|
||||
|
||||
stateController.addCallback(mCallback);
|
||||
mExecutor.runAllReady();
|
||||
assertThat(stateController.isDreamOverlayStatusBarVisible()).isFalse();
|
||||
|
||||
stateController.setDreamOverlayStatusBarVisible(true);
|
||||
mExecutor.runAllReady();
|
||||
|
||||
verify(mCallback, times(1)).onStateChanged();
|
||||
assertThat(stateController.isDreamOverlayStatusBarVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifyHasAssistantAttentionChanged() {
|
||||
final DreamOverlayStateController stateController =
|
||||
new DreamOverlayStateController(mExecutor, true);
|
||||
|
||||
stateController.addCallback(mCallback);
|
||||
mExecutor.runAllReady();
|
||||
assertThat(stateController.hasAssistantAttention()).isFalse();
|
||||
|
||||
stateController.setHasAssistantAttention(true);
|
||||
mExecutor.runAllReady();
|
||||
|
||||
verify(mCallback, times(1)).onStateChanged();
|
||||
assertThat(stateController.hasAssistantAttention()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,6 +467,21 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
||||
DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssistantAttentionIconShownWhenAttentionGained() {
|
||||
mController.onViewAttached();
|
||||
|
||||
when(mDreamOverlayStateController.hasAssistantAttention()).thenReturn(true);
|
||||
|
||||
final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture =
|
||||
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
|
||||
verify(mDreamOverlayStateController).addCallback(callbackCapture.capture());
|
||||
callbackCapture.getValue().onStateChanged();
|
||||
|
||||
verify(mView).showIcon(
|
||||
DreamOverlayStatusBarView.STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE, true, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatusBarHiddenWhenSystemStatusBarShown() {
|
||||
mController.onViewAttached();
|
||||
@@ -572,6 +587,13 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
||||
assertThat(mView.getVisibility()).isEqualTo(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDreamOverlayStatusBarVisibleSetToFalseOnDetach() {
|
||||
mController.onViewAttached();
|
||||
mController.onViewDetached();
|
||||
verify(mDreamOverlayStateController).setDreamOverlayStatusBarVisible(false);
|
||||
}
|
||||
|
||||
private StatusBarWindowStateListener updateStatusBarWindowState(boolean show) {
|
||||
when(mStatusBarWindowStateController.windowIsShowing()).thenReturn(show);
|
||||
final ArgumentCaptor<StatusBarWindowStateListener>
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.dreams.conditions;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
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.shared.condition.Condition;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class AssistantAttentionConditionTest extends SysuiTestCase {
|
||||
@Mock
|
||||
Condition.Callback mCallback;
|
||||
@Mock
|
||||
AssistUtils mAssistUtils;
|
||||
@Mock
|
||||
DreamOverlayStateController mDreamOverlayStateController;
|
||||
|
||||
private AssistantAttentionCondition mAssistantAttentionCondition;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mAssistantAttentionCondition =
|
||||
new AssistantAttentionCondition(mDreamOverlayStateController, mAssistUtils);
|
||||
// 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());
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
@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());
|
||||
|
||||
listenerCaptor.getValue().onAttentionGained();
|
||||
assertThat(mAssistantAttentionCondition.isConditionMet()).isTrue();
|
||||
|
||||
listenerCaptor.getValue().onAttentionLost();
|
||||
assertThat(mAssistantAttentionCondition.isConditionMet()).isFalse();
|
||||
|
||||
verify(mCallback, times(2)).onConditionChanged(eq(mAssistantAttentionCondition));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user