blob: 04efc2d7558debef27f3b23eab3cd7e2e821d5f6 [file] [log] [blame]
Dave Mankoff1193aa42019-10-28 17:51:26 -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.statusbar.phone;
18
19import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
20import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
21
22import android.annotation.NonNull;
23import android.os.Bundle;
24import android.os.PowerManager;
25import android.os.SystemClock;
26import android.os.SystemProperties;
27import android.util.Log;
28import android.view.MotionEvent;
29import android.view.View;
30
31import com.android.internal.annotations.VisibleForTesting;
32import com.android.keyguard.KeyguardUpdateMonitor;
33import com.android.systemui.assist.AssistManager;
34import com.android.systemui.doze.DozeEvent;
35import com.android.systemui.doze.DozeHost;
36import com.android.systemui.doze.DozeLog;
37import com.android.systemui.doze.DozeReceiver;
38import com.android.systemui.keyguard.KeyguardViewMediator;
39import com.android.systemui.keyguard.WakefulnessLifecycle;
40import com.android.systemui.statusbar.PulseExpansionHandler;
41import com.android.systemui.statusbar.StatusBarState;
42import com.android.systemui.statusbar.SysuiStatusBarStateController;
43import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
44import com.android.systemui.statusbar.notification.VisualStabilityManager;
45import com.android.systemui.statusbar.notification.collection.NotificationEntry;
46import com.android.systemui.statusbar.policy.BatteryController;
47import com.android.systemui.statusbar.policy.DeviceProvisionedController;
48
49import java.util.ArrayList;
50
51import javax.inject.Inject;
52import javax.inject.Singleton;
53
54import dagger.Lazy;
55
56/**
57 * Implementation of DozeHost for SystemUI.
58 */
59@Singleton
60public final class DozeServiceHost implements DozeHost {
61 private static final String TAG = "DozeServiceHost";
62 private final ArrayList<Callback> mCallbacks = new ArrayList<>();
63 private final DozeLog mDozeLog;
64 private final PowerManager mPowerManager;
65 private boolean mAnimateWakeup;
66 private boolean mAnimateScreenOff;
67 private boolean mIgnoreTouchWhilePulsing;
68 private Runnable mPendingScreenOffCallback;
69 @VisibleForTesting
70 boolean mWakeLockScreenPerformsAuth = SystemProperties.getBoolean(
71 "persist.sysui.wake_performs_auth", true);
72 private boolean mDozingRequested;
Dave Mankoff1193aa42019-10-28 17:51:26 -040073 private boolean mPulsing;
74 private WakefulnessLifecycle mWakefulnessLifecycle;
75 private final SysuiStatusBarStateController mStatusBarStateController;
76 private final DeviceProvisionedController mDeviceProvisionedController;
77 private final HeadsUpManagerPhone mHeadsUpManagerPhone;
78 private final BatteryController mBatteryController;
79 private final ScrimController mScrimController;
80 private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
81 private BiometricUnlockController mBiometricUnlockController;
82 private final KeyguardViewMediator mKeyguardViewMediator;
Dave Mankoff4dd47fa2019-11-07 10:44:48 -050083 private final Lazy<AssistManager> mAssistManagerLazy;
Dave Mankoff1193aa42019-10-28 17:51:26 -040084 private final DozeScrimController mDozeScrimController;
85 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
86 private final VisualStabilityManager mVisualStabilityManager;
87 private final PulseExpansionHandler mPulseExpansionHandler;
wilsonshihe8321942019-10-18 18:39:46 +080088 private final NotificationShadeWindowController mNotificationShadeWindowController;
Dave Mankoff1193aa42019-10-28 17:51:26 -040089 private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
wilsonshihe8321942019-10-18 18:39:46 +080090 private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
Heemin Seog82b96cd2019-11-12 16:40:00 -080091 private final LockscreenLockIconController mLockscreenLockIconController;
Dave Mankoff1193aa42019-10-28 17:51:26 -040092 private NotificationIconAreaController mNotificationIconAreaController;
Dave Mankoff1193aa42019-10-28 17:51:26 -040093 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Dave Mankoffaf8163f2020-01-08 14:24:35 -050094 private NotificationPanelViewController mNotificationPanel;
Dave Mankoff1193aa42019-10-28 17:51:26 -040095 private View mAmbientIndicationContainer;
96 private StatusBar mStatusBar;
97
98 @Inject
99 public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager,
100 WakefulnessLifecycle wakefulnessLifecycle,
101 SysuiStatusBarStateController statusBarStateController,
102 DeviceProvisionedController deviceProvisionedController,
103 HeadsUpManagerPhone headsUpManagerPhone, BatteryController batteryController,
104 ScrimController scrimController,
105 Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
106 KeyguardViewMediator keyguardViewMediator,
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500107 Lazy<AssistManager> assistManagerLazy,
Dave Mankoff1193aa42019-10-28 17:51:26 -0400108 DozeScrimController dozeScrimController, KeyguardUpdateMonitor keyguardUpdateMonitor,
109 VisualStabilityManager visualStabilityManager,
110 PulseExpansionHandler pulseExpansionHandler,
wilsonshihe8321942019-10-18 18:39:46 +0800111 NotificationShadeWindowController notificationShadeWindowController,
Heemin Seog82b96cd2019-11-12 16:40:00 -0800112 NotificationWakeUpCoordinator notificationWakeUpCoordinator,
Heemin Seog82b96cd2019-11-12 16:40:00 -0800113 LockscreenLockIconController lockscreenLockIconController) {
Dave Mankoff1193aa42019-10-28 17:51:26 -0400114 super();
115 mDozeLog = dozeLog;
116 mPowerManager = powerManager;
117 mWakefulnessLifecycle = wakefulnessLifecycle;
118 mStatusBarStateController = statusBarStateController;
119 mDeviceProvisionedController = deviceProvisionedController;
120 mHeadsUpManagerPhone = headsUpManagerPhone;
121 mBatteryController = batteryController;
122 mScrimController = scrimController;
123 mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
124 mKeyguardViewMediator = keyguardViewMediator;
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500125 mAssistManagerLazy = assistManagerLazy;
Dave Mankoff1193aa42019-10-28 17:51:26 -0400126 mDozeScrimController = dozeScrimController;
127 mKeyguardUpdateMonitor = keyguardUpdateMonitor;
128 mVisualStabilityManager = visualStabilityManager;
129 mPulseExpansionHandler = pulseExpansionHandler;
wilsonshihe8321942019-10-18 18:39:46 +0800130 mNotificationShadeWindowController = notificationShadeWindowController;
Dave Mankoff1193aa42019-10-28 17:51:26 -0400131 mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
Heemin Seog82b96cd2019-11-12 16:40:00 -0800132 mLockscreenLockIconController = lockscreenLockIconController;
Dave Mankoff1193aa42019-10-28 17:51:26 -0400133 }
134
135 // TODO: we should try to not pass status bar in here if we can avoid it.
136
137 /**
138 * Initialize instance with objects only available later during execution.
139 */
140 public void initialize(StatusBar statusBar,
141 NotificationIconAreaController notificationIconAreaController,
Dave Mankoff1193aa42019-10-28 17:51:26 -0400142 StatusBarKeyguardViewManager statusBarKeyguardViewManager,
wilsonshihe8321942019-10-18 18:39:46 +0800143 NotificationShadeWindowViewController notificationShadeWindowViewController,
Dave Mankoffaf8163f2020-01-08 14:24:35 -0500144 NotificationPanelViewController notificationPanel, View ambientIndicationContainer) {
Dave Mankoff1193aa42019-10-28 17:51:26 -0400145 mStatusBar = statusBar;
146 mNotificationIconAreaController = notificationIconAreaController;
Dave Mankoff1193aa42019-10-28 17:51:26 -0400147 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
148 mNotificationPanel = notificationPanel;
wilsonshihe8321942019-10-18 18:39:46 +0800149 mNotificationShadeWindowViewController = notificationShadeWindowViewController;
Dave Mankoff1193aa42019-10-28 17:51:26 -0400150 mAmbientIndicationContainer = ambientIndicationContainer;
151 mBiometricUnlockController = mBiometricUnlockControllerLazy.get();
152 }
153
154 @Override
155 public String toString() {
156 return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
157 }
158
159 void firePowerSaveChanged(boolean active) {
160 for (Callback callback : mCallbacks) {
161 callback.onPowerSaveChanged(active);
162 }
163 }
164
165 void fireNotificationPulse(NotificationEntry entry) {
166 Runnable pulseSuppressedListener = () -> {
167 entry.setPulseSuppressed(true);
168 mNotificationIconAreaController.updateAodNotificationIcons();
169 };
170 for (Callback callback : mCallbacks) {
171 callback.onNotificationAlerted(pulseSuppressedListener);
172 }
173 }
174
175 boolean getDozingRequested() {
176 return mDozingRequested;
177 }
178
179 boolean isPulsing() {
180 return mPulsing;
181 }
182
183
184 @Override
185 public void addCallback(@NonNull Callback callback) {
186 mCallbacks.add(callback);
187 }
188
189 @Override
190 public void removeCallback(@NonNull Callback callback) {
191 mCallbacks.remove(callback);
192 }
193
194 @Override
195 public void startDozing() {
196 if (!mDozingRequested) {
197 mDozingRequested = true;
Dave Mankoff1193aa42019-10-28 17:51:26 -0400198 updateDozing();
Lucas Dupinbcc606e2020-01-06 09:27:48 -0800199 mDozeLog.traceDozing(mStatusBarStateController.isDozing());
Dave Mankoff1193aa42019-10-28 17:51:26 -0400200 mStatusBar.updateIsKeyguard();
201 }
202 }
203
204 void updateDozing() {
205 // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
206 boolean
207 dozing =
208 mDozingRequested && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
209 || mBiometricUnlockController.getMode()
210 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
211 // When in wake-and-unlock we may not have received a change to StatusBarState
212 // but we still should not be dozing, manually set to false.
213 if (mBiometricUnlockController.getMode()
214 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
215 dozing = false;
216 }
217
218
219 mStatusBarStateController.setIsDozing(dozing);
220 }
221
222 @Override
223 public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
224 if (reason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS) {
225 mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
226 "com.android.systemui:LONG_PRESS");
Dave Mankoff4dd47fa2019-11-07 10:44:48 -0500227 mAssistManagerLazy.get().startAssist(new Bundle());
Dave Mankoff1193aa42019-10-28 17:51:26 -0400228 return;
229 }
230
231 if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
232 mScrimController.setWakeLockScreenSensorActive(true);
233 }
234
Dave Mankoff1193aa42019-10-28 17:51:26 -0400235 boolean passiveAuthInterrupt = reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
236 && mWakeLockScreenPerformsAuth;
237 // Set the state to pulsing, so ScrimController will know what to do once we ask it to
238 // execute the transition. The pulse callback will then be invoked when the scrims
239 // are black, indicating that StatusBar is ready to present the rest of the UI.
240 mPulsing = true;
241 mDozeScrimController.pulse(new PulseCallback() {
242 @Override
243 public void onPulseStarted() {
244 callback.onPulseStarted();
245 mStatusBar.updateNotificationPanelTouchState();
246 setPulsing(true);
247 }
248
249 @Override
250 public void onPulseFinished() {
251 mPulsing = false;
252 callback.onPulseFinished();
253 mStatusBar.updateNotificationPanelTouchState();
254 mScrimController.setWakeLockScreenSensorActive(false);
Dave Mankoff1193aa42019-10-28 17:51:26 -0400255 setPulsing(false);
256 }
257
258 private void setPulsing(boolean pulsing) {
259 mStatusBarStateController.setPulsing(pulsing);
260 mStatusBarKeyguardViewManager.setPulsing(pulsing);
261 mKeyguardViewMediator.setPulsing(pulsing);
262 mNotificationPanel.setPulsing(pulsing);
263 mVisualStabilityManager.setPulsing(pulsing);
Heemin Seog82b96cd2019-11-12 16:40:00 -0800264 mLockscreenLockIconController.setPulsing(pulsing);
Dave Mankoff1193aa42019-10-28 17:51:26 -0400265 mIgnoreTouchWhilePulsing = false;
266 if (mKeyguardUpdateMonitor != null && passiveAuthInterrupt) {
267 mKeyguardUpdateMonitor.onAuthInterruptDetected(pulsing /* active */);
268 }
269 mStatusBar.updateScrimController();
270 mPulseExpansionHandler.setPulsing(pulsing);
271 mNotificationWakeUpCoordinator.setPulsing(pulsing);
272 }
273 }, reason);
274 // DozeScrimController is in pulse state, now let's ask ScrimController to start
275 // pulsing and draw the black frame, if necessary.
276 mStatusBar.updateScrimController();
277 }
278
279 @Override
280 public void stopDozing() {
281 if (mDozingRequested) {
282 mDozingRequested = false;
Dave Mankoff1193aa42019-10-28 17:51:26 -0400283 updateDozing();
Lucas Dupinbcc606e2020-01-06 09:27:48 -0800284 mDozeLog.traceDozing(mStatusBarStateController.isDozing());
Dave Mankoff1193aa42019-10-28 17:51:26 -0400285 }
286 }
287
288 @Override
289 public void onIgnoreTouchWhilePulsing(boolean ignore) {
290 if (ignore != mIgnoreTouchWhilePulsing) {
291 mDozeLog.tracePulseTouchDisabledByProx(ignore);
292 }
293 mIgnoreTouchWhilePulsing = ignore;
Lucas Dupinbcc606e2020-01-06 09:27:48 -0800294 if (mStatusBarStateController.isDozing() && ignore) {
wilsonshihe8321942019-10-18 18:39:46 +0800295 mNotificationShadeWindowViewController.cancelCurrentTouch();
Dave Mankoff1193aa42019-10-28 17:51:26 -0400296 }
297 }
298
299 @Override
300 public void dozeTimeTick() {
301 mNotificationPanel.dozeTimeTick();
302 if (mAmbientIndicationContainer instanceof DozeReceiver) {
303 ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
304 }
305 }
306
307 @Override
308 public boolean isPowerSaveActive() {
309 return mBatteryController.isAodPowerSave();
310 }
311
312 @Override
313 public boolean isPulsingBlocked() {
314 return mBiometricUnlockController.getMode()
315 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
316 }
317
318 @Override
319 public boolean isProvisioned() {
320 return mDeviceProvisionedController.isDeviceProvisioned()
321 && mDeviceProvisionedController.isCurrentUserSetup();
322 }
323
324 @Override
325 public boolean isBlockingDoze() {
326 if (mBiometricUnlockController.hasPendingAuthentication()) {
327 Log.i(StatusBar.TAG, "Blocking AOD because fingerprint has authenticated");
328 return true;
329 }
330 return false;
331 }
332
333 @Override
334 public void extendPulse(int reason) {
335 if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
336 mScrimController.setWakeLockScreenSensorActive(true);
337 }
338 if (mDozeScrimController.isPulsing() && mHeadsUpManagerPhone.hasNotifications()) {
339 mHeadsUpManagerPhone.extendHeadsUp();
340 } else {
341 mDozeScrimController.extendPulse();
342 }
343 }
344
345 @Override
346 public void stopPulsing() {
347 if (mDozeScrimController.isPulsing()) {
348 mDozeScrimController.pulseOutNow();
349 }
350 }
351
352 @Override
353 public void setAnimateWakeup(boolean animateWakeup) {
354 if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
355 || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) {
356 // Too late to change the wakeup animation.
357 return;
358 }
359 mAnimateWakeup = animateWakeup;
360 }
361
362 @Override
363 public void setAnimateScreenOff(boolean animateScreenOff) {
364 mAnimateScreenOff = animateScreenOff;
365 }
366
367 @Override
368 public void onSlpiTap(float screenX, float screenY) {
369 if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
370 && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
371 int[] locationOnScreen = new int[2];
372 mAmbientIndicationContainer.getLocationOnScreen(locationOnScreen);
373 float viewX = screenX - locationOnScreen[0];
374 float viewY = screenY - locationOnScreen[1];
375 if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
376 && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
377
378 // Dispatch a tap
379 long now = SystemClock.elapsedRealtime();
380 MotionEvent ev = MotionEvent.obtain(
381 now, now, MotionEvent.ACTION_DOWN, screenX, screenY, 0);
382 mAmbientIndicationContainer.dispatchTouchEvent(ev);
383 ev.recycle();
384 ev = MotionEvent.obtain(
385 now, now, MotionEvent.ACTION_UP, screenX, screenY, 0);
386 mAmbientIndicationContainer.dispatchTouchEvent(ev);
387 ev.recycle();
388 }
389 }
390 }
391
392 @Override
393 public void setDozeScreenBrightness(int value) {
wilsonshihe8321942019-10-18 18:39:46 +0800394 mNotificationShadeWindowController.setDozeScreenBrightness(value);
Dave Mankoff1193aa42019-10-28 17:51:26 -0400395 }
396
397 @Override
398 public void setAodDimmingScrim(float scrimOpacity) {
399 mScrimController.setAodFrontScrimAlpha(scrimOpacity);
400 }
401
402
403
404 @Override
405 public void prepareForGentleSleep(Runnable onDisplayOffCallback) {
406 if (mPendingScreenOffCallback != null) {
407 Log.w(TAG, "Overlapping onDisplayOffCallback. Ignoring previous one.");
408 }
409 mPendingScreenOffCallback = onDisplayOffCallback;
410 mStatusBar.updateScrimController();
411 }
412
413 @Override
414 public void cancelGentleSleep() {
415 mPendingScreenOffCallback = null;
416 if (mScrimController.getState() == ScrimState.OFF) {
417 mStatusBar.updateScrimController();
418 }
419 }
420
421 /**
422 * When the dozing host is waiting for scrims to fade out to change the display state.
423 */
424 boolean hasPendingScreenOffCallback() {
425 return mPendingScreenOffCallback != null;
426 }
427
428 /**
429 * Executes an nullifies the pending display state callback.
430 *
431 * @see #hasPendingScreenOffCallback()
432 * @see #prepareForGentleSleep(Runnable)
433 */
434 void executePendingScreenOffCallback() {
435 if (mPendingScreenOffCallback == null) {
436 return;
437 }
438 mPendingScreenOffCallback.run();
439 mPendingScreenOffCallback = null;
440 }
441
442 boolean shouldAnimateWakeup() {
443 return mAnimateWakeup;
444 }
445
446 boolean shouldAnimateScreenOff() {
447 return mAnimateScreenOff;
448 }
449
Dave Mankoff1193aa42019-10-28 17:51:26 -0400450 boolean getIgnoreTouchWhilePulsing() {
451 return mIgnoreTouchWhilePulsing;
452 }
453}