blob: 4b6a6dcee91d15337d0e736221086e64d014cb37 [file] [log] [blame]
Govinda Wassermanc7495cd2019-05-20 14:43:28 -04001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.assist;
18
Govinda Wasserman2c113402019-05-24 14:11:24 -040019import android.app.ActivityManager;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040020import android.content.ComponentName;
21import android.content.Context;
Govinda Wasserman1f606b02019-05-29 09:16:02 -040022import android.os.SystemClock;
23import android.provider.DeviceConfig;
24import android.provider.Settings;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040025
26import androidx.annotation.Nullable;
27
Govinda Wasserman1f606b02019-05-29 09:16:02 -040028import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040029import com.android.systemui.Dependency;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040030import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
31import com.android.systemui.plugins.statusbar.StatusBarStateController;
32import com.android.systemui.recents.OverviewProxyService;
33import com.android.systemui.shared.system.ActivityManagerWrapper;
Govinda Wasserman2c113402019-05-24 14:11:24 -040034import com.android.systemui.shared.system.QuickStepContract;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040035import com.android.systemui.shared.system.TaskStackChangeListener;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040036import com.android.systemui.statusbar.StatusBarState;
37
Govinda Wasserman1f606b02019-05-29 09:16:02 -040038import java.util.concurrent.TimeUnit;
39
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040040/**
41 * Assistant handle behavior that hides the handles when the phone is dozing or in immersive mode,
42 * shows the handles when on lockscreen, and shows the handles temporarily when changing tasks or
43 * entering overview.
44 */
45final class AssistHandleReminderExpBehavior implements BehaviorController {
46
Govinda Wasserman1f606b02019-05-29 09:16:02 -040047 private static final String LEARNING_TIME_ELAPSED_KEY = "reminder_exp_learning_time_elapsed";
48 private static final String LEARNING_EVENT_COUNT_KEY = "reminder_exp_learning_event_count";
49 private static final long DEFAULT_LEARNING_TIME_MS = TimeUnit.DAYS.toMillis(3);
50 private static final int DEFAULT_LEARNING_COUNT = 3;
51
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040052 private final StatusBarStateController.StateListener mStatusBarStateListener =
53 new StatusBarStateController.StateListener() {
54 @Override
55 public void onStateChanged(int newState) {
56 handleStatusBarStateChanged(newState);
57 }
58
59 @Override
60 public void onDozingChanged(boolean isDozing) {
61 handleDozingChanged(isDozing);
62 }
63 };
64 private final TaskStackChangeListener mTaskStackChangeListener =
65 new TaskStackChangeListener() {
66 @Override
67 public void onTaskMovedToFront(int taskId) {
68 handleTaskStackTopChanged(taskId);
69 }
70
71 @Override
72 public void onTaskCreated(int taskId, ComponentName componentName) {
73 handleTaskStackTopChanged(taskId);
74 }
75 };
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040076 private final OverviewProxyService.OverviewProxyListener mOverviewProxyListener =
77 new OverviewProxyService.OverviewProxyListener() {
78 @Override
79 public void onOverviewShown(boolean fromHome) {
80 handleOverviewShown();
81 }
Govinda Wasserman2c113402019-05-24 14:11:24 -040082
83 @Override
84 public void onSystemUiStateChanged(int sysuiStateFlags) {
85 handleSystemUiStateChanged(sysuiStateFlags);
86 }
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040087 };
88
Govinda Wasserman2c113402019-05-24 14:11:24 -040089 private final StatusBarStateController mStatusBarStateController;
90 private final ActivityManagerWrapper mActivityManagerWrapper;
91 private final OverviewProxyService mOverviewProxyService;
92
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040093 private boolean mOnLockscreen;
94 private boolean mIsDozing;
95 private int mRunningTaskId;
Govinda Wasserman2c113402019-05-24 14:11:24 -040096 private boolean mIsNavBarHidden;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -040097
Govinda Wasserman1f606b02019-05-29 09:16:02 -040098 /** Whether user has learned the gesture. */
99 private boolean mIsLearned;
100 private long mLastLearningTimestamp;
101 /** Uptime while in this behavior. */
102 private long mLearningTimeElapsed;
103 /** Number of successful Assistant invocations while in this behavior. */
104 private int mLearningCount;
105
106 @Nullable private Context mContext;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400107 @Nullable private AssistHandleCallbacks mAssistHandleCallbacks;
108
Govinda Wasserman2c113402019-05-24 14:11:24 -0400109 AssistHandleReminderExpBehavior() {
110 mStatusBarStateController = Dependency.get(StatusBarStateController.class);
111 mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
112 mOverviewProxyService = Dependency.get(OverviewProxyService.class);
113 }
114
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400115 @Override
116 public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400117 mContext = context;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400118 mAssistHandleCallbacks = callbacks;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400119 mOnLockscreen = onLockscreen(mStatusBarStateController.getState());
120 mIsDozing = mStatusBarStateController.isDozing();
121 mStatusBarStateController.addCallback(mStatusBarStateListener);
Govinda Wasserman2c113402019-05-24 14:11:24 -0400122 ActivityManager.RunningTaskInfo runningTaskInfo = mActivityManagerWrapper.getRunningTask();
123 mRunningTaskId = runningTaskInfo == null ? 0 : runningTaskInfo.taskId;
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400124 mActivityManagerWrapper.registerTaskStackListener(mTaskStackChangeListener);
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400125 mOverviewProxyService.addCallback(mOverviewProxyListener);
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400126
127 mLearningTimeElapsed = Settings.Secure.getLong(
128 context.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, /* default = */ 0);
129 mLearningCount = Settings.Secure.getInt(
130 context.getContentResolver(), LEARNING_EVENT_COUNT_KEY, /* default = */ 0);
131 mLastLearningTimestamp = SystemClock.uptimeMillis();
132
133 callbackForCurrentState(/* justUnlocked = */ false);
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400134 }
135
136 @Override
137 public void onModeDeactivated() {
138 mAssistHandleCallbacks = null;
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400139 if (mContext != null) {
140 Settings.Secure.putLong(
141 mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, mLearningTimeElapsed);
142 Settings.Secure.putInt(
143 mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, mLearningCount);
144 mContext = null;
145 }
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400146 mStatusBarStateController.removeCallback(mStatusBarStateListener);
147 mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackChangeListener);
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400148 mOverviewProxyService.removeCallback(mOverviewProxyListener);
149 }
150
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400151 @Override
152 public void onAssistantGesturePerformed() {
153 if (mContext == null) {
154 return;
155 }
156
157 Settings.Secure.putLong(
158 mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, ++mLearningCount);
159 }
160
Govinda Wasserman2c113402019-05-24 14:11:24 -0400161 private static boolean isNavBarHidden(int sysuiStateFlags) {
162 return (sysuiStateFlags & QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
163 }
164
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400165 private void handleStatusBarStateChanged(int newState) {
166 boolean onLockscreen = onLockscreen(newState);
167 if (mOnLockscreen == onLockscreen) {
168 return;
169 }
170
171 mOnLockscreen = onLockscreen;
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400172 callbackForCurrentState(!onLockscreen);
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400173 }
174
175 private void handleDozingChanged(boolean isDozing) {
176 if (mIsDozing == isDozing) {
177 return;
178 }
179
180 mIsDozing = isDozing;
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400181 callbackForCurrentState(/* justUnlocked = */ false);
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400182 }
183
184 private void handleTaskStackTopChanged(int taskId) {
185 if (mRunningTaskId == taskId) {
186 return;
187 }
188
189 mRunningTaskId = taskId;
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400190 callbackForCurrentState(/* justUnlocked = */ false);
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400191 }
192
Govinda Wasserman2c113402019-05-24 14:11:24 -0400193 private void handleSystemUiStateChanged(int sysuiStateFlags) {
194 boolean isNavBarHidden = isNavBarHidden(sysuiStateFlags);
195 if (mIsNavBarHidden == isNavBarHidden) {
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400196 return;
197 }
198
Govinda Wasserman2c113402019-05-24 14:11:24 -0400199 mIsNavBarHidden = isNavBarHidden;
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400200 callbackForCurrentState(/* justUnlocked = */ false);
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400201 }
202
203 private void handleOverviewShown() {
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400204 callbackForCurrentState(/* justUnlocked = */ false);
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400205 }
206
207 private boolean onLockscreen(int statusBarState) {
208 return statusBarState == StatusBarState.KEYGUARD
209 || statusBarState == StatusBarState.SHADE_LOCKED;
210 }
211
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400212 private void callbackForCurrentState(boolean justUnlocked) {
213 updateLearningStatus();
214
215 if (mIsLearned) {
216 callbackForLearnedState(justUnlocked);
217 } else {
218 callbackForUnlearnedState();
219 }
220 }
221
222 private void callbackForLearnedState(boolean justUnlocked) {
223 if (mAssistHandleCallbacks == null) {
224 return;
225 }
226
227 if (mIsDozing || mIsNavBarHidden || mOnLockscreen) {
228 mAssistHandleCallbacks.hide();
229 } else if (justUnlocked) {
230 mAssistHandleCallbacks.showAndGo();
231 }
232 }
233
234 private void callbackForUnlearnedState() {
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400235 if (mAssistHandleCallbacks == null) {
236 return;
237 }
238
Govinda Wasserman2c113402019-05-24 14:11:24 -0400239 if (mIsDozing || mIsNavBarHidden) {
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400240 mAssistHandleCallbacks.hide();
241 } else if (mOnLockscreen) {
242 mAssistHandleCallbacks.showAndStay();
243 } else {
244 mAssistHandleCallbacks.showAndGo();
245 }
246 }
Govinda Wasserman1f606b02019-05-29 09:16:02 -0400247
248 private void updateLearningStatus() {
249 if (mContext == null) {
250 return;
251 }
252
253 long currentTimestamp = SystemClock.uptimeMillis();
254 mLearningTimeElapsed += currentTimestamp - mLastLearningTimestamp;
255 mLastLearningTimestamp = currentTimestamp;
256 Settings.Secure.putLong(
257 mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, mLearningTimeElapsed);
258
259 mIsLearned =
260 mLearningCount >= getLearningCount() || mLearningTimeElapsed >= getLearningTimeMs();
261 }
262
263 private long getLearningTimeMs() {
264 return DeviceConfig.getLong(
265 DeviceConfig.NAMESPACE_SYSTEMUI,
266 SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_TIME_MS,
267 DEFAULT_LEARNING_TIME_MS);
268 }
269
270 private int getLearningCount() {
271 return DeviceConfig.getInt(
272 DeviceConfig.NAMESPACE_SYSTEMUI,
273 SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_COUNT,
274 DEFAULT_LEARNING_COUNT);
275 }
Govinda Wassermanc7495cd2019-05-20 14:43:28 -0400276}