Adds an Assistant handle controller to the AssistManager
This will control when the Assistant handles show or hide.
Change mode using the following command:
$ adb shell am broadcast \
-a "com.google.systemui.SET_ASSIST_HANDLE_BEHAVIOR" \
--es behavior "${BEHAVIOR}"
BEHAVIOR can be one of: OFF, LIKE_HOME, or REMINDER_EXP
Change the minimum time between handle appearance in REMINDER_EXP using
the following command:
$ adb shell setprop ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS \
${DESIRED_MILLISECONDS}
Change the duration the handles appear in REMINDER_EXP using the
following command:
$ adb shell setprop ASSIST_HANDLES_SHOW_AND_GO_DURATION_MS \
${DESIRED_MILLISECONDS}
BUG:132983599
BUG:131115187
Test: atest AssistHandleBehaviorControllerTest
Test: Tested locally.
Change-Id: I44bb59367159226b67a2aeb49aae2a5b34584d70
This commit is contained in:
@@ -156,6 +156,11 @@ public class ScreenDecorations extends SystemUI implements Tunable {
|
||||
* @param visible whether the handles should be shown
|
||||
*/
|
||||
public void setAssistHintVisible(boolean visible) {
|
||||
if (!mHandler.getLooper().isCurrentThread()) {
|
||||
mHandler.post(() -> setAssistHintVisible(visible));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAssistHintVisible != visible) {
|
||||
mAssistHintVisible = visible;
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.assist;
|
||||
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
|
||||
|
||||
public enum AssistHandleBehavior {
|
||||
|
||||
TEST(new AssistHandleOffBehavior()),
|
||||
OFF(new AssistHandleOffBehavior()),
|
||||
LIKE_HOME(new AssistHandleLikeHomeBehavior()),
|
||||
REMINDER_EXP(new AssistHandleReminderExpBehavior());
|
||||
|
||||
private BehaviorController mController;
|
||||
|
||||
AssistHandleBehavior(BehaviorController controller) {
|
||||
mController = controller;
|
||||
}
|
||||
|
||||
BehaviorController getController() {
|
||||
return mController;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setTestController(BehaviorController controller) {
|
||||
if (this.equals(TEST)) {
|
||||
mController = controller;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.assist;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.ScreenDecorations;
|
||||
import com.android.systemui.SysUiServiceProvider;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
import com.android.systemui.statusbar.phone.NavigationModeController;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A class for managing Assistant handle logic.
|
||||
*
|
||||
* Controls when visual handles for Assistant gesture affordance should be shown or hidden using an
|
||||
* {@link AssistHandleBehavior}.
|
||||
*/
|
||||
public final class AssistHandleBehaviorController implements AssistHandleCallbacks {
|
||||
|
||||
private static final String TAG = "AssistHandleBehavior";
|
||||
private static final boolean IS_DEBUG_DEVICE =
|
||||
Build.TYPE.toLowerCase(Locale.ROOT).contains("debug")
|
||||
|| Build.TYPE.toLowerCase(Locale.ROOT).equals("eng");
|
||||
|
||||
private static final String SHOWN_FREQUENCY_THRESHOLD_KEY =
|
||||
"ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS";
|
||||
private static final long DEFAULT_SHOWN_FREQUENCY_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(10);
|
||||
private static final String SHOW_AND_GO_DURATION_KEY = "ASSIST_HANDLES_SHOW_AND_GO_DURATION_MS";
|
||||
private static final long DEFAULT_SHOW_AND_GO_DURATION_MS = TimeUnit.SECONDS.toMillis(3);
|
||||
private static final String BEHAVIOR_KEY = "behavior";
|
||||
private static final String SET_BEHAVIOR_ACTION =
|
||||
"com.android.systemui.SET_ASSIST_HANDLE_BEHAVIOR";
|
||||
|
||||
private final Context mContext;
|
||||
private final Handler mHandler;
|
||||
private final Runnable mHideHandles = this::hideHandles;
|
||||
private final Supplier<ScreenDecorations> mScreenDecorationsSupplier;
|
||||
|
||||
private boolean mHandlesShowing = false;
|
||||
private long mHandlesLastHiddenAt;
|
||||
private AssistHandleBehavior mCurrentBehavior = AssistHandleBehavior.OFF;
|
||||
private boolean mInGesturalMode;
|
||||
|
||||
AssistHandleBehaviorController(Context context, Handler handler) {
|
||||
this(context, handler, () ->
|
||||
SysUiServiceProvider.getComponent(context, ScreenDecorations.class));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
AssistHandleBehaviorController(
|
||||
Context context,
|
||||
Handler handler,
|
||||
Supplier<ScreenDecorations> screenDecorationsSupplier) {
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
mScreenDecorationsSupplier = screenDecorationsSupplier;
|
||||
|
||||
mInGesturalMode = QuickStepContract.isGesturalMode(
|
||||
Dependency.get(NavigationModeController.class)
|
||||
.addListener(this::handleNavigationModeChange));
|
||||
|
||||
if (IS_DEBUG_DEVICE) {
|
||||
context.registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String behaviorString = intent.getExtras().getString(BEHAVIOR_KEY);
|
||||
try {
|
||||
setBehavior(AssistHandleBehavior.valueOf(behaviorString));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(TAG, "Invalid behavior identifier: " + behaviorString);
|
||||
}
|
||||
}
|
||||
}, new IntentFilter(SET_BEHAVIOR_ACTION));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
mHandler.removeCallbacks(mHideHandles);
|
||||
mHandler.post(mHideHandles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showAndGo() {
|
||||
mHandler.removeCallbacks(mHideHandles);
|
||||
mHandler.post(() -> {
|
||||
maybeShowHandles(/* ignoreThreshold = */ false);
|
||||
mHandler.postDelayed(mHideHandles, getShowAndGoDuration());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showAndStay() {
|
||||
mHandler.removeCallbacks(mHideHandles);
|
||||
mHandler.post(() -> maybeShowHandles(/* ignoreThreshold = */ true));
|
||||
}
|
||||
|
||||
void setBehavior(AssistHandleBehavior behavior) {
|
||||
if (mCurrentBehavior == behavior) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mInGesturalMode) {
|
||||
mCurrentBehavior.getController().onModeDeactivated();
|
||||
behavior.getController().onModeActivated(mContext, this);
|
||||
}
|
||||
|
||||
mCurrentBehavior = behavior;
|
||||
}
|
||||
|
||||
private static long getShownFrequencyThreshold() {
|
||||
return SystemProperties.getLong(
|
||||
SHOWN_FREQUENCY_THRESHOLD_KEY, DEFAULT_SHOWN_FREQUENCY_THRESHOLD_MS);
|
||||
}
|
||||
|
||||
private static long getShowAndGoDuration() {
|
||||
return SystemProperties.getLong(SHOW_AND_GO_DURATION_KEY, DEFAULT_SHOW_AND_GO_DURATION_MS);
|
||||
}
|
||||
|
||||
private void maybeShowHandles(boolean ignoreThreshold) {
|
||||
if (mHandlesShowing) {
|
||||
return;
|
||||
}
|
||||
|
||||
long timeSinceHidden = SystemClock.elapsedRealtime() - mHandlesLastHiddenAt;
|
||||
if (ignoreThreshold || timeSinceHidden > getShownFrequencyThreshold()) {
|
||||
mHandlesShowing = true;
|
||||
ScreenDecorations screenDecorations = mScreenDecorationsSupplier.get();
|
||||
if (screenDecorations == null) {
|
||||
Log.w(TAG, "Couldn't show handles, ScreenDecorations unavailable");
|
||||
} else {
|
||||
screenDecorations.setAssistHintVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void hideHandles() {
|
||||
if (!mHandlesShowing) {
|
||||
return;
|
||||
}
|
||||
|
||||
mHandlesShowing = false;
|
||||
mHandlesLastHiddenAt = SystemClock.elapsedRealtime();
|
||||
ScreenDecorations screenDecorations = mScreenDecorationsSupplier.get();
|
||||
if (screenDecorations == null) {
|
||||
Log.w(TAG, "Couldn't hide handles, ScreenDecorations unavailable");
|
||||
} else {
|
||||
screenDecorations.setAssistHintVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNavigationModeChange(int navigationMode) {
|
||||
boolean inGesturalMode = QuickStepContract.isGesturalMode(navigationMode);
|
||||
if (mInGesturalMode == inGesturalMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInGesturalMode = inGesturalMode;
|
||||
if (mInGesturalMode) {
|
||||
mCurrentBehavior.getController().onModeActivated(mContext, this);
|
||||
} else {
|
||||
mCurrentBehavior.getController().onModeDeactivated();
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setInGesturalModeForTest(boolean inGesturalMode) {
|
||||
mInGesturalMode = inGesturalMode;
|
||||
}
|
||||
|
||||
interface BehaviorController {
|
||||
void onModeActivated(Context context, AssistHandleCallbacks callbacks);
|
||||
void onModeDeactivated();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.assist;
|
||||
|
||||
/** Callback for controlling Assistant handle behavior. */
|
||||
public interface AssistHandleCallbacks {
|
||||
|
||||
/** Hide the Assistant handles. */
|
||||
void hide();
|
||||
|
||||
/**
|
||||
* Show the Assistant handles for the configured duration and then hide them.
|
||||
*
|
||||
* Won't show if the handles have been shown within the configured timeout.
|
||||
*/
|
||||
void showAndGo();
|
||||
|
||||
/** Show the Assistant handles. */
|
||||
void showAndStay();
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.assist;
|
||||
|
||||
import android.app.StatusBarManager;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.SysUiServiceProvider;
|
||||
import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.NavigationBarController;
|
||||
import com.android.systemui.statusbar.phone.NavigationBarFragment;
|
||||
|
||||
/**
|
||||
* Assistant Handle behavior that makes Assistant handles show/hide when the home handle is
|
||||
* shown/hidden, respectively.
|
||||
*/
|
||||
final class AssistHandleLikeHomeBehavior implements BehaviorController {
|
||||
|
||||
private final CommandQueue.Callbacks mCallbacks = new CommandQueue.Callbacks() {
|
||||
@Override
|
||||
public void setWindowState(int displayId, int window, int state) {
|
||||
if (mNavBarDisplayId == displayId
|
||||
&& window == StatusBarManager.WINDOW_NAVIGATION_BAR) {
|
||||
handleWindowStateChanged(state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private CommandQueue mCommandQueue;
|
||||
private int mNavBarDisplayId;
|
||||
private boolean mIsNavBarWindowVisible;
|
||||
|
||||
@Nullable private AssistHandleCallbacks mAssistHandleCallbacks;
|
||||
|
||||
@Override
|
||||
public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
|
||||
mAssistHandleCallbacks = callbacks;
|
||||
NavigationBarFragment navigationBarFragment =
|
||||
Dependency.get(NavigationBarController.class).getDefaultNavigationBarFragment();
|
||||
mNavBarDisplayId = navigationBarFragment.mDisplayId;
|
||||
mIsNavBarWindowVisible = navigationBarFragment.isNavBarWindowVisible();
|
||||
mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class);
|
||||
mCommandQueue.addCallback(mCallbacks);
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModeDeactivated() {
|
||||
mAssistHandleCallbacks = null;
|
||||
mCommandQueue.removeCallback(mCallbacks);
|
||||
}
|
||||
|
||||
private void handleWindowStateChanged(int state) {
|
||||
boolean newVisibility = state == StatusBarManager.WINDOW_STATE_SHOWING;
|
||||
if (mIsNavBarWindowVisible == newVisibility) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsNavBarWindowVisible = newVisibility;
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
private void callbackForCurrentState() {
|
||||
if (mAssistHandleCallbacks == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsNavBarWindowVisible) {
|
||||
mAssistHandleCallbacks.showAndStay();
|
||||
} else {
|
||||
mAssistHandleCallbacks.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.assist;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
|
||||
|
||||
/** Assistant handle behavior that hides the Assistant handles. */
|
||||
final class AssistHandleOffBehavior implements BehaviorController {
|
||||
|
||||
@Override
|
||||
public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
|
||||
callbacks.hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModeDeactivated() {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.assist;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.SysUiServiceProvider;
|
||||
import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.recents.OverviewProxyService;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
|
||||
/**
|
||||
* Assistant handle behavior that hides the handles when the phone is dozing or in immersive mode,
|
||||
* shows the handles when on lockscreen, and shows the handles temporarily when changing tasks or
|
||||
* entering overview.
|
||||
*/
|
||||
final class AssistHandleReminderExpBehavior implements BehaviorController {
|
||||
|
||||
private final StatusBarStateController.StateListener mStatusBarStateListener =
|
||||
new StatusBarStateController.StateListener() {
|
||||
@Override
|
||||
public void onStateChanged(int newState) {
|
||||
handleStatusBarStateChanged(newState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDozingChanged(boolean isDozing) {
|
||||
handleDozingChanged(isDozing);
|
||||
}
|
||||
};
|
||||
private final TaskStackChangeListener mTaskStackChangeListener =
|
||||
new TaskStackChangeListener() {
|
||||
@Override
|
||||
public void onTaskMovedToFront(int taskId) {
|
||||
handleTaskStackTopChanged(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskCreated(int taskId, ComponentName componentName) {
|
||||
handleTaskStackTopChanged(taskId);
|
||||
}
|
||||
};
|
||||
private final CommandQueue.Callbacks mCallbacks = new CommandQueue.Callbacks() {
|
||||
@Override
|
||||
public void setSystemUiVisibility(int displayId, int vis,
|
||||
int fullscreenStackVis, int dockedStackVis, int mask,
|
||||
Rect fullscreenStackBounds, Rect dockedStackBounds,
|
||||
boolean navbarColorManagedByIme) {
|
||||
if (mStatusBarDisplayId == displayId) {
|
||||
handleSystemUiVisibilityChange(vis, mask);
|
||||
}
|
||||
}
|
||||
};
|
||||
private final OverviewProxyService.OverviewProxyListener mOverviewProxyListener =
|
||||
new OverviewProxyService.OverviewProxyListener() {
|
||||
@Override
|
||||
public void onOverviewShown(boolean fromHome) {
|
||||
handleOverviewShown();
|
||||
}
|
||||
};
|
||||
|
||||
private StatusBarStateController mStatusBarStateController;
|
||||
private ActivityManagerWrapper mActivityManagerWrapper;
|
||||
private OverviewProxyService mOverviewProxyService;
|
||||
private int mStatusBarDisplayId;
|
||||
private CommandQueue mCommandQueue;
|
||||
private boolean mOnLockscreen;
|
||||
private boolean mIsDozing;
|
||||
private int mRunningTaskId;
|
||||
private boolean mIsImmersive;
|
||||
|
||||
@Nullable private AssistHandleCallbacks mAssistHandleCallbacks;
|
||||
|
||||
@Override
|
||||
public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
|
||||
mAssistHandleCallbacks = callbacks;
|
||||
mStatusBarStateController = Dependency.get(StatusBarStateController.class);
|
||||
mOnLockscreen = onLockscreen(mStatusBarStateController.getState());
|
||||
mIsDozing = mStatusBarStateController.isDozing();
|
||||
mStatusBarStateController.addCallback(mStatusBarStateListener);
|
||||
mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
|
||||
mRunningTaskId = mActivityManagerWrapper.getRunningTask().taskId;
|
||||
mActivityManagerWrapper.registerTaskStackListener(mTaskStackChangeListener);
|
||||
mStatusBarDisplayId =
|
||||
((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
|
||||
.getDefaultDisplay().getDisplayId();
|
||||
mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class);
|
||||
mCommandQueue.addCallback(mCallbacks);
|
||||
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
|
||||
mOverviewProxyService.addCallback(mOverviewProxyListener);
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModeDeactivated() {
|
||||
mAssistHandleCallbacks = null;
|
||||
mStatusBarStateController.removeCallback(mStatusBarStateListener);
|
||||
mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackChangeListener);
|
||||
mCommandQueue.removeCallback(mCallbacks);
|
||||
mOverviewProxyService.removeCallback(mOverviewProxyListener);
|
||||
}
|
||||
|
||||
private void handleStatusBarStateChanged(int newState) {
|
||||
boolean onLockscreen = onLockscreen(newState);
|
||||
if (mOnLockscreen == onLockscreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
mOnLockscreen = onLockscreen;
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
private void handleDozingChanged(boolean isDozing) {
|
||||
if (mIsDozing == isDozing) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsDozing = isDozing;
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
private void handleTaskStackTopChanged(int taskId) {
|
||||
if (mRunningTaskId == taskId) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRunningTaskId = taskId;
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
private void handleSystemUiVisibilityChange(int vis, int mask) {
|
||||
boolean isImmersive = isImmersive(vis, mask);
|
||||
if (mIsImmersive == isImmersive) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsImmersive = isImmersive;
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
private void handleOverviewShown() {
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
private boolean onLockscreen(int statusBarState) {
|
||||
return statusBarState == StatusBarState.KEYGUARD
|
||||
|| statusBarState == StatusBarState.SHADE_LOCKED;
|
||||
}
|
||||
|
||||
private boolean isImmersive(int vis, int mask) {
|
||||
return ((vis & mask)
|
||||
& (View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)) != 0;
|
||||
}
|
||||
|
||||
private void callbackForCurrentState() {
|
||||
if (mAssistHandleCallbacks == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsDozing || mIsImmersive) {
|
||||
mAssistHandleCallbacks.hide();
|
||||
} else if (mOnLockscreen) {
|
||||
mAssistHandleCallbacks.showAndStay();
|
||||
} else {
|
||||
mAssistHandleCallbacks.showAndGo();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@ public class AssistManager implements ConfigurationChangedReceiver {
|
||||
private final AssistDisclosure mAssistDisclosure;
|
||||
private final InterestingConfigChanges mInterestingConfigChanges;
|
||||
private final PhoneStateMonitor mPhoneStateMonitor;
|
||||
private final AssistHandleBehaviorController mHandleController;
|
||||
|
||||
private AssistOrbContainer mView;
|
||||
private final DeviceProvisionedController mDeviceProvisionedController;
|
||||
@@ -110,6 +111,7 @@ public class AssistManager implements ConfigurationChangedReceiver {
|
||||
mAssistUtils = new AssistUtils(context);
|
||||
mAssistDisclosure = new AssistDisclosure(context, new Handler());
|
||||
mPhoneStateMonitor = new PhoneStateMonitor(context);
|
||||
mHandleController = new AssistHandleBehaviorController(context, new Handler());
|
||||
|
||||
registerVoiceInteractionSessionListener();
|
||||
mInterestingConfigChanges = new InterestingConfigChanges(ActivityInfo.CONFIG_ORIENTATION
|
||||
@@ -352,6 +354,10 @@ public class AssistManager implements ConfigurationChangedReceiver {
|
||||
v.setImageDrawable(null);
|
||||
}
|
||||
|
||||
protected AssistHandleBehaviorController getHandleBehaviorController() {
|
||||
return mHandleController;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ComponentName getAssistInfoForUser(int userId) {
|
||||
return mAssistUtils.getAssistComponentForUser(userId);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* Copyright (C) 2019 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.
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.assist;
|
||||
|
||||
import static org.mockito.AdditionalAnswers.answerVoid;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.ScreenDecorations;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper
|
||||
public class AssistHandleBehaviorControllerTest extends SysuiTestCase {
|
||||
|
||||
private final AssistHandleBehavior mTestBehavior = AssistHandleBehavior.TEST;
|
||||
|
||||
private AssistHandleBehaviorController mAssistHandleBehaviorController;
|
||||
|
||||
@Mock private ScreenDecorations mMockScreenDecorations;
|
||||
@Mock private Handler mMockHandler;
|
||||
@Mock private AssistHandleBehaviorController.BehaviorController mMockBehaviorController;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
doAnswer(answerVoid(Runnable::run)).when(mMockHandler).post(any(Runnable.class));
|
||||
doAnswer(answerVoid(Runnable::run)).when(mMockHandler)
|
||||
.postDelayed(any(Runnable.class), anyLong());
|
||||
mTestBehavior.setTestController(mMockBehaviorController);
|
||||
mAssistHandleBehaviorController =
|
||||
new AssistHandleBehaviorController(
|
||||
mContext, mMockHandler, () -> mMockScreenDecorations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hide_hidesHandlesWhenShowing() {
|
||||
// Arrange
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
reset(mMockScreenDecorations);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.hide();
|
||||
|
||||
// Assert
|
||||
verify(mMockScreenDecorations).setAssistHintVisible(false);
|
||||
verifyNoMoreInteractions(mMockScreenDecorations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hide_doesNothingWhenHiding() {
|
||||
// Arrange
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockScreenDecorations);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.hide();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockScreenDecorations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndStay_showsHandlesWhenHiding() {
|
||||
// Arrange
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockScreenDecorations);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
|
||||
// Assert
|
||||
verify(mMockScreenDecorations).setAssistHintVisible(true);
|
||||
verifyNoMoreInteractions(mMockScreenDecorations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndStay_doesNothingWhenShowing() {
|
||||
// Arrange
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
reset(mMockScreenDecorations);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockScreenDecorations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGo_showsThenHidesHandlesWhenHiding() {
|
||||
// Arrange
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockScreenDecorations);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
|
||||
// Assert
|
||||
InOrder inOrder = inOrder(mMockScreenDecorations);
|
||||
inOrder.verify(mMockScreenDecorations).setAssistHintVisible(true);
|
||||
inOrder.verify(mMockScreenDecorations).setAssistHintVisible(false);
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGo_hidesHandlesAfterTimeoutWhenShowing() {
|
||||
// Arrange
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
reset(mMockScreenDecorations);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
|
||||
// Assert
|
||||
verify(mMockScreenDecorations).setAssistHintVisible(false);
|
||||
verifyNoMoreInteractions(mMockScreenDecorations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGo_doesNothingIfRecentlyHidden() {
|
||||
// Arrange
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
reset(mMockScreenDecorations);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockScreenDecorations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBehavior_activatesTheBehaviorWhenInGesturalMode() {
|
||||
// Arrange
|
||||
mAssistHandleBehaviorController.setInGesturalModeForTest(true);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.setBehavior(mTestBehavior);
|
||||
|
||||
// Assert
|
||||
verify(mMockBehaviorController).onModeActivated(mContext, mAssistHandleBehaviorController);
|
||||
verifyNoMoreInteractions(mMockBehaviorController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBehavior_deactivatesThePreviousBehaviorWhenInGesturalMode() {
|
||||
// Arrange
|
||||
mAssistHandleBehaviorController.setBehavior(mTestBehavior);
|
||||
mAssistHandleBehaviorController.setInGesturalModeForTest(true);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.setBehavior(AssistHandleBehavior.OFF);
|
||||
|
||||
// Assert
|
||||
verify(mMockBehaviorController).onModeDeactivated();
|
||||
verifyNoMoreInteractions(mMockBehaviorController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBehavior_doesNothingWhenNotInGesturalMode() {
|
||||
// Arrange
|
||||
mAssistHandleBehaviorController.setInGesturalModeForTest(false);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.setBehavior(mTestBehavior);
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockBehaviorController);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user