Merge "Remove Assistant corner handles" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
bae77dcdbb
@@ -19,27 +19,11 @@
|
||||
|
||||
<com.android.systemui.navigationbar.NavigationBarView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/navigation_bar_view"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@drawable/system_bar_background">
|
||||
|
||||
<com.android.systemui.CornerHandleView
|
||||
android:id="@+id/assist_hint_left"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="left|bottom"
|
||||
android:rotation="270"
|
||||
android:visibility="gone"/>
|
||||
<com.android.systemui.CornerHandleView
|
||||
android:id="@+id/assist_hint_right"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="right|bottom"
|
||||
android:rotation="180"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.android.systemui.navigationbar.NavigationBarInflaterView
|
||||
android:id="@+id/navigation_inflater"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.animation.ArgbEvaluator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.settingslib.Utils;
|
||||
|
||||
/**
|
||||
* CornerHandleView draws an inset arc intended to be displayed within the screen decoration
|
||||
* corners.
|
||||
*/
|
||||
public class CornerHandleView extends View {
|
||||
private static final float STROKE_DP_LARGE = 2f;
|
||||
private static final float STROKE_DP_SMALL = 1.95f;
|
||||
// Radius to use if none is available.
|
||||
private static final int FALLBACK_RADIUS_DP = 15;
|
||||
private static final float MARGIN_DP = 8;
|
||||
private static final int MAX_ARC_DEGREES = 90;
|
||||
// Arc length along the phone's perimeter used to measure the desired angle.
|
||||
private static final float ARC_LENGTH_DP = 31f;
|
||||
|
||||
private Paint mPaint;
|
||||
private int mLightColor;
|
||||
private int mDarkColor;
|
||||
private Path mPath;
|
||||
private boolean mRequiresInvalidate;
|
||||
|
||||
public CornerHandleView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
mPaint = new Paint();
|
||||
mPaint.setAntiAlias(true);
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
mPaint.setStrokeWidth(getStrokePx());
|
||||
|
||||
final int dualToneDarkTheme = Utils.getThemeAttr(mContext, R.attr.darkIconTheme);
|
||||
final int dualToneLightTheme = Utils.getThemeAttr(mContext, R.attr.lightIconTheme);
|
||||
Context lightContext = new ContextThemeWrapper(mContext, dualToneLightTheme);
|
||||
Context darkContext = new ContextThemeWrapper(mContext, dualToneDarkTheme);
|
||||
mLightColor = Utils.getColorAttrDefaultColor(lightContext, R.attr.singleToneColor);
|
||||
mDarkColor = Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor);
|
||||
|
||||
updatePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(float alpha) {
|
||||
super.setAlpha(alpha);
|
||||
if (alpha > 0f && mRequiresInvalidate) {
|
||||
mRequiresInvalidate = false;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePath() {
|
||||
mPath = new Path();
|
||||
|
||||
float marginPx = getMarginPx();
|
||||
float radiusPx = getInnerRadiusPx();
|
||||
float halfStrokePx = getStrokePx() / 2f;
|
||||
float angle = getAngle();
|
||||
float startAngle = 180 + ((90 - angle) / 2);
|
||||
RectF circle = new RectF(marginPx + halfStrokePx,
|
||||
marginPx + halfStrokePx,
|
||||
marginPx + 2 * radiusPx - halfStrokePx,
|
||||
marginPx + 2 * radiusPx - halfStrokePx);
|
||||
|
||||
if (angle >= 90f) {
|
||||
float innerCircumferenceDp = convertPixelToDp(radiusPx * 2 * (float) Math.PI,
|
||||
mContext);
|
||||
float arcDp = innerCircumferenceDp * getAngle() / 360f;
|
||||
// Add additional "arms" to the two ends of the arc. The length computation is
|
||||
// hand-tuned.
|
||||
float lineLengthPx = convertDpToPixel((ARC_LENGTH_DP - arcDp - MARGIN_DP) / 2,
|
||||
mContext);
|
||||
|
||||
mPath.moveTo(marginPx + halfStrokePx, marginPx + radiusPx + lineLengthPx);
|
||||
mPath.lineTo(marginPx + halfStrokePx, marginPx + radiusPx);
|
||||
mPath.arcTo(circle, startAngle, angle);
|
||||
mPath.moveTo(marginPx + radiusPx, marginPx + halfStrokePx);
|
||||
mPath.lineTo(marginPx + radiusPx + lineLengthPx, marginPx + halfStrokePx);
|
||||
} else {
|
||||
mPath.arcTo(circle, startAngle, angle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives an intensity from 0 (lightest) to 1 (darkest) and sets the handle color
|
||||
* appropriately. Intention is to match the home handle color.
|
||||
*/
|
||||
public void updateDarkness(float darkIntensity) {
|
||||
// Handle color is same as home handle color.
|
||||
int color = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
|
||||
mLightColor, mDarkColor);
|
||||
if (mPaint.getColor() != color) {
|
||||
mPaint.setColor(color);
|
||||
if (getVisibility() == VISIBLE && getAlpha() > 0) {
|
||||
invalidate();
|
||||
} else {
|
||||
// If we are currently invisible, then invalidate when we are next made visible
|
||||
mRequiresInvalidate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
canvas.drawPath(mPath, mPaint);
|
||||
}
|
||||
|
||||
private static float convertDpToPixel(float dp, Context context) {
|
||||
return dp * ((float) context.getResources().getDisplayMetrics().densityDpi
|
||||
/ DisplayMetrics.DENSITY_DEFAULT);
|
||||
}
|
||||
|
||||
private static float convertPixelToDp(float px, Context context) {
|
||||
return px * DisplayMetrics.DENSITY_DEFAULT
|
||||
/ ((float) context.getResources().getDisplayMetrics().densityDpi);
|
||||
}
|
||||
|
||||
private float getAngle() {
|
||||
// Measure a length of ARC_LENGTH_DP along the *screen's* perimeter, get the angle and cap
|
||||
// it at 90.
|
||||
float circumferenceDp = convertPixelToDp((
|
||||
getOuterRadiusPx()) * 2 * (float) Math.PI, mContext);
|
||||
float angleDeg = (ARC_LENGTH_DP / circumferenceDp) * 360;
|
||||
if (angleDeg > MAX_ARC_DEGREES) {
|
||||
angleDeg = MAX_ARC_DEGREES;
|
||||
}
|
||||
return angleDeg;
|
||||
}
|
||||
|
||||
private float getMarginPx() {
|
||||
return convertDpToPixel(MARGIN_DP, mContext);
|
||||
}
|
||||
|
||||
private float getInnerRadiusPx() {
|
||||
return getOuterRadiusPx() - getMarginPx();
|
||||
}
|
||||
|
||||
private float getOuterRadiusPx() {
|
||||
// Attempt to get the bottom corner radius, otherwise fall back on the generic or top
|
||||
// values. If none are available, use the FALLBACK_RADIUS_DP.
|
||||
int radius = getResources().getDimensionPixelSize(
|
||||
com.android.systemui.R.dimen.config_rounded_mask_size_bottom);
|
||||
if (radius == 0) {
|
||||
radius = getResources().getDimensionPixelSize(
|
||||
com.android.systemui.R.dimen.config_rounded_mask_size);
|
||||
}
|
||||
if (radius == 0) {
|
||||
radius = getResources().getDimensionPixelSize(
|
||||
com.android.systemui.R.dimen.config_rounded_mask_size_top);
|
||||
}
|
||||
if (radius == 0) {
|
||||
radius = (int) convertDpToPixel(FALLBACK_RADIUS_DP, mContext);
|
||||
}
|
||||
return radius;
|
||||
}
|
||||
|
||||
private float getStrokePx() {
|
||||
// Use a slightly smaller stroke if we need to cover the full corner angle.
|
||||
return convertDpToPixel((getAngle() < 90) ? STROKE_DP_LARGE : STROKE_DP_SMALL,
|
||||
getContext());
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public enum AssistHandleBehavior {
|
||||
|
||||
TEST,
|
||||
OFF,
|
||||
LIKE_HOME,
|
||||
REMINDER_EXP;
|
||||
}
|
||||
@@ -1,336 +0,0 @@
|
||||
/*
|
||||
* 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 com.android.systemui.assist.AssistModule.ASSIST_HANDLE_THREAD_NAME;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.app.AssistUtils;
|
||||
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.navigationbar.NavigationModeController;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import dagger.Lazy;
|
||||
|
||||
/**
|
||||
* A class for managing Assistant handle logic.
|
||||
*
|
||||
* Controls when visual handles for Assistant gesture affordance should be shown or hidden using an
|
||||
* {@link AssistHandleBehavior}.
|
||||
*/
|
||||
@SysUISingleton
|
||||
public final class AssistHandleBehaviorController implements AssistHandleCallbacks, Dumpable {
|
||||
|
||||
private static final String TAG = "AssistHandleBehavior";
|
||||
|
||||
private static final long DEFAULT_SHOWN_FREQUENCY_THRESHOLD_MS = 0;
|
||||
private static final long DEFAULT_SHOW_AND_GO_DURATION_MS = TimeUnit.SECONDS.toMillis(3);
|
||||
private static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete";
|
||||
|
||||
/**
|
||||
* This is the default behavior that will be used once the system is up. It will be set once the
|
||||
* behavior dependencies are available. This ensures proper behavior lifecycle.
|
||||
*/
|
||||
private static final AssistHandleBehavior DEFAULT_BEHAVIOR = AssistHandleBehavior.REMINDER_EXP;
|
||||
|
||||
private final Context mContext;
|
||||
private final AssistUtils mAssistUtils;
|
||||
private final Handler mHandler;
|
||||
private final Runnable mHideHandles = this::hideHandles;
|
||||
private final Runnable mShowAndGo = this::showAndGoInternal;
|
||||
private final Provider<AssistHandleViewController> mAssistHandleViewController;
|
||||
private final DeviceConfigHelper mDeviceConfigHelper;
|
||||
private final Map<AssistHandleBehavior, BehaviorController> mBehaviorMap;
|
||||
private final Lazy<AccessibilityManager> mA11yManager;
|
||||
|
||||
private boolean mHandlesShowing = false;
|
||||
private long mHandlesLastHiddenAt;
|
||||
private long mShowAndGoEndsAt;
|
||||
/**
|
||||
* This should always be initialized as {@link AssistHandleBehavior#OFF} to ensure proper
|
||||
* behavior lifecycle.
|
||||
*/
|
||||
private AssistHandleBehavior mCurrentBehavior = AssistHandleBehavior.OFF;
|
||||
private boolean mInGesturalMode;
|
||||
|
||||
@Inject
|
||||
AssistHandleBehaviorController(
|
||||
Context context,
|
||||
AssistUtils assistUtils,
|
||||
@Named(ASSIST_HANDLE_THREAD_NAME) Handler handler,
|
||||
Provider<AssistHandleViewController> assistHandleViewController,
|
||||
DeviceConfigHelper deviceConfigHelper,
|
||||
Map<AssistHandleBehavior, BehaviorController> behaviorMap,
|
||||
NavigationModeController navigationModeController,
|
||||
Lazy<AccessibilityManager> a11yManager,
|
||||
DumpManager dumpManager) {
|
||||
mContext = context;
|
||||
mAssistUtils = assistUtils;
|
||||
mHandler = handler;
|
||||
mAssistHandleViewController = assistHandleViewController;
|
||||
mDeviceConfigHelper = deviceConfigHelper;
|
||||
mBehaviorMap = behaviorMap;
|
||||
mA11yManager = a11yManager;
|
||||
|
||||
mInGesturalMode = QuickStepContract.isGesturalMode(
|
||||
navigationModeController.addListener(this::handleNavigationModeChange));
|
||||
|
||||
setBehavior(getBehaviorMode());
|
||||
mDeviceConfigHelper.addOnPropertiesChangedListener(
|
||||
mHandler::post,
|
||||
(properties) -> {
|
||||
if (properties.getKeyset().contains(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_BEHAVIOR_MODE)) {
|
||||
setBehavior(properties.getString(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_BEHAVIOR_MODE, null));
|
||||
}
|
||||
});
|
||||
|
||||
dumpManager.registerDumpable(TAG, this);
|
||||
}
|
||||
|
||||
@Override // AssistHandleCallbacks
|
||||
public void hide() {
|
||||
clearPendingCommands();
|
||||
mHandler.post(mHideHandles);
|
||||
}
|
||||
|
||||
@Override // AssistHandleCallbacks
|
||||
public void showAndGo() {
|
||||
clearPendingCommands();
|
||||
mHandler.post(mShowAndGo);
|
||||
}
|
||||
|
||||
private void showAndGoInternal() {
|
||||
maybeShowHandles(/* ignoreThreshold = */ false);
|
||||
long showAndGoDuration = getShowAndGoDuration();
|
||||
mShowAndGoEndsAt = SystemClock.elapsedRealtime() + showAndGoDuration;
|
||||
mHandler.postDelayed(mHideHandles, showAndGoDuration);
|
||||
}
|
||||
|
||||
@Override // AssistHandleCallbacks
|
||||
public void showAndGoDelayed(long delayMs, boolean hideIfShowing) {
|
||||
clearPendingCommands();
|
||||
if (hideIfShowing) {
|
||||
mHandler.post(mHideHandles);
|
||||
}
|
||||
mHandler.postDelayed(mShowAndGo, delayMs);
|
||||
}
|
||||
|
||||
@Override // AssistHandleCallbacks
|
||||
public void showAndStay() {
|
||||
clearPendingCommands();
|
||||
mHandler.post(() -> maybeShowHandles(/* ignoreThreshold = */ true));
|
||||
}
|
||||
|
||||
public long getShowAndGoRemainingTimeMs() {
|
||||
return Long.max(mShowAndGoEndsAt - SystemClock.elapsedRealtime(), 0);
|
||||
}
|
||||
|
||||
public boolean areHandlesShowing() {
|
||||
return mHandlesShowing;
|
||||
}
|
||||
|
||||
void onAssistantGesturePerformed() {
|
||||
mBehaviorMap.get(mCurrentBehavior).onAssistantGesturePerformed();
|
||||
}
|
||||
|
||||
void onAssistHandlesRequested() {
|
||||
if (mInGesturalMode) {
|
||||
mBehaviorMap.get(mCurrentBehavior).onAssistHandlesRequested();
|
||||
}
|
||||
}
|
||||
|
||||
void setBehavior(AssistHandleBehavior behavior) {
|
||||
if (mCurrentBehavior == behavior) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mBehaviorMap.containsKey(behavior)) {
|
||||
Log.e(TAG, "Unsupported behavior requested: " + behavior.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (mInGesturalMode) {
|
||||
mBehaviorMap.get(mCurrentBehavior).onModeDeactivated();
|
||||
mBehaviorMap.get(behavior).onModeActivated(mContext, /* callbacks = */ this);
|
||||
}
|
||||
|
||||
mCurrentBehavior = behavior;
|
||||
}
|
||||
|
||||
private void setBehavior(@Nullable String behavior) {
|
||||
try {
|
||||
setBehavior(AssistHandleBehavior.valueOf(behavior));
|
||||
} catch (IllegalArgumentException | NullPointerException e) {
|
||||
Log.e(TAG, "Invalid behavior: " + behavior);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handlesUnblocked(boolean ignoreThreshold) {
|
||||
if (!isUserSetupComplete()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long timeSinceHidden = SystemClock.elapsedRealtime() - mHandlesLastHiddenAt;
|
||||
boolean notThrottled = ignoreThreshold || timeSinceHidden >= getShownFrequencyThreshold();
|
||||
ComponentName assistantComponent =
|
||||
mAssistUtils.getAssistComponentForUser(KeyguardUpdateMonitor.getCurrentUser());
|
||||
return notThrottled && assistantComponent != null;
|
||||
}
|
||||
|
||||
private long getShownFrequencyThreshold() {
|
||||
return mDeviceConfigHelper.getLong(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS,
|
||||
DEFAULT_SHOWN_FREQUENCY_THRESHOLD_MS);
|
||||
}
|
||||
|
||||
private long getShowAndGoDuration() {
|
||||
long configuredTime = mDeviceConfigHelper.getLong(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DURATION_MS,
|
||||
DEFAULT_SHOW_AND_GO_DURATION_MS);
|
||||
return mA11yManager.get().getRecommendedTimeoutMillis(
|
||||
(int) configuredTime, AccessibilityManager.FLAG_CONTENT_ICONS);
|
||||
}
|
||||
|
||||
private String getBehaviorMode() {
|
||||
return mDeviceConfigHelper.getString(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_BEHAVIOR_MODE,
|
||||
DEFAULT_BEHAVIOR.toString());
|
||||
}
|
||||
|
||||
private void maybeShowHandles(boolean ignoreThreshold) {
|
||||
if (mHandlesShowing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handlesUnblocked(ignoreThreshold)) {
|
||||
mHandlesShowing = true;
|
||||
AssistHandleViewController assistHandleViewController =
|
||||
mAssistHandleViewController.get();
|
||||
if (assistHandleViewController == null) {
|
||||
Log.w(TAG, "Couldn't show handles, AssistHandleViewController unavailable");
|
||||
} else {
|
||||
assistHandleViewController.setAssistHintVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void hideHandles() {
|
||||
if (!mHandlesShowing) {
|
||||
return;
|
||||
}
|
||||
|
||||
mHandlesShowing = false;
|
||||
mHandlesLastHiddenAt = SystemClock.elapsedRealtime();
|
||||
AssistHandleViewController assistHandleViewController =
|
||||
mAssistHandleViewController.get();
|
||||
if (assistHandleViewController == null) {
|
||||
Log.w(TAG, "Couldn't show handles, AssistHandleViewController unavailable");
|
||||
} else {
|
||||
assistHandleViewController.setAssistHintVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNavigationModeChange(int navigationMode) {
|
||||
boolean inGesturalMode = QuickStepContract.isGesturalMode(navigationMode);
|
||||
if (mInGesturalMode == inGesturalMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInGesturalMode = inGesturalMode;
|
||||
if (mInGesturalMode) {
|
||||
mBehaviorMap.get(mCurrentBehavior).onModeActivated(mContext, /* callbacks = */ this);
|
||||
} else {
|
||||
mBehaviorMap.get(mCurrentBehavior).onModeDeactivated();
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearPendingCommands() {
|
||||
mHandler.removeCallbacks(mHideHandles);
|
||||
mHandler.removeCallbacks(mShowAndGo);
|
||||
mShowAndGoEndsAt = 0;
|
||||
}
|
||||
|
||||
private boolean isUserSetupComplete() {
|
||||
return Settings.Secure.getInt(
|
||||
mContext.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setInGesturalModeForTest(boolean inGesturalMode) {
|
||||
mInGesturalMode = inGesturalMode;
|
||||
}
|
||||
|
||||
@Override // Dumpable
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println("Current AssistHandleBehaviorController State:");
|
||||
|
||||
pw.println(" mHandlesShowing=" + mHandlesShowing);
|
||||
pw.println(" mHandlesLastHiddenAt=" + mHandlesLastHiddenAt);
|
||||
pw.println(" mInGesturalMode=" + mInGesturalMode);
|
||||
|
||||
pw.println(" Phenotype Flags:");
|
||||
pw.println(" "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DURATION_MS + "(a11y modded)"
|
||||
+ "="
|
||||
+ getShowAndGoDuration());
|
||||
pw.println(" "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS
|
||||
+ "="
|
||||
+ getShownFrequencyThreshold());
|
||||
pw.println(" "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_BEHAVIOR_MODE
|
||||
+ "="
|
||||
+ getBehaviorMode());
|
||||
|
||||
pw.println(" mCurrentBehavior=" + mCurrentBehavior.toString());
|
||||
mBehaviorMap.get(mCurrentBehavior).dump(pw, " ");
|
||||
}
|
||||
|
||||
interface BehaviorController {
|
||||
void onModeActivated(Context context, AssistHandleCallbacks callbacks);
|
||||
default void onModeDeactivated() {}
|
||||
default void onAssistantGesturePerformed() {}
|
||||
default void onAssistHandlesRequested() {}
|
||||
default void dump(PrintWriter pw, String prefix) {}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* Same as show and go, but will not do anything until a delay has elapsed.
|
||||
*
|
||||
* Will be cancelled if another command is given during the delay.
|
||||
*/
|
||||
void showAndGoDelayed(long delayMs, boolean hideIfShowing);
|
||||
|
||||
/** Show the Assistant handles. */
|
||||
void showAndStay();
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* 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 androidx.annotation.Nullable;
|
||||
|
||||
import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
import com.android.systemui.model.SysUiState;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.Lazy;
|
||||
|
||||
/**
|
||||
* Assistant Handle behavior that makes Assistant handles show/hide when the home handle is
|
||||
* shown/hidden, respectively.
|
||||
*/
|
||||
@SysUISingleton
|
||||
final class AssistHandleLikeHomeBehavior implements BehaviorController {
|
||||
|
||||
private final StatusBarStateController.StateListener mStatusBarStateListener =
|
||||
new StatusBarStateController.StateListener() {
|
||||
@Override
|
||||
public void onDozingChanged(boolean isDozing) {
|
||||
handleDozingChanged(isDozing);
|
||||
}
|
||||
};
|
||||
private final WakefulnessLifecycle.Observer mWakefulnessLifecycleObserver =
|
||||
new WakefulnessLifecycle.Observer() {
|
||||
@Override
|
||||
public void onStartedWakingUp() {
|
||||
handleWakefullnessChanged(/* isAwake = */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishedWakingUp() {
|
||||
handleWakefullnessChanged(/* isAwake = */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartedGoingToSleep() {
|
||||
handleWakefullnessChanged(/* isAwake = */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishedGoingToSleep() {
|
||||
handleWakefullnessChanged(/* isAwake = */ false);
|
||||
}
|
||||
};
|
||||
|
||||
private final SysUiState.SysUiStateCallback mSysUiStateCallback =
|
||||
this::handleSystemUiStateChange;
|
||||
|
||||
private final Lazy<StatusBarStateController> mStatusBarStateController;
|
||||
private final Lazy<WakefulnessLifecycle> mWakefulnessLifecycle;
|
||||
private final Lazy<SysUiState> mSysUiFlagContainer;
|
||||
|
||||
private boolean mIsDozing;
|
||||
private boolean mIsAwake;
|
||||
private boolean mIsHomeHandleHiding;
|
||||
|
||||
@Nullable private AssistHandleCallbacks mAssistHandleCallbacks;
|
||||
|
||||
@Inject
|
||||
AssistHandleLikeHomeBehavior(
|
||||
Lazy<StatusBarStateController> statusBarStateController,
|
||||
Lazy<WakefulnessLifecycle> wakefulnessLifecycle,
|
||||
Lazy<SysUiState> sysUiFlagContainer) {
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mWakefulnessLifecycle = wakefulnessLifecycle;
|
||||
mSysUiFlagContainer = sysUiFlagContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
|
||||
mAssistHandleCallbacks = callbacks;
|
||||
mIsDozing = mStatusBarStateController.get().isDozing();
|
||||
mStatusBarStateController.get().addCallback(mStatusBarStateListener);
|
||||
mIsAwake = mWakefulnessLifecycle.get().getWakefulness()
|
||||
== WakefulnessLifecycle.WAKEFULNESS_AWAKE;
|
||||
mWakefulnessLifecycle.get().addObserver(mWakefulnessLifecycleObserver);
|
||||
mSysUiFlagContainer.get().addCallback(mSysUiStateCallback);
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModeDeactivated() {
|
||||
mAssistHandleCallbacks = null;
|
||||
mStatusBarStateController.get().removeCallback(mStatusBarStateListener);
|
||||
mWakefulnessLifecycle.get().removeObserver(mWakefulnessLifecycleObserver);
|
||||
mSysUiFlagContainer.get().removeCallback(mSysUiStateCallback);
|
||||
}
|
||||
|
||||
private static boolean isHomeHandleHiding(int sysuiStateFlags) {
|
||||
return (sysuiStateFlags & QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
|
||||
}
|
||||
|
||||
private void handleDozingChanged(boolean isDozing) {
|
||||
if (mIsDozing == isDozing) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsDozing = isDozing;
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
private void handleWakefullnessChanged(boolean isAwake) {
|
||||
if (mIsAwake == isAwake) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsAwake = isAwake;
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
private void handleSystemUiStateChange(int sysuiStateFlags) {
|
||||
boolean isHomeHandleHiding = isHomeHandleHiding(sysuiStateFlags);
|
||||
if (mIsHomeHandleHiding == isHomeHandleHiding) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsHomeHandleHiding = isHomeHandleHiding;
|
||||
callbackForCurrentState();
|
||||
}
|
||||
|
||||
private void callbackForCurrentState() {
|
||||
if (mAssistHandleCallbacks == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsHomeHandleHiding || !isFullyAwake()) {
|
||||
mAssistHandleCallbacks.hide();
|
||||
} else {
|
||||
mAssistHandleCallbacks.showAndStay();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFullyAwake() {
|
||||
return mIsAwake && !mIsDozing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
pw.println(prefix + "Current AssistHandleLikeHomeBehavior State:");
|
||||
|
||||
pw.println(prefix + " mIsDozing=" + mIsDozing);
|
||||
pw.println(prefix + " mIsAwake=" + mIsAwake);
|
||||
pw.println(prefix + " mIsHomeHandleHiding=" + mIsHomeHandleHiding);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** Assistant handle behavior that hides the Assistant handles. */
|
||||
@SysUISingleton
|
||||
final class AssistHandleOffBehavior implements BehaviorController {
|
||||
|
||||
@Inject
|
||||
AssistHandleOffBehavior() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
|
||||
callbacks.hide();
|
||||
}
|
||||
}
|
||||
@@ -1,662 +0,0 @@
|
||||
/*
|
||||
* 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 com.android.systemui.assist.AssistModule.ASSIST_HANDLE_THREAD_NAME;
|
||||
import static com.android.systemui.assist.AssistModule.UPTIME_NAME;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.slice.Clock;
|
||||
|
||||
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
|
||||
import com.android.systemui.BootCompleteCache;
|
||||
import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
import com.android.systemui.model.SysUiState;
|
||||
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.PackageManagerWrapper;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListeners;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import dagger.Lazy;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@SysUISingleton
|
||||
final class AssistHandleReminderExpBehavior implements BehaviorController {
|
||||
|
||||
private static final Uri LEARNING_TIME_ELAPSED_URI =
|
||||
Settings.Secure.getUriFor(Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS);
|
||||
private static final Uri LEARNING_EVENT_COUNT_URI =
|
||||
Settings.Secure.getUriFor(Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT);
|
||||
private static final String LEARNED_HINT_LAST_SHOWN_KEY =
|
||||
"reminder_exp_learned_hint_last_shown";
|
||||
private static final long DEFAULT_LEARNING_TIME_MS = TimeUnit.DAYS.toMillis(10);
|
||||
private static final int DEFAULT_LEARNING_COUNT = 10;
|
||||
private static final long DEFAULT_SHOW_AND_GO_DELAYED_SHORT_DELAY_MS = 150;
|
||||
private static final long DEFAULT_SHOW_AND_GO_DELAYED_LONG_DELAY_MS =
|
||||
TimeUnit.SECONDS.toMillis(1);
|
||||
private static final long DEFAULT_SHOW_AND_GO_DELAY_RESET_TIMEOUT_MS =
|
||||
TimeUnit.SECONDS.toMillis(3);
|
||||
private static final boolean DEFAULT_SUPPRESS_ON_LOCKSCREEN = false;
|
||||
private static final boolean DEFAULT_SUPPRESS_ON_LAUNCHER = false;
|
||||
private static final boolean DEFAULT_SUPPRESS_ON_APPS = true;
|
||||
private static final boolean DEFAULT_SHOW_WHEN_TAUGHT = false;
|
||||
|
||||
private static final String[] DEFAULT_HOME_CHANGE_ACTIONS = new String[] {
|
||||
PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED,
|
||||
Intent.ACTION_PACKAGE_ADDED,
|
||||
Intent.ACTION_PACKAGE_CHANGED,
|
||||
Intent.ACTION_PACKAGE_REMOVED
|
||||
};
|
||||
|
||||
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(ActivityManager.RunningTaskInfo taskInfo) {
|
||||
handleTaskStackTopChanged(taskInfo.taskId, taskInfo.topActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskCreated(int taskId, ComponentName componentName) {
|
||||
handleTaskStackTopChanged(taskId, componentName);
|
||||
}
|
||||
};
|
||||
private final OverviewProxyService.OverviewProxyListener mOverviewProxyListener =
|
||||
new OverviewProxyService.OverviewProxyListener() {
|
||||
@Override
|
||||
public void onOverviewShown(boolean fromHome) {
|
||||
handleOverviewShown();
|
||||
}
|
||||
};
|
||||
private final SysUiState.SysUiStateCallback mSysUiStateCallback =
|
||||
this::handleSystemUiStateChanged;
|
||||
private final WakefulnessLifecycle.Observer mWakefulnessLifecycleObserver =
|
||||
new WakefulnessLifecycle.Observer() {
|
||||
@Override
|
||||
public void onStartedWakingUp() {
|
||||
handleWakefullnessChanged(/* isAwake = */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishedWakingUp() {
|
||||
handleWakefullnessChanged(/* isAwake = */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartedGoingToSleep() {
|
||||
handleWakefullnessChanged(/* isAwake = */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishedGoingToSleep() {
|
||||
handleWakefullnessChanged(/* isAwake = */ false);
|
||||
}
|
||||
};
|
||||
private final BroadcastReceiver mDefaultHomeBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mDefaultHome = getCurrentDefaultHome();
|
||||
}
|
||||
};
|
||||
|
||||
private final BootCompleteCache.BootCompleteListener mBootCompleteListener =
|
||||
new BootCompleteCache.BootCompleteListener() {
|
||||
@Override
|
||||
public void onBootComplete() {
|
||||
mDefaultHome = getCurrentDefaultHome();
|
||||
}
|
||||
};
|
||||
|
||||
private final IntentFilter mDefaultHomeIntentFilter;
|
||||
private final Runnable mResetConsecutiveTaskSwitches = this::resetConsecutiveTaskSwitches;
|
||||
|
||||
private final Clock mClock;
|
||||
private final Handler mHandler;
|
||||
private final DeviceConfigHelper mDeviceConfigHelper;
|
||||
private final Lazy<StatusBarStateController> mStatusBarStateController;
|
||||
private final Lazy<ActivityManagerWrapper> mActivityManagerWrapper;
|
||||
private final Lazy<TaskStackChangeListeners> mTaskStackChangeListeners;
|
||||
private final Lazy<OverviewProxyService> mOverviewProxyService;
|
||||
private final Lazy<SysUiState> mSysUiFlagContainer;
|
||||
private final Lazy<WakefulnessLifecycle> mWakefulnessLifecycle;
|
||||
private final Lazy<PackageManagerWrapper> mPackageManagerWrapper;
|
||||
private final Lazy<BroadcastDispatcher> mBroadcastDispatcher;
|
||||
private final Lazy<BootCompleteCache> mBootCompleteCache;
|
||||
|
||||
private boolean mOnLockscreen;
|
||||
private boolean mIsDozing;
|
||||
private boolean mIsAwake;
|
||||
private int mRunningTaskId;
|
||||
private boolean mIsNavBarHidden;
|
||||
private boolean mIsLauncherShowing;
|
||||
private int mConsecutiveTaskSwitches;
|
||||
@Nullable private ContentObserver mSettingObserver;
|
||||
|
||||
/** Whether user has learned the gesture. */
|
||||
private boolean mIsLearned;
|
||||
private long mLastLearningTimestamp;
|
||||
/** Uptime while in this behavior. */
|
||||
private long mLearningTimeElapsed;
|
||||
/** Number of successful Assistant invocations while in this behavior. */
|
||||
private int mLearningCount;
|
||||
private long mLearnedHintLastShownEpochDay;
|
||||
|
||||
@Nullable private Context mContext;
|
||||
@Nullable private AssistHandleCallbacks mAssistHandleCallbacks;
|
||||
@Nullable private ComponentName mDefaultHome;
|
||||
|
||||
@Inject
|
||||
AssistHandleReminderExpBehavior(
|
||||
@Named(UPTIME_NAME) Clock clock,
|
||||
@Named(ASSIST_HANDLE_THREAD_NAME) Handler handler,
|
||||
DeviceConfigHelper deviceConfigHelper,
|
||||
Lazy<StatusBarStateController> statusBarStateController,
|
||||
Lazy<ActivityManagerWrapper> activityManagerWrapper,
|
||||
Lazy<TaskStackChangeListeners> taskStackChangeListeners,
|
||||
Lazy<OverviewProxyService> overviewProxyService,
|
||||
Lazy<SysUiState> sysUiFlagContainer,
|
||||
Lazy<WakefulnessLifecycle> wakefulnessLifecycle,
|
||||
Lazy<PackageManagerWrapper> packageManagerWrapper,
|
||||
Lazy<BroadcastDispatcher> broadcastDispatcher,
|
||||
Lazy<BootCompleteCache> bootCompleteCache) {
|
||||
mClock = clock;
|
||||
mHandler = handler;
|
||||
mDeviceConfigHelper = deviceConfigHelper;
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mActivityManagerWrapper = activityManagerWrapper;
|
||||
mTaskStackChangeListeners = taskStackChangeListeners;
|
||||
mOverviewProxyService = overviewProxyService;
|
||||
mSysUiFlagContainer = sysUiFlagContainer;
|
||||
mWakefulnessLifecycle = wakefulnessLifecycle;
|
||||
mPackageManagerWrapper = packageManagerWrapper;
|
||||
mDefaultHomeIntentFilter = new IntentFilter();
|
||||
for (String action : DEFAULT_HOME_CHANGE_ACTIONS) {
|
||||
mDefaultHomeIntentFilter.addAction(action);
|
||||
}
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mBootCompleteCache = bootCompleteCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
|
||||
mContext = context;
|
||||
mAssistHandleCallbacks = callbacks;
|
||||
mConsecutiveTaskSwitches = 0;
|
||||
mBootCompleteCache.get().addListener(mBootCompleteListener);
|
||||
mDefaultHome = getCurrentDefaultHome();
|
||||
mBroadcastDispatcher.get()
|
||||
.registerReceiver(mDefaultHomeBroadcastReceiver, mDefaultHomeIntentFilter);
|
||||
mOnLockscreen = onLockscreen(mStatusBarStateController.get().getState());
|
||||
mIsDozing = mStatusBarStateController.get().isDozing();
|
||||
mStatusBarStateController.get().addCallback(mStatusBarStateListener);
|
||||
ActivityManager.RunningTaskInfo runningTaskInfo =
|
||||
mActivityManagerWrapper.get().getRunningTask();
|
||||
mRunningTaskId = runningTaskInfo == null ? 0 : runningTaskInfo.taskId;
|
||||
mTaskStackChangeListeners.get().registerTaskStackListener(mTaskStackChangeListener);
|
||||
mOverviewProxyService.get().addCallback(mOverviewProxyListener);
|
||||
mSysUiFlagContainer.get().addCallback(mSysUiStateCallback);
|
||||
mIsAwake = mWakefulnessLifecycle.get().getWakefulness()
|
||||
== WakefulnessLifecycle.WAKEFULNESS_AWAKE;
|
||||
mWakefulnessLifecycle.get().addObserver(mWakefulnessLifecycleObserver);
|
||||
|
||||
mLearningTimeElapsed = Settings.Secure.getLong(
|
||||
context.getContentResolver(),
|
||||
Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
|
||||
/* default = */ 0);
|
||||
mLearningCount = Settings.Secure.getInt(
|
||||
context.getContentResolver(),
|
||||
Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
|
||||
/* default = */ 0);
|
||||
mSettingObserver = new SettingsObserver(context, mHandler);
|
||||
context.getContentResolver().registerContentObserver(
|
||||
LEARNING_TIME_ELAPSED_URI,
|
||||
/* notifyForDescendants = */ true,
|
||||
mSettingObserver);
|
||||
context.getContentResolver().registerContentObserver(
|
||||
LEARNING_EVENT_COUNT_URI,
|
||||
/* notifyForDescendants = */ true,
|
||||
mSettingObserver);
|
||||
mLearnedHintLastShownEpochDay = Settings.Secure.getLong(
|
||||
context.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, /* default = */ 0);
|
||||
mLastLearningTimestamp = mClock.currentTimeMillis();
|
||||
|
||||
callbackForCurrentState(/* justUnlocked = */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModeDeactivated() {
|
||||
mAssistHandleCallbacks = null;
|
||||
if (mContext != null) {
|
||||
mBroadcastDispatcher.get().unregisterReceiver(mDefaultHomeBroadcastReceiver);
|
||||
mBootCompleteCache.get().removeListener(mBootCompleteListener);
|
||||
mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
|
||||
mSettingObserver = null;
|
||||
// putString in order to use overrideableByRestore
|
||||
Settings.Secure.putString(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
|
||||
Long.toString(0L),
|
||||
/* overrideableByRestore = */ true);
|
||||
// putString in order to use overrideableByRestore
|
||||
Settings.Secure.putString(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
|
||||
Integer.toString(0),
|
||||
/* overrideableByRestore = */ true);
|
||||
Settings.Secure.putLong(mContext.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, 0);
|
||||
mContext = null;
|
||||
}
|
||||
mStatusBarStateController.get().removeCallback(mStatusBarStateListener);
|
||||
mTaskStackChangeListeners.get().unregisterTaskStackListener(mTaskStackChangeListener);
|
||||
mOverviewProxyService.get().removeCallback(mOverviewProxyListener);
|
||||
mSysUiFlagContainer.get().removeCallback(mSysUiStateCallback);
|
||||
mWakefulnessLifecycle.get().removeObserver(mWakefulnessLifecycleObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssistantGesturePerformed() {
|
||||
if (mContext == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// putString in order to use overrideableByRestore
|
||||
Settings.Secure.putString(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
|
||||
Integer.toString(++mLearningCount),
|
||||
/* overrideableByRestore = */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssistHandlesRequested() {
|
||||
if (mAssistHandleCallbacks != null
|
||||
&& isFullyAwake()
|
||||
&& !mIsNavBarHidden
|
||||
&& !mOnLockscreen) {
|
||||
mAssistHandleCallbacks.showAndGo();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ComponentName getCurrentDefaultHome() {
|
||||
List<ResolveInfo> homeActivities = new ArrayList<>();
|
||||
ComponentName defaultHome = mPackageManagerWrapper.get().getHomeActivities(homeActivities);
|
||||
if (defaultHome != null) {
|
||||
return defaultHome;
|
||||
}
|
||||
|
||||
int topPriority = Integer.MIN_VALUE;
|
||||
ComponentName topComponent = null;
|
||||
for (ResolveInfo resolveInfo : homeActivities) {
|
||||
if (resolveInfo.priority > topPriority) {
|
||||
topComponent = resolveInfo.activityInfo.getComponentName();
|
||||
topPriority = resolveInfo.priority;
|
||||
} else if (resolveInfo.priority == topPriority) {
|
||||
topComponent = null;
|
||||
}
|
||||
}
|
||||
return topComponent;
|
||||
}
|
||||
|
||||
private void handleStatusBarStateChanged(int newState) {
|
||||
boolean onLockscreen = onLockscreen(newState);
|
||||
if (mOnLockscreen == onLockscreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
resetConsecutiveTaskSwitches();
|
||||
mOnLockscreen = onLockscreen;
|
||||
callbackForCurrentState(!onLockscreen);
|
||||
}
|
||||
|
||||
private void handleDozingChanged(boolean isDozing) {
|
||||
if (mIsDozing == isDozing) {
|
||||
return;
|
||||
}
|
||||
|
||||
resetConsecutiveTaskSwitches();
|
||||
mIsDozing = isDozing;
|
||||
callbackForCurrentState(/* justUnlocked = */ false);
|
||||
}
|
||||
|
||||
private void handleWakefullnessChanged(boolean isAwake) {
|
||||
if (mIsAwake == isAwake) {
|
||||
return;
|
||||
}
|
||||
|
||||
resetConsecutiveTaskSwitches();
|
||||
mIsAwake = isAwake;
|
||||
callbackForCurrentState(/* justUnlocked = */ false);
|
||||
}
|
||||
|
||||
private void handleTaskStackTopChanged(int taskId, @Nullable ComponentName taskComponentName) {
|
||||
if (mRunningTaskId == taskId || taskComponentName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRunningTaskId = taskId;
|
||||
mIsLauncherShowing = taskComponentName.equals(mDefaultHome);
|
||||
if (mIsLauncherShowing) {
|
||||
resetConsecutiveTaskSwitches();
|
||||
} else {
|
||||
rescheduleConsecutiveTaskSwitchesReset();
|
||||
mConsecutiveTaskSwitches++;
|
||||
}
|
||||
callbackForCurrentState(/* justUnlocked = */ false);
|
||||
}
|
||||
|
||||
private void handleSystemUiStateChanged(int sysuiStateFlags) {
|
||||
boolean isNavBarHidden =
|
||||
(sysuiStateFlags & QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
|
||||
if (mIsNavBarHidden == isNavBarHidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
resetConsecutiveTaskSwitches();
|
||||
mIsNavBarHidden = isNavBarHidden;
|
||||
callbackForCurrentState(/* justUnlocked = */ false);
|
||||
}
|
||||
|
||||
private void handleOverviewShown() {
|
||||
resetConsecutiveTaskSwitches();
|
||||
callbackForCurrentState(/* justUnlocked = */ false);
|
||||
}
|
||||
|
||||
private boolean onLockscreen(int statusBarState) {
|
||||
return statusBarState == StatusBarState.KEYGUARD
|
||||
|| statusBarState == StatusBarState.SHADE_LOCKED;
|
||||
}
|
||||
|
||||
private void callbackForCurrentState(boolean justUnlocked) {
|
||||
updateLearningStatus();
|
||||
|
||||
if (mIsLearned) {
|
||||
callbackForLearnedState(justUnlocked);
|
||||
} else {
|
||||
callbackForUnlearnedState();
|
||||
}
|
||||
}
|
||||
|
||||
private void callbackForLearnedState(boolean justUnlocked) {
|
||||
if (mAssistHandleCallbacks == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isFullyAwake() || mIsNavBarHidden || mOnLockscreen || !getShowWhenTaught()) {
|
||||
mAssistHandleCallbacks.hide();
|
||||
} else if (justUnlocked) {
|
||||
long currentEpochDay = LocalDate.now().toEpochDay();
|
||||
if (mLearnedHintLastShownEpochDay < currentEpochDay) {
|
||||
if (mContext != null) {
|
||||
Settings.Secure.putLong(
|
||||
mContext.getContentResolver(),
|
||||
LEARNED_HINT_LAST_SHOWN_KEY,
|
||||
currentEpochDay);
|
||||
}
|
||||
mLearnedHintLastShownEpochDay = currentEpochDay;
|
||||
mAssistHandleCallbacks.showAndGo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void callbackForUnlearnedState() {
|
||||
if (mAssistHandleCallbacks == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isFullyAwake() || mIsNavBarHidden || isSuppressed()) {
|
||||
mAssistHandleCallbacks.hide();
|
||||
} else if (mOnLockscreen) {
|
||||
mAssistHandleCallbacks.showAndStay();
|
||||
} else if (mIsLauncherShowing) {
|
||||
mAssistHandleCallbacks.showAndGo();
|
||||
} else if (mConsecutiveTaskSwitches == 1) {
|
||||
mAssistHandleCallbacks.showAndGoDelayed(
|
||||
getShowAndGoDelayedShortDelayMs(), /* hideIfShowing = */ false);
|
||||
} else {
|
||||
mAssistHandleCallbacks.showAndGoDelayed(
|
||||
getShowAndGoDelayedLongDelayMs(), /* hideIfShowing = */ true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSuppressed() {
|
||||
if (mOnLockscreen) {
|
||||
return getSuppressOnLockscreen();
|
||||
} else if (mIsLauncherShowing) {
|
||||
return getSuppressOnLauncher();
|
||||
} else {
|
||||
return getSuppressOnApps();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLearningStatus() {
|
||||
if (mContext == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long currentTimestamp = mClock.currentTimeMillis();
|
||||
mLearningTimeElapsed += currentTimestamp - mLastLearningTimestamp;
|
||||
mLastLearningTimestamp = currentTimestamp;
|
||||
|
||||
mIsLearned =
|
||||
mLearningCount >= getLearningCount() || mLearningTimeElapsed >= getLearningTimeMs();
|
||||
|
||||
// putString in order to use overrideableByRestore
|
||||
mHandler.post(() -> Settings.Secure.putString(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
|
||||
Long.toString(mLearningTimeElapsed),
|
||||
/* overrideableByRestore = */ true));
|
||||
}
|
||||
|
||||
private void resetConsecutiveTaskSwitches() {
|
||||
mHandler.removeCallbacks(mResetConsecutiveTaskSwitches);
|
||||
mConsecutiveTaskSwitches = 0;
|
||||
}
|
||||
|
||||
private void rescheduleConsecutiveTaskSwitchesReset() {
|
||||
mHandler.removeCallbacks(mResetConsecutiveTaskSwitches);
|
||||
mHandler.postDelayed(mResetConsecutiveTaskSwitches, getShowAndGoDelayResetTimeoutMs());
|
||||
}
|
||||
|
||||
private boolean isFullyAwake() {
|
||||
return mIsAwake && !mIsDozing;
|
||||
}
|
||||
|
||||
private long getLearningTimeMs() {
|
||||
return mDeviceConfigHelper.getLong(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_TIME_MS,
|
||||
DEFAULT_LEARNING_TIME_MS);
|
||||
}
|
||||
|
||||
private int getLearningCount() {
|
||||
return mDeviceConfigHelper.getInt(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_COUNT,
|
||||
DEFAULT_LEARNING_COUNT);
|
||||
}
|
||||
|
||||
private long getShowAndGoDelayedShortDelayMs() {
|
||||
return mDeviceConfigHelper.getLong(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAYED_SHORT_DELAY_MS,
|
||||
DEFAULT_SHOW_AND_GO_DELAYED_SHORT_DELAY_MS);
|
||||
}
|
||||
|
||||
private long getShowAndGoDelayedLongDelayMs() {
|
||||
return mDeviceConfigHelper.getLong(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAYED_LONG_DELAY_MS,
|
||||
DEFAULT_SHOW_AND_GO_DELAYED_LONG_DELAY_MS);
|
||||
}
|
||||
|
||||
private long getShowAndGoDelayResetTimeoutMs() {
|
||||
return mDeviceConfigHelper.getLong(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAY_RESET_TIMEOUT_MS,
|
||||
DEFAULT_SHOW_AND_GO_DELAY_RESET_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
private boolean getSuppressOnLockscreen() {
|
||||
return mDeviceConfigHelper.getBoolean(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_LOCKSCREEN,
|
||||
DEFAULT_SUPPRESS_ON_LOCKSCREEN);
|
||||
}
|
||||
|
||||
private boolean getSuppressOnLauncher() {
|
||||
return mDeviceConfigHelper.getBoolean(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_LAUNCHER,
|
||||
DEFAULT_SUPPRESS_ON_LAUNCHER);
|
||||
}
|
||||
|
||||
private boolean getSuppressOnApps() {
|
||||
return mDeviceConfigHelper.getBoolean(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_APPS,
|
||||
DEFAULT_SUPPRESS_ON_APPS);
|
||||
}
|
||||
|
||||
private boolean getShowWhenTaught() {
|
||||
return mDeviceConfigHelper.getBoolean(
|
||||
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_WHEN_TAUGHT,
|
||||
DEFAULT_SHOW_WHEN_TAUGHT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
pw.println(prefix + "Current AssistHandleReminderExpBehavior State:");
|
||||
pw.println(prefix + " mOnLockscreen=" + mOnLockscreen);
|
||||
pw.println(prefix + " mIsDozing=" + mIsDozing);
|
||||
pw.println(prefix + " mIsAwake=" + mIsAwake);
|
||||
pw.println(prefix + " mRunningTaskId=" + mRunningTaskId);
|
||||
pw.println(prefix + " mDefaultHome=" + mDefaultHome);
|
||||
pw.println(prefix + " mIsNavBarHidden=" + mIsNavBarHidden);
|
||||
pw.println(prefix + " mIsLauncherShowing=" + mIsLauncherShowing);
|
||||
pw.println(prefix + " mConsecutiveTaskSwitches=" + mConsecutiveTaskSwitches);
|
||||
pw.println(prefix + " mIsLearned=" + mIsLearned);
|
||||
pw.println(prefix + " mLastLearningTimestamp=" + mLastLearningTimestamp);
|
||||
pw.println(prefix + " mLearningTimeElapsed=" + mLearningTimeElapsed);
|
||||
pw.println(prefix + " mLearningCount=" + mLearningCount);
|
||||
pw.println(prefix + " mLearnedHintLastShownEpochDay=" + mLearnedHintLastShownEpochDay);
|
||||
pw.println(
|
||||
prefix + " mAssistHandleCallbacks present: " + (mAssistHandleCallbacks != null));
|
||||
|
||||
pw.println(prefix + " Phenotype Flags:");
|
||||
pw.println(prefix + " "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_TIME_MS
|
||||
+ "="
|
||||
+ getLearningTimeMs());
|
||||
pw.println(prefix + " "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_COUNT
|
||||
+ "="
|
||||
+ getLearningCount());
|
||||
pw.println(prefix + " "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAYED_SHORT_DELAY_MS
|
||||
+ "="
|
||||
+ getShowAndGoDelayedShortDelayMs());
|
||||
pw.println(prefix + " "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAYED_LONG_DELAY_MS
|
||||
+ "="
|
||||
+ getShowAndGoDelayedLongDelayMs());
|
||||
pw.println(prefix + " "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAY_RESET_TIMEOUT_MS
|
||||
+ "="
|
||||
+ getShowAndGoDelayResetTimeoutMs());
|
||||
pw.println(prefix + " "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_LOCKSCREEN
|
||||
+ "="
|
||||
+ getSuppressOnLockscreen());
|
||||
pw.println(prefix + " "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_LAUNCHER
|
||||
+ "="
|
||||
+ getSuppressOnLauncher());
|
||||
pw.println(prefix + " "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_APPS
|
||||
+ "="
|
||||
+ getSuppressOnApps());
|
||||
pw.println(prefix + " "
|
||||
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_WHEN_TAUGHT
|
||||
+ "="
|
||||
+ getShowWhenTaught());
|
||||
}
|
||||
|
||||
private final class SettingsObserver extends ContentObserver {
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
SettingsObserver(Context context, Handler handler) {
|
||||
super(handler);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, @Nullable Uri uri) {
|
||||
if (LEARNING_TIME_ELAPSED_URI.equals(uri)) {
|
||||
mLastLearningTimestamp = mClock.currentTimeMillis();
|
||||
mLearningTimeElapsed = Settings.Secure.getLong(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
|
||||
/* default = */ 0);
|
||||
} else if (LEARNING_EVENT_COUNT_URI.equals(uri)) {
|
||||
mLearningCount = Settings.Secure.getInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
|
||||
/* default = */ 0);
|
||||
}
|
||||
|
||||
super.onChange(selfChange, uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* 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.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.PathInterpolator;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.CornerHandleView;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.navigationbar.NavigationBarTransitions;
|
||||
|
||||
/**
|
||||
* A class for managing Assistant handle show, hide and animation.
|
||||
*/
|
||||
public class AssistHandleViewController implements NavigationBarTransitions.DarkIntensityListener {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "AssistHandleViewController";
|
||||
|
||||
private Handler mHandler;
|
||||
private CornerHandleView mAssistHintLeft;
|
||||
private CornerHandleView mAssistHintRight;
|
||||
private int mBottomOffset;
|
||||
|
||||
@VisibleForTesting
|
||||
boolean mAssistHintVisible;
|
||||
@VisibleForTesting
|
||||
boolean mAssistHintBlocked = false;
|
||||
|
||||
public AssistHandleViewController(Handler handler, View navBar) {
|
||||
mHandler = handler;
|
||||
mAssistHintLeft = navBar.findViewById(R.id.assist_hint_left);
|
||||
mAssistHintRight = navBar.findViewById(R.id.assist_hint_right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDarkIntensity(float darkIntensity) {
|
||||
mAssistHintLeft.updateDarkness(darkIntensity);
|
||||
mAssistHintRight.updateDarkness(darkIntensity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bottom offset.
|
||||
*
|
||||
* @param bottomOffset the bottom offset to translate.
|
||||
*/
|
||||
public void setBottomOffset(int bottomOffset) {
|
||||
if (mBottomOffset != bottomOffset) {
|
||||
mBottomOffset = bottomOffset;
|
||||
if (mAssistHintVisible) {
|
||||
// If assist handles are visible, hide them without animation and then make them
|
||||
// show once again (with corrected bottom offset).
|
||||
hideAssistHandles();
|
||||
setAssistHintVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls the visibility of the assist gesture handles.
|
||||
*
|
||||
* @param visible whether the handles should be shown
|
||||
*/
|
||||
public void setAssistHintVisible(boolean visible) {
|
||||
if (!mHandler.getLooper().isCurrentThread()) {
|
||||
mHandler.post(() -> setAssistHintVisible(visible));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAssistHintBlocked && visible) {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "Assist hint blocked, cannot make it visible");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAssistHintVisible != visible) {
|
||||
mAssistHintVisible = visible;
|
||||
fade(mAssistHintLeft, mAssistHintVisible, /* isLeft = */ true);
|
||||
fade(mAssistHintRight, mAssistHintVisible, /* isLeft = */ false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents the assist hint from becoming visible even if `mAssistHintVisible` is true.
|
||||
*/
|
||||
public void setAssistHintBlocked(boolean blocked) {
|
||||
if (!mHandler.getLooper().isCurrentThread()) {
|
||||
mHandler.post(() -> setAssistHintBlocked(blocked));
|
||||
return;
|
||||
}
|
||||
|
||||
mAssistHintBlocked = blocked;
|
||||
if (mAssistHintVisible && mAssistHintBlocked) {
|
||||
hideAssistHandles();
|
||||
}
|
||||
}
|
||||
|
||||
private void hideAssistHandles() {
|
||||
mAssistHintLeft.setVisibility(View.GONE);
|
||||
mAssistHintRight.setVisibility(View.GONE);
|
||||
mAssistHintVisible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an animator that animates the given view from start to end over durationMs. Start and
|
||||
* end represent total animation progress: 0 is the start, 1 is the end, 1.1 would be an
|
||||
* overshoot.
|
||||
*/
|
||||
Animator getHandleAnimator(View view, float start, float end, boolean isLeft, long durationMs,
|
||||
Interpolator interpolator) {
|
||||
// Note that lerp does allow overshoot, in cases where start and end are outside of [0,1].
|
||||
float scaleStart = MathUtils.lerp(2f, 1f, start);
|
||||
float scaleEnd = MathUtils.lerp(2f, 1f, end);
|
||||
Animator scaleX = ObjectAnimator.ofFloat(view, View.SCALE_X, scaleStart, scaleEnd);
|
||||
Animator scaleY = ObjectAnimator.ofFloat(view, View.SCALE_Y, scaleStart, scaleEnd);
|
||||
float translationStart = MathUtils.lerp(0.2f, 0f, start);
|
||||
float translationEnd = MathUtils.lerp(0.2f, 0f, end);
|
||||
int xDirection = isLeft ? -1 : 1;
|
||||
Animator translateX = ObjectAnimator.ofFloat(view, View.TRANSLATION_X,
|
||||
xDirection * translationStart * view.getWidth(),
|
||||
xDirection * translationEnd * view.getWidth());
|
||||
Animator translateY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y,
|
||||
translationStart * view.getHeight() + mBottomOffset,
|
||||
translationEnd * view.getHeight() + mBottomOffset);
|
||||
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
set.play(scaleX).with(scaleY);
|
||||
set.play(scaleX).with(translateX);
|
||||
set.play(scaleX).with(translateY);
|
||||
set.setDuration(durationMs);
|
||||
set.setInterpolator(interpolator);
|
||||
return set;
|
||||
}
|
||||
|
||||
private void fade(View view, boolean fadeIn, boolean isLeft) {
|
||||
if (fadeIn) {
|
||||
view.animate().cancel();
|
||||
view.setAlpha(1f);
|
||||
view.setVisibility(View.VISIBLE);
|
||||
|
||||
// A piecewise spring-like interpolation.
|
||||
// End value in one animator call must match the start value in the next, otherwise
|
||||
// there will be a discontinuity.
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
Animator first = getHandleAnimator(view, 0, 1.1f, isLeft, 750,
|
||||
new PathInterpolator(0, 0.45f, .67f, 1f));
|
||||
Interpolator secondInterpolator = new PathInterpolator(0.33f, 0, 0.67f, 1f);
|
||||
Animator second = getHandleAnimator(view, 1.1f, 0.97f, isLeft, 400,
|
||||
secondInterpolator);
|
||||
Animator third = getHandleAnimator(view, 0.97f, 1.02f, isLeft, 400,
|
||||
secondInterpolator);
|
||||
Animator fourth = getHandleAnimator(view, 1.02f, 1f, isLeft, 400,
|
||||
secondInterpolator);
|
||||
anim.play(first).before(second);
|
||||
anim.play(second).before(third);
|
||||
anim.play(third).before(fourth);
|
||||
anim.start();
|
||||
} else {
|
||||
view.animate().cancel();
|
||||
view.animate()
|
||||
.setInterpolator(new AccelerateInterpolator(1.5f))
|
||||
.setDuration(250)
|
||||
.alpha(0f);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -37,8 +37,7 @@ open class AssistLogger @Inject constructor(
|
||||
protected val context: Context,
|
||||
protected val uiEventLogger: UiEventLogger,
|
||||
private val assistUtils: AssistUtils,
|
||||
private val phoneStateMonitor: PhoneStateMonitor,
|
||||
private val assistHandleBehaviorController: AssistHandleBehaviorController
|
||||
private val phoneStateMonitor: PhoneStateMonitor
|
||||
) {
|
||||
|
||||
private val instanceIdSequence = InstanceIdSequence(INSTANCE_ID_MAX)
|
||||
@@ -82,7 +81,7 @@ open class AssistLogger @Inject constructor(
|
||||
assistComponentFinal.flattenToString(),
|
||||
getOrCreateInstanceId().id,
|
||||
deviceStateFinal,
|
||||
assistHandleBehaviorController.areHandlesShowing())
|
||||
false)
|
||||
reportAssistantInvocationExtraData()
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ public class AssistManager {
|
||||
private static final String INVOCATION_TIME_MS_KEY = "invocation_time_ms";
|
||||
private static final String INVOCATION_PHONE_STATE_KEY = "invocation_phone_state";
|
||||
protected static final String ACTION_KEY = "action";
|
||||
protected static final String SHOW_ASSIST_HANDLES_ACTION = "show_assist_handles";
|
||||
protected static final String SET_ASSIST_GESTURE_CONSTRAINED_ACTION =
|
||||
"set_assist_gesture_constrained";
|
||||
protected static final String CONSTRAINED_KEY = "should_constrain";
|
||||
@@ -119,7 +118,6 @@ public class AssistManager {
|
||||
protected final Context mContext;
|
||||
private final AssistDisclosure mAssistDisclosure;
|
||||
private final PhoneStateMonitor mPhoneStateMonitor;
|
||||
private final AssistHandleBehaviorController mHandleController;
|
||||
private final UiController mUiController;
|
||||
protected final Lazy<SysUiState> mSysUiState;
|
||||
protected final AssistLogger mAssistLogger;
|
||||
@@ -148,7 +146,6 @@ public class AssistManager {
|
||||
DeviceProvisionedController controller,
|
||||
Context context,
|
||||
AssistUtils assistUtils,
|
||||
AssistHandleBehaviorController handleController,
|
||||
CommandQueue commandQueue,
|
||||
PhoneStateMonitor phoneStateMonitor,
|
||||
OverviewProxyService overviewProxyService,
|
||||
@@ -162,7 +159,6 @@ public class AssistManager {
|
||||
mAssistUtils = assistUtils;
|
||||
mAssistDisclosure = new AssistDisclosure(context, new Handler());
|
||||
mPhoneStateMonitor = phoneStateMonitor;
|
||||
mHandleController = handleController;
|
||||
mAssistLogger = assistLogger;
|
||||
|
||||
mOrbController = new AssistOrbController(configurationController, context);
|
||||
@@ -216,9 +212,7 @@ public class AssistManager {
|
||||
}
|
||||
|
||||
String action = hints.getString(ACTION_KEY);
|
||||
if (SHOW_ASSIST_HANDLES_ACTION.equals(action)) {
|
||||
requestAssistHandles();
|
||||
} else if (SET_ASSIST_GESTURE_CONSTRAINED_ACTION.equals(action)) {
|
||||
if (SET_ASSIST_GESTURE_CONSTRAINED_ACTION.equals(action)) {
|
||||
mSysUiState.get()
|
||||
.setFlag(
|
||||
SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
|
||||
@@ -249,9 +243,6 @@ public class AssistManager {
|
||||
args = new Bundle();
|
||||
}
|
||||
int legacyInvocationType = args.getInt(INVOCATION_TYPE_KEY, 0);
|
||||
if (legacyInvocationType == INVOCATION_TYPE_GESTURE) {
|
||||
mHandleController.onAssistantGesturePerformed();
|
||||
}
|
||||
int legacyDeviceState = mPhoneStateMonitor.getPhoneState();
|
||||
args.putInt(INVOCATION_PHONE_STATE_KEY, legacyDeviceState);
|
||||
args.putLong(INVOCATION_TIME_MS_KEY, SystemClock.elapsedRealtime());
|
||||
@@ -278,10 +269,6 @@ public class AssistManager {
|
||||
mUiController.onGestureCompletion(velocity);
|
||||
}
|
||||
|
||||
protected void requestAssistHandles() {
|
||||
mHandleController.onAssistHandlesRequested();
|
||||
}
|
||||
|
||||
public void hideAssist() {
|
||||
mAssistUtils.hideCurrentSession();
|
||||
}
|
||||
@@ -362,10 +349,6 @@ public class AssistManager {
|
||||
return mAssistUtils.isSessionRunning();
|
||||
}
|
||||
|
||||
protected AssistHandleBehaviorController getHandleBehaviorController() {
|
||||
return mHandleController;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ComponentName getAssistInfoForUser(int userId) {
|
||||
return mAssistUtils.getAssistComponentForUser(userId);
|
||||
@@ -389,10 +372,6 @@ public class AssistManager {
|
||||
});
|
||||
}
|
||||
|
||||
public long getAssistHandleShowAndGoRemainingDurationMs() {
|
||||
return mHandleController.getShowAndGoRemainingTimeMs();
|
||||
}
|
||||
|
||||
/** Returns the logging flags for the given Assistant invocation type. */
|
||||
public int toLoggingSubType(int invocationType) {
|
||||
return toLoggingSubType(invocationType, mPhoneStateMonitor.getPhoneState());
|
||||
@@ -409,7 +388,7 @@ public class AssistManager {
|
||||
// Note that this logic will break if the number of Assistant invocation types exceeds 7.
|
||||
// There are currently 5 invocation types, but we will be migrating to the new logging
|
||||
// framework in the next update.
|
||||
int subType = mHandleController.areHandlesShowing() ? 0 : 1;
|
||||
int subType = 0;
|
||||
subType |= invocationType << 1;
|
||||
subType |= phoneState << 4;
|
||||
return subType;
|
||||
|
||||
@@ -21,15 +21,10 @@ import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.slice.Clock;
|
||||
|
||||
import com.android.internal.app.AssistUtils;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.navigationbar.NavigationBarController;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
@@ -53,28 +48,6 @@ public abstract class AssistModule {
|
||||
return backgroundHandlerThread.getThreadHandler();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@SysUISingleton
|
||||
static Map<AssistHandleBehavior, AssistHandleBehaviorController.BehaviorController>
|
||||
provideAssistHandleBehaviorControllerMap(
|
||||
AssistHandleOffBehavior offBehavior,
|
||||
AssistHandleLikeHomeBehavior likeHomeBehavior,
|
||||
AssistHandleReminderExpBehavior reminderExpBehavior) {
|
||||
Map<AssistHandleBehavior, AssistHandleBehaviorController.BehaviorController> map =
|
||||
new EnumMap<>(AssistHandleBehavior.class);
|
||||
map.put(AssistHandleBehavior.OFF, offBehavior);
|
||||
map.put(AssistHandleBehavior.LIKE_HOME, likeHomeBehavior);
|
||||
map.put(AssistHandleBehavior.REMINDER_EXP, reminderExpBehavior);
|
||||
return map;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Nullable
|
||||
static AssistHandleViewController provideAssistHandleViewController(
|
||||
NavigationBarController navigationBarController) {
|
||||
return navigationBarController.getAssistHandlerViewController();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@SysUISingleton
|
||||
static AssistUtils provideAssistUtils(Context context) {
|
||||
|
||||
@@ -37,12 +37,10 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.assist.AssistHandleViewController;
|
||||
import com.android.systemui.assist.AssistLogger;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.assist.AssistantSessionEvent;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.navigationbar.NavigationBarController;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -113,7 +111,6 @@ public class DefaultUiController implements AssistManager.UiController {
|
||||
if (!mInvocationInProgress) {
|
||||
attach();
|
||||
mInvocationInProgress = true;
|
||||
updateAssistHandleVisibility();
|
||||
}
|
||||
setProgressInternal(type, progress);
|
||||
}
|
||||
@@ -136,7 +133,6 @@ public class DefaultUiController implements AssistManager.UiController {
|
||||
}
|
||||
mInvocationLightsView.hide();
|
||||
mInvocationInProgress = false;
|
||||
updateAssistHandleVisibility();
|
||||
}
|
||||
|
||||
protected void logInvocationProgressMetrics(
|
||||
@@ -174,17 +170,6 @@ public class DefaultUiController implements AssistManager.UiController {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAssistHandleVisibility() {
|
||||
NavigationBarController navigationBarController =
|
||||
Dependency.get(NavigationBarController.class);
|
||||
AssistHandleViewController controller =
|
||||
navigationBarController == null
|
||||
? null : navigationBarController.getAssistHandlerViewController();
|
||||
if (controller != null) {
|
||||
controller.setAssistHintBlocked(mInvocationInProgress);
|
||||
}
|
||||
}
|
||||
|
||||
private void attach() {
|
||||
if (!mAttached) {
|
||||
mWindowManager.addView(mRoot, mLayoutParams);
|
||||
|
||||
@@ -116,7 +116,6 @@ import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
|
||||
import com.android.systemui.accessibility.SystemActions;
|
||||
import com.android.systemui.assist.AssistHandleViewController;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
@@ -276,11 +275,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
}
|
||||
}
|
||||
|
||||
/** Only for default display */
|
||||
@Nullable
|
||||
AssistHandleViewController mAssistHandlerViewController;
|
||||
|
||||
|
||||
private final AutoHideUiElement mAutoHideUiElement = new AutoHideUiElement() {
|
||||
@Override
|
||||
public void synchronizeState() {
|
||||
@@ -630,11 +624,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
mDisabledFlags2 |= StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS;
|
||||
}
|
||||
setDisabled2Flags(mDisabledFlags2);
|
||||
if (mIsOnDefaultDisplay) {
|
||||
mAssistHandlerViewController =
|
||||
new AssistHandleViewController(mHandler, mNavigationBarView);
|
||||
getBarTransitions().addDarkIntensityListener(mAssistHandlerViewController);
|
||||
}
|
||||
|
||||
initSecondaryHomeHandleForRotation();
|
||||
|
||||
@@ -664,11 +653,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
if (mNavigationBarView != null) {
|
||||
if (mIsOnDefaultDisplay) {
|
||||
mNavigationBarView.getBarTransitions()
|
||||
.removeDarkIntensityListener(mAssistHandlerViewController);
|
||||
mAssistHandlerViewController = null;
|
||||
}
|
||||
mNavigationBarView.getBarTransitions().destroy();
|
||||
mNavigationBarView.getLightTransitionsController().destroy(mContext);
|
||||
}
|
||||
@@ -1596,11 +1580,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AssistHandleViewController getAssistHandlerViewController() {
|
||||
return mAssistHandlerViewController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs transitions on navigation bar.
|
||||
*
|
||||
|
||||
@@ -45,7 +45,6 @@ import com.android.settingslib.applications.InterestingConfigChanges;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
|
||||
import com.android.systemui.accessibility.SystemActions;
|
||||
import com.android.systemui.assist.AssistHandleViewController;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
@@ -399,13 +398,6 @@ public class NavigationBarController implements Callbacks,
|
||||
return mNavigationBars.get(DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
/** @return {@link AssistHandleViewController} (only on the default display). */
|
||||
@Nullable
|
||||
public AssistHandleViewController getAssistHandlerViewController() {
|
||||
NavigationBar navBar = getDefaultNavigationBar();
|
||||
return navBar == null ? null : navBar.getAssistHandlerViewController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
|
||||
for (int i = 0; i < mNavigationBars.size(); i++) {
|
||||
|
||||
@@ -69,7 +69,6 @@ import com.android.settingslib.Utils;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.Interpolators;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.assist.AssistHandleViewController;
|
||||
import com.android.systemui.model.SysUiState;
|
||||
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
|
||||
import com.android.systemui.navigationbar.buttons.ContextualButton;
|
||||
@@ -1357,14 +1356,6 @@ public class NavigationBarView extends FrameLayout implements
|
||||
setClipChildren(shouldClip);
|
||||
setClipToPadding(shouldClip);
|
||||
|
||||
NavigationBarController navigationBarController =
|
||||
Dependency.get(NavigationBarController.class);
|
||||
AssistHandleViewController controller =
|
||||
navigationBarController == null
|
||||
? null : navigationBarController.getAssistHandlerViewController();
|
||||
if (controller != null) {
|
||||
controller.setBottomOffset(insets.getSystemWindowInsetBottom());
|
||||
}
|
||||
return super.onApplyWindowInsets(insets);
|
||||
}
|
||||
|
||||
|
||||
@@ -196,8 +196,6 @@ public class ButtonDispatcher {
|
||||
if (animate) {
|
||||
setVisibility(View.VISIBLE);
|
||||
mFadeAnimator = ValueAnimator.ofFloat(getAlpha(), alpha);
|
||||
mFadeAnimator.setStartDelay(
|
||||
mAssistManager.getAssistHandleShowAndGoRemainingDurationMs());
|
||||
mFadeAnimator.setDuration(duration);
|
||||
mFadeAnimator.setInterpolator(LINEAR);
|
||||
mFadeAnimator.addListener(mFadeListener);
|
||||
|
||||
@@ -1,392 +0,0 @@
|
||||
/*
|
||||
* 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.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.os.Handler;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.app.AssistUtils;
|
||||
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.navigationbar.NavigationModeController;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper
|
||||
public class AssistHandleBehaviorControllerTest extends SysuiTestCase {
|
||||
|
||||
private static final ComponentName COMPONENT_NAME = new ComponentName("", "");
|
||||
|
||||
private AssistHandleBehaviorController mAssistHandleBehaviorController;
|
||||
|
||||
@Mock private AssistUtils mMockAssistUtils;
|
||||
@Mock private Handler mMockHandler;
|
||||
@Mock private DeviceConfigHelper mMockDeviceConfigHelper;
|
||||
@Mock private AssistHandleOffBehavior mMockOffBehavior;
|
||||
@Mock private AssistHandleLikeHomeBehavior mMockLikeHomeBehavior;
|
||||
@Mock private AssistHandleReminderExpBehavior mMockReminderExpBehavior;
|
||||
@Mock private AssistHandleBehaviorController.BehaviorController mMockTestBehavior;
|
||||
@Mock private NavigationModeController mMockNavigationModeController;
|
||||
@Mock private AssistHandleViewController mMockAssistHandleViewController;
|
||||
@Mock private AccessibilityManager mMockA11yManager;
|
||||
|
||||
@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());
|
||||
doAnswer(invocation -> invocation.getArgument(0)).when(mMockA11yManager)
|
||||
.getRecommendedTimeoutMillis(anyInt(), anyInt());
|
||||
|
||||
Map<AssistHandleBehavior, AssistHandleBehaviorController.BehaviorController> behaviorMap =
|
||||
new EnumMap<>(AssistHandleBehavior.class);
|
||||
behaviorMap.put(AssistHandleBehavior.OFF, mMockOffBehavior);
|
||||
behaviorMap.put(AssistHandleBehavior.LIKE_HOME, mMockLikeHomeBehavior);
|
||||
behaviorMap.put(AssistHandleBehavior.REMINDER_EXP, mMockReminderExpBehavior);
|
||||
behaviorMap.put(AssistHandleBehavior.TEST, mMockTestBehavior);
|
||||
|
||||
mAssistHandleBehaviorController =
|
||||
new AssistHandleBehaviorController(
|
||||
mContext,
|
||||
mMockAssistUtils,
|
||||
mMockHandler,
|
||||
() -> mMockAssistHandleViewController,
|
||||
mMockDeviceConfigHelper,
|
||||
behaviorMap,
|
||||
mMockNavigationModeController,
|
||||
() -> mMockA11yManager,
|
||||
mock(DumpManager.class));
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
mAssistHandleBehaviorController.setBehavior(AssistHandleBehavior.OFF);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hide_hidesHandlesWhenShowing() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.hide();
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleViewController).setAssistHintVisible(false);
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hide_doesNothingWhenHiding() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.hide();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndStay_showsHandlesWhenHiding() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleViewController).setAssistHintVisible(true);
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndStay_doesNothingWhenShowing() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndStay_doesNothingWhenThereIsNoAssistant() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(null);
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGo_showsThenHidesHandlesWhenHiding() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
|
||||
// Assert
|
||||
InOrder inOrder = inOrder(mMockAssistHandleViewController);
|
||||
inOrder.verify(mMockAssistHandleViewController).setAssistHintVisible(true);
|
||||
inOrder.verify(mMockAssistHandleViewController).setAssistHintVisible(false);
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGo_hidesHandlesAfterTimeoutWhenShowing() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleViewController).setAssistHintVisible(false);
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGo_doesNothingIfRecentlyHidden() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
when(mMockDeviceConfigHelper.getLong(
|
||||
eq(SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS),
|
||||
anyLong())).thenReturn(10000L);
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGo_doesNothingWhenThereIsNoAssistant() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(null);
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGo_usesA11yTimeout() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
when(mMockDeviceConfigHelper.getLong(
|
||||
eq(SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DURATION_MS), anyLong()))
|
||||
.thenReturn(12345L);
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockAssistHandleViewController, mMockA11yManager);
|
||||
when(mMockA11yManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn(54321);
|
||||
ArgumentCaptor<Long> delay = ArgumentCaptor.forClass(Long.class);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
|
||||
// Assert
|
||||
verify(mMockA11yManager).getRecommendedTimeoutMillis(
|
||||
eq(12345), eq(AccessibilityManager.FLAG_CONTENT_ICONS));
|
||||
verify(mMockHandler).postDelayed(any(Runnable.class), delay.capture());
|
||||
assert delay.getValue() == 54321L;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGoDelayed_showsThenHidesHandlesWhenHiding() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGoDelayed(1000, false);
|
||||
|
||||
// Assert
|
||||
InOrder inOrder = inOrder(mMockAssistHandleViewController);
|
||||
inOrder.verify(mMockAssistHandleViewController).setAssistHintVisible(true);
|
||||
inOrder.verify(mMockAssistHandleViewController).setAssistHintVisible(false);
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGoDelayed_hidesHandlesAfterTimeoutWhenShowing() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGoDelayed(1000, false);
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleViewController).setAssistHintVisible(false);
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGoDelayed_hidesInitiallyThenShowsThenHidesAfterTimeoutWhenHideRequested() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.showAndStay();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGoDelayed(1000, true);
|
||||
|
||||
// Assert
|
||||
InOrder inOrder = inOrder(mMockAssistHandleViewController);
|
||||
inOrder.verify(mMockAssistHandleViewController).setAssistHintVisible(false);
|
||||
inOrder.verify(mMockAssistHandleViewController).setAssistHintVisible(true);
|
||||
inOrder.verify(mMockAssistHandleViewController).setAssistHintVisible(false);
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGoDelayed_doesNothingIfRecentlyHidden() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
when(mMockDeviceConfigHelper.getLong(
|
||||
eq(SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS),
|
||||
anyLong())).thenReturn(10000L);
|
||||
mAssistHandleBehaviorController.showAndGo();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGoDelayed(1000, false);
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showAndGoDelayed_doesNothingWhenThereIsNoAssistant() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(null);
|
||||
mAssistHandleBehaviorController.hide();
|
||||
reset(mMockAssistHandleViewController);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.showAndGoDelayed(1000, false);
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockAssistHandleViewController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBehavior_activatesTheBehaviorWhenInGesturalMode() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.setInGesturalModeForTest(true);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.setBehavior(AssistHandleBehavior.TEST);
|
||||
|
||||
// Assert
|
||||
verify(mMockTestBehavior).onModeActivated(mContext, mAssistHandleBehaviorController);
|
||||
verifyNoMoreInteractions(mMockTestBehavior);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBehavior_deactivatesThePreviousBehaviorWhenInGesturalMode() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.setBehavior(AssistHandleBehavior.TEST);
|
||||
mAssistHandleBehaviorController.setInGesturalModeForTest(true);
|
||||
reset(mMockTestBehavior);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.setBehavior(AssistHandleBehavior.OFF);
|
||||
|
||||
// Assert
|
||||
verify(mMockTestBehavior).onModeDeactivated();
|
||||
verifyNoMoreInteractions(mMockTestBehavior);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBehavior_doesNothingWhenNotInGesturalMode() {
|
||||
// Arrange
|
||||
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
|
||||
mAssistHandleBehaviorController.setInGesturalModeForTest(false);
|
||||
|
||||
// Act
|
||||
mAssistHandleBehaviorController.setBehavior(AssistHandleBehavior.TEST);
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockTestBehavior);
|
||||
}
|
||||
}
|
||||
@@ -1,364 +0,0 @@
|
||||
/*
|
||||
* 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.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
import com.android.systemui.model.SysUiState;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
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)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase {
|
||||
|
||||
private AssistHandleLikeHomeBehavior mAssistHandleLikeHomeBehavior;
|
||||
|
||||
@Mock private StatusBarStateController mMockStatusBarStateController;
|
||||
@Mock private WakefulnessLifecycle mMockWakefulnessLifecycle;
|
||||
@Mock private SysUiState mMockSysUiState;
|
||||
@Mock private AssistHandleCallbacks mMockAssistHandleCallbacks;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mAssistHandleLikeHomeBehavior = new AssistHandleLikeHomeBehavior(
|
||||
() -> mMockStatusBarStateController,
|
||||
() -> mMockWakefulnessLifecycle,
|
||||
() -> mMockSysUiState);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onModeActivated_beginsObserving() {
|
||||
// Arrange
|
||||
|
||||
// Act
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
|
||||
// Assert
|
||||
verify(mMockStatusBarStateController).isDozing();
|
||||
verify(mMockStatusBarStateController).addCallback(
|
||||
any(StatusBarStateController.StateListener.class));
|
||||
verify(mMockWakefulnessLifecycle).getWakefulness();
|
||||
verify(mMockWakefulnessLifecycle).addObserver(any(WakefulnessLifecycle.Observer.class));
|
||||
verify(mMockSysUiState).addCallback(any(SysUiState.SysUiStateCallback.class));
|
||||
verifyNoMoreInteractions(mMockWakefulnessLifecycle, mMockSysUiState);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onModeActivated_showsHandlesWhenFullyAwake() {
|
||||
// Arrange
|
||||
when(mMockStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mMockWakefulnessLifecycle.getWakefulness())
|
||||
.thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
|
||||
// Act
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).showAndStay();
|
||||
verifyNoMoreInteractions(mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onModeActivated_hidesHandlesWhenNotAwake() {
|
||||
// Arrange
|
||||
when(mMockStatusBarStateController.isDozing()).thenReturn(true);
|
||||
when(mMockWakefulnessLifecycle.getWakefulness())
|
||||
.thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP);
|
||||
|
||||
// Act
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).hide();
|
||||
verifyNoMoreInteractions(mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onModeActivated_hidesHandlesWhenDozing() {
|
||||
// Arrange
|
||||
when(mMockStatusBarStateController.isDozing()).thenReturn(true);
|
||||
when(mMockWakefulnessLifecycle.getWakefulness())
|
||||
.thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
|
||||
// Act
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).hide();
|
||||
verifyNoMoreInteractions(mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onModeDeactivated_stopsObserving() {
|
||||
// Arrange
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
ArgumentCaptor<StatusBarStateController.StateListener> stateListener =
|
||||
ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
|
||||
ArgumentCaptor<WakefulnessLifecycle.Observer> observer =
|
||||
ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
|
||||
ArgumentCaptor<SysUiState.SysUiStateCallback> sysUiStateCallback =
|
||||
ArgumentCaptor.forClass(SysUiState.SysUiStateCallback.class);
|
||||
verify(mMockStatusBarStateController).addCallback(stateListener.capture());
|
||||
verify(mMockWakefulnessLifecycle).addObserver(observer.capture());
|
||||
verify(mMockSysUiState).addCallback(sysUiStateCallback.capture());
|
||||
reset(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
mAssistHandleLikeHomeBehavior.onModeDeactivated();
|
||||
|
||||
// Assert
|
||||
verify(mMockStatusBarStateController).removeCallback(eq(stateListener.getValue()));
|
||||
verify(mMockWakefulnessLifecycle).removeObserver(eq(observer.getValue()));
|
||||
verify(mMockSysUiState).removeCallback(eq(sysUiStateCallback.getValue()));
|
||||
verifyNoMoreInteractions(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAssistantGesturePerformed_doesNothing() {
|
||||
// Arrange
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
reset(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
mAssistHandleLikeHomeBehavior.onAssistantGesturePerformed();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAssistHandlesRequested_doesNothing() {
|
||||
// Arrange
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
reset(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
mAssistHandleLikeHomeBehavior.onAssistHandlesRequested();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBothAwakeAndUnDoze_handlesShow() {
|
||||
// Arrange
|
||||
when(mMockStatusBarStateController.isDozing()).thenReturn(true);
|
||||
when(mMockWakefulnessLifecycle.getWakefulness())
|
||||
.thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP);
|
||||
ArgumentCaptor<StatusBarStateController.StateListener> stateListener =
|
||||
ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
|
||||
ArgumentCaptor<WakefulnessLifecycle.Observer> observer =
|
||||
ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
verify(mMockStatusBarStateController).addCallback(stateListener.capture());
|
||||
verify(mMockWakefulnessLifecycle).addObserver(observer.capture());
|
||||
reset(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
observer.getValue().onFinishedWakingUp();
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).hide();
|
||||
verifyNoMoreInteractions(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
|
||||
// Arrange
|
||||
observer.getValue().onFinishedGoingToSleep();
|
||||
reset(mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
stateListener.getValue().onDozingChanged(false);
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).hide();
|
||||
verifyNoMoreInteractions(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
observer.getValue().onFinishedWakingUp();
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).showAndStay();
|
||||
verifyNoMoreInteractions(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSleepOrDoze_handlesHide() {
|
||||
// Arrange
|
||||
when(mMockStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mMockWakefulnessLifecycle.getWakefulness())
|
||||
.thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
ArgumentCaptor<StatusBarStateController.StateListener> stateListener =
|
||||
ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
|
||||
ArgumentCaptor<WakefulnessLifecycle.Observer> observer =
|
||||
ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
verify(mMockStatusBarStateController).addCallback(stateListener.capture());
|
||||
verify(mMockWakefulnessLifecycle).addObserver(observer.capture());
|
||||
reset(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
observer.getValue().onStartedGoingToSleep();
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).hide();
|
||||
verifyNoMoreInteractions(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
|
||||
// Arrange
|
||||
observer.getValue().onFinishedWakingUp();
|
||||
reset(mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
stateListener.getValue().onDozingChanged(true);
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).hide();
|
||||
verifyNoMoreInteractions(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onHomeHandleHide_handlesHide() {
|
||||
// Arrange
|
||||
when(mMockStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mMockWakefulnessLifecycle.getWakefulness())
|
||||
.thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
ArgumentCaptor<SysUiState.SysUiStateCallback> sysUiStateCallback =
|
||||
ArgumentCaptor.forClass(SysUiState.SysUiStateCallback.class);
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
verify(mMockSysUiState).addCallback(sysUiStateCallback.capture());
|
||||
reset(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
sysUiStateCallback.getValue().onSystemUiStateChanged(
|
||||
QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN);
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).hide();
|
||||
verifyNoMoreInteractions(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onHomeHandleUnhide_handlesShow() {
|
||||
// Arrange
|
||||
when(mMockStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mMockWakefulnessLifecycle.getWakefulness())
|
||||
.thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
ArgumentCaptor<SysUiState.SysUiStateCallback> sysUiStateCallback =
|
||||
ArgumentCaptor.forClass(SysUiState.SysUiStateCallback.class);
|
||||
mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
verify(mMockSysUiState).addCallback(sysUiStateCallback.capture());
|
||||
sysUiStateCallback.getValue().onSystemUiStateChanged(
|
||||
QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN);
|
||||
reset(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
sysUiStateCallback.getValue().onSystemUiStateChanged(
|
||||
~QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN);
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).showAndStay();
|
||||
verifyNoMoreInteractions(
|
||||
mMockStatusBarStateController,
|
||||
mMockWakefulnessLifecycle,
|
||||
mMockSysUiState,
|
||||
mMockAssistHandleCallbacks);
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class AssistHandleOffBehaviorTest extends SysuiTestCase {
|
||||
|
||||
private AssistHandleOffBehavior mAssistHandleOffBehavior;
|
||||
|
||||
@Mock private AssistHandleCallbacks mMockAssistHandleCallbacks;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mAssistHandleOffBehavior = new AssistHandleOffBehavior();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onModeActivated_hidesHandles() {
|
||||
// Arrange
|
||||
|
||||
// Act
|
||||
mAssistHandleOffBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
|
||||
// Assert
|
||||
verify(mMockAssistHandleCallbacks).hide();
|
||||
verifyNoMoreInteractions(mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onModeDeactivated_doesNothing() {
|
||||
// Arrange
|
||||
mAssistHandleOffBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
reset(mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
mAssistHandleOffBehavior.onModeDeactivated();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAssistantGesturePerformed_doesNothing() {
|
||||
// Arrange
|
||||
mAssistHandleOffBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
reset(mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
mAssistHandleOffBehavior.onAssistantGesturePerformed();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockAssistHandleCallbacks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAssistHandlesRequested_doesNothing() {
|
||||
// Arrange
|
||||
mAssistHandleOffBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
|
||||
reset(mMockAssistHandleCallbacks);
|
||||
|
||||
// Act
|
||||
mAssistHandleOffBehavior.onAssistHandlesRequested();
|
||||
|
||||
// Assert
|
||||
verifyNoMoreInteractions(mMockAssistHandleCallbacks);
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* 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 junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
import android.view.View;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.CornerHandleView;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper
|
||||
public class AssistHandleViewControllerTest extends SysuiTestCase {
|
||||
|
||||
private AssistHandleViewController mAssistHandleViewController;
|
||||
|
||||
@Mock private Handler mMockHandler;
|
||||
@Mock private Looper mMockLooper;
|
||||
@Mock private View mMockBarView;
|
||||
@Mock private CornerHandleView mMockAssistHint;
|
||||
@Mock private ViewPropertyAnimator mMockAnimator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mMockBarView.findViewById(anyInt())).thenReturn(mMockAssistHint);
|
||||
when(mMockAssistHint.animate()).thenReturn(mMockAnimator);
|
||||
when(mMockAnimator.setInterpolator(any())).thenReturn(mMockAnimator);
|
||||
when(mMockAnimator.setDuration(anyLong())).thenReturn(mMockAnimator);
|
||||
doNothing().when(mMockAnimator).cancel();
|
||||
when(mMockHandler.getLooper()).thenReturn(mMockLooper);
|
||||
when(mMockLooper.isCurrentThread()).thenReturn(true);
|
||||
|
||||
mAssistHandleViewController = new AssistHandleViewController(mMockHandler, mMockBarView);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetVisibleWithoutBlocked() {
|
||||
// Act
|
||||
mAssistHandleViewController.setAssistHintVisible(true);
|
||||
|
||||
// Assert
|
||||
assertTrue(mAssistHandleViewController.mAssistHintVisible);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetInvisibleWithoutBlocked() {
|
||||
// Arrange
|
||||
mAssistHandleViewController.setAssistHintVisible(true);
|
||||
|
||||
// Act
|
||||
mAssistHandleViewController.setAssistHintVisible(false);
|
||||
|
||||
// Assert
|
||||
assertFalse(mAssistHandleViewController.mAssistHintVisible);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetVisibleWithBlocked() {
|
||||
// Act
|
||||
mAssistHandleViewController.setAssistHintBlocked(true);
|
||||
mAssistHandleViewController.setAssistHintVisible(true);
|
||||
|
||||
// Assert
|
||||
assertFalse(mAssistHandleViewController.mAssistHintVisible);
|
||||
assertTrue(mAssistHandleViewController.mAssistHintBlocked);
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@@ -272,10 +271,4 @@ public class NavigationBarControllerTest extends SysuiTestCase {
|
||||
|
||||
verify(mSecondaryNavBar).disableAnimationsDuringHide(eq(500L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAssistHandlerViewController_noCrash() {
|
||||
reset(mNavigationBarController.mNavigationBars);
|
||||
mNavigationBarController.getAssistHandlerViewController();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user