blob: 7e86651ffef65066e0b661ffabd4fa7d48f2def1 [file] [log] [blame]
Jorim Jaggi5cf17872014-03-26 18:31:48 +01001/*
2 * Copyright (C) 2014 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
Jason Monk297c04e2018-08-23 17:16:59 -040019import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
Selim Cinek06c12d62019-07-01 19:44:18 -070020import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020021import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
22import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
Jorim Jaggif5304ad2017-07-17 18:31:13 +020023
Jorim Jaggi786afcb2014-09-25 02:41:29 +020024import android.content.ComponentCallbacks2;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010025import android.content.Context;
Jason Chang1e4a4bd2018-05-22 17:30:19 +080026import android.content.res.ColorStateList;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010027import android.os.Bundle;
Jorim Jaggie29b2db2014-05-30 23:17:03 +020028import android.os.SystemClock;
Tej Singhdd7bd352018-02-09 19:33:15 -080029import android.util.StatsLog;
Jorim Jaggidf993512014-05-13 23:06:35 +020030import android.view.KeyEvent;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010031import android.view.View;
32import android.view.ViewGroup;
Jorim Jaggib774e552015-08-24 14:52:45 -070033import android.view.ViewRootImpl;
Jorim Jaggi786afcb2014-09-25 02:41:29 +020034import android.view.WindowManagerGlobal;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010035
Lucas Dupinbc9aac12018-03-04 20:18:15 -080036import com.android.internal.util.LatencyTracker;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010037import com.android.internal.widget.LockPatternUtils;
Adrian Roosb6011622014-05-14 15:52:53 +020038import com.android.keyguard.KeyguardUpdateMonitor;
Jorim Jaggia9d7fcd2017-05-18 01:08:12 +020039import com.android.keyguard.KeyguardUpdateMonitorCallback;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010040import com.android.keyguard.ViewMediatorCallback;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070041import com.android.settingslib.animation.AppearAnimationUtils;
Jorim Jaggi8adb30c2016-09-13 15:02:22 -070042import com.android.systemui.DejankUtils;
Jason Monk421a9412017-02-06 09:15:21 -080043import com.android.systemui.Dependency;
Xiyuan Xia1b30f792016-01-06 08:50:30 -080044import com.android.systemui.SystemUIFactory;
Lucas Dupinafffbf92019-04-09 19:52:26 -070045import com.android.systemui.dock.DockManager;
Jorim Jaggi241ae102016-11-02 21:57:33 -070046import com.android.systemui.keyguard.DismissCallbackRegistry;
Beverly8fdb5332019-02-04 14:29:49 -050047import com.android.systemui.plugins.statusbar.StatusBarStateController;
Lucas Dupinafffbf92019-04-09 19:52:26 -070048import com.android.systemui.shared.system.QuickStepContract;
Jim Miller25d7e512015-03-03 17:12:09 -080049import com.android.systemui.statusbar.CommandQueue;
Lucas Dupin269feda2019-04-29 17:11:02 -070050import com.android.systemui.statusbar.CrossFadeHelper;
Jason Monk297c04e2018-08-23 17:16:59 -040051import com.android.systemui.statusbar.NotificationMediaManager;
Adrian Roosd28ccd72016-01-06 15:23:14 +010052import com.android.systemui.statusbar.RemoteInputController;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070053import com.android.systemui.statusbar.StatusBarState;
Beverly8fdb5332019-02-04 14:29:49 -050054import com.android.systemui.statusbar.SysuiStatusBarStateController;
Selim Cinek06c12d62019-07-01 19:44:18 -070055import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
Lucas Dupin15a6b6c2018-04-16 14:50:20 +080056import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
Lucas Dupinafffbf92019-04-09 19:52:26 -070057import com.android.systemui.statusbar.policy.ConfigurationController;
Jason Monk1fd3fc32018-08-14 17:20:09 -040058import com.android.systemui.statusbar.policy.KeyguardMonitor;
Evan Laird2d620fa2018-10-30 13:03:31 -040059import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010060
Lucas Dupin15a6b6c2018-04-16 14:50:20 +080061import java.io.PrintWriter;
Jorim Jaggibcbe9482016-11-23 17:37:49 +010062import java.util.ArrayList;
63
Jorim Jaggi5cf17872014-03-26 18:31:48 +010064/**
65 * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
66 * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
67 * which is in turn, reported to this class by the current
68 * {@link com.android.keyguard.KeyguardViewBase}.
69 */
Evan Laird878c8532018-10-15 15:54:29 -040070public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
Lucas Dupin2e838ac2019-04-17 16:50:58 -070071 StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
Selim Cineka678b0e2019-07-23 13:12:55 -070072 PanelExpansionListener, NavigationModeController.ModeChangedListener {
Jorim Jaggi76a16232014-08-08 17:00:47 +020073
74 // When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
Jorim Jaggi56fd70c2016-10-27 19:57:08 -070075 private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
Jorim Jaggi76a16232014-08-08 17:00:47 +020076
Jorim Jaggi416493b2014-09-13 03:57:32 +020077 // Delay for showing the navigation bar when the bouncer appears. This should be kept in sync
78 // with the appear animations of the PIN/pattern/password views.
79 private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320;
80
Jorim Jaggi007f0e82015-08-14 13:56:01 -070081 private static final long WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS = 200;
82
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070083 // Duration of the Keyguard dismissal animation in case the user is currently locked. This is to
84 // make everything a bit slower to bridge a gap until the user is unlocked and home screen has
85 // dranw its first frame.
86 private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
87
Jorim Jaggi5cf17872014-03-26 18:31:48 +010088 private static String TAG = "StatusBarKeyguardViewManager";
89
Xiyuan Xia1b30f792016-01-06 08:50:30 -080090 protected final Context mContext;
Lucas Dupin1a8588d2018-08-21 12:18:47 -070091 private final StatusBarWindowController mStatusBarWindowController;
Lucas Dupin15a6b6c2018-04-16 14:50:20 +080092 private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() {
93 @Override
94 public void onFullyShown() {
95 updateStates();
Lucas Dupin3cfd6882019-03-19 15:22:03 -070096 mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), mContainer, "BOUNCER_VISIBLE");
Lucas Dupin2e838ac2019-04-17 16:50:58 -070097 updateLockIcon();
Lucas Dupin15a6b6c2018-04-16 14:50:20 +080098 }
99
100 @Override
Lucas Dupin84993542018-10-11 19:23:45 -0700101 public void onStartingToHide() {
102 updateStates();
103 }
104
105 @Override
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700106 public void onStartingToShow() {
107 updateLockIcon();
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800108 }
Lucas Dupin27321c42019-03-20 16:22:24 -0700109
110 @Override
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700111 public void onFullyHidden() {
112 updateStates();
113 updateLockIcon();
Lucas Dupin27321c42019-03-20 16:22:24 -0700114 }
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800115 };
Lucas Dupinafffbf92019-04-09 19:52:26 -0700116 private final DockManager.DockEventListener mDockEventListener =
117 new DockManager.DockEventListener() {
118 @Override
119 public void onEvent(int event) {
120 boolean isDocked = mDockManager.isDocked();
121 if (isDocked == mIsDocked) {
122 return;
123 }
124 mIsDocked = isDocked;
125 updateStates();
126 }
127 };
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100128
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800129 protected LockPatternUtils mLockPatternUtils;
130 protected ViewMediatorCallback mViewMediatorCallback;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500131 protected StatusBar mStatusBar;
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800132 private NotificationPanelView mNotificationPanelView;
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200133 private BiometricUnlockController mBiometricUnlockController;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100134
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100135 private ViewGroup mContainer;
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700136 private ViewGroup mLockIconContainer;
Selim Cinek06c12d62019-07-01 19:44:18 -0700137 private View mNotificationContainer;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100138
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800139 protected KeyguardBouncer mBouncer;
140 protected boolean mShowing;
141 protected boolean mOccluded;
142 protected boolean mRemoteInputActive;
Adrian Roos087826a2017-04-19 16:59:09 -0700143 private boolean mDozing;
Lucas Dupinafffbf92019-04-09 19:52:26 -0700144 private boolean mPulsing;
145 private boolean mGesturalNav;
146 private boolean mIsDocked;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100147
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800148 protected boolean mFirstUpdate = true;
149 protected boolean mLastShowing;
150 protected boolean mLastOccluded;
Adrian Roosb6011622014-05-14 15:52:53 +0200151 private boolean mLastBouncerShowing;
152 private boolean mLastBouncerDismissible;
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800153 protected boolean mLastRemoteInputActive;
Adrian Roos087826a2017-04-19 16:59:09 -0700154 private boolean mLastDozing;
Lucas Dupinafffbf92019-04-09 19:52:26 -0700155 private boolean mLastGesturalNav;
156 private boolean mLastIsDocked;
157 private boolean mLastPulsing;
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200158 private int mLastBiometricMode;
Lucas Dupin16cfe452018-02-08 13:14:50 -0800159 private boolean mGoingToSleepVisibleNotOccluded;
Lucas Dupin269feda2019-04-29 17:11:02 -0700160 private boolean mLastLockVisible;
Adrian Roosd28ccd72016-01-06 15:23:14 +0100161
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200162 private OnDismissAction mAfterKeyguardGoneAction;
Jorim Jaggibcbe9482016-11-23 17:37:49 +0100163 private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>();
Adrian Roosb6011622014-05-14 15:52:53 +0200164
Adrian Roosfee661c2017-08-04 17:05:45 +0200165 // Dismiss action to be launched when we stop dozing or the keyguard is gone.
Adrian Roos34e65402017-08-07 19:32:45 +0200166 private DismissWithActionRequest mPendingWakeupAction;
Evan Laird2d620fa2018-10-30 13:03:31 -0400167 private final KeyguardMonitorImpl mKeyguardMonitor =
168 (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
Jason Monk297c04e2018-08-23 17:16:59 -0400169 private final NotificationMediaManager mMediaManager =
170 Dependency.get(NotificationMediaManager.class);
Selim Cinek06c12d62019-07-01 19:44:18 -0700171 private final SysuiStatusBarStateController mStatusBarStateController =
172 (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
Lucas Dupinafffbf92019-04-09 19:52:26 -0700173 private final DockManager mDockManager;
Selim Cinek06c12d62019-07-01 19:44:18 -0700174 private KeyguardBypassController mBypassController;
Adrian Roosfee661c2017-08-04 17:05:45 +0200175
Jorim Jaggia9d7fcd2017-05-18 01:08:12 +0200176 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
177 new KeyguardUpdateMonitorCallback() {
178 @Override
179 public void onEmergencyCallAction() {
180
181 // Since we won't get a setOccluded call we have to reset the view manually such that
182 // the bouncer goes away.
183 if (mOccluded) {
Lucas Dupin28f90292017-08-08 18:07:49 -0400184 reset(true /* hideBouncerWhenShowing */);
Jorim Jaggia9d7fcd2017-05-18 01:08:12 +0200185 }
186 }
187 };
188
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100189 public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback,
190 LockPatternUtils lockPatternUtils) {
191 mContext = context;
192 mViewMediatorCallback = callback;
193 mLockPatternUtils = lockPatternUtils;
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700194 mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
Jorim Jaggia9d7fcd2017-05-18 01:08:12 +0200195 KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback);
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700196 mStatusBarStateController.addCallback(this);
Lucas Dupinafffbf92019-04-09 19:52:26 -0700197 Dependency.get(ConfigurationController.class).addCallback(this);
Lucas Dupinbe050b22019-05-02 16:38:33 -0700198 mGesturalNav = QuickStepContract.isGesturalMode(
Winson Chung1aa24b92019-04-24 15:17:33 -0700199 Dependency.get(NavigationModeController.class).addListener(this));
Lucas Dupind93e95f2019-05-01 00:49:35 +0000200 mDockManager = Dependency.get(DockManager.class);
Lucas Dupinafffbf92019-04-09 19:52:26 -0700201 if (mDockManager != null) {
202 mDockManager.addListener(mDockEventListener);
203 mIsDocked = mDockManager.isDocked();
204 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100205 }
206
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500207 public void registerStatusBar(StatusBar statusBar,
Jason Monk421a9412017-02-06 09:15:21 -0800208 ViewGroup container,
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800209 NotificationPanelView notificationPanelView,
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200210 BiometricUnlockController biometricUnlockController,
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700211 DismissCallbackRegistry dismissCallbackRegistry,
Selim Cinek06c12d62019-07-01 19:44:18 -0700212 ViewGroup lockIconContainer, View notificationContainer,
213 KeyguardBypassController bypassController) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500214 mStatusBar = statusBar;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100215 mContainer = container;
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700216 mLockIconContainer = lockIconContainer;
Lucas Dupin269feda2019-04-29 17:11:02 -0700217 if (mLockIconContainer != null) {
218 mLastLockVisible = mLockIconContainer.getVisibility() == View.VISIBLE;
219 }
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200220 mBiometricUnlockController = biometricUnlockController;
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800221 mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800222 mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
Lucas Dupin04ec6df2019-08-15 11:41:52 -0700223 mExpansionCallback, bypassController);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800224 mNotificationPanelView = notificationPanelView;
Selim Cineka678b0e2019-07-23 13:12:55 -0700225 notificationPanelView.addExpansionListener(this);
Selim Cinek06c12d62019-07-01 19:44:18 -0700226 mBypassController = bypassController;
227 mNotificationContainer = notificationContainer;
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800228 }
229
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700230 @Override
231 public void onPanelExpansionChanged(float expansion, boolean tracking) {
Lucas Dupin6f0d71f2018-03-23 17:26:06 -0700232 // We don't want to translate the bounce when:
233 // • Keyguard is occluded, because we're in a FLAG_SHOW_WHEN_LOCKED activity and need to
234 // conserve the original animation.
235 // • The user quickly taps on the display and we show "swipe up to unlock."
236 // • Keyguard will be dismissed by an action. a.k.a: FLAG_DISMISS_KEYGUARD_ACTIVITY
jovanak5f6dc612018-03-27 11:59:22 -0700237 // • Full-screen user switcher is displayed.
Lucas Dupind7344dc2018-04-20 12:08:52 +0800238 if (mNotificationPanelView.isUnlockHintRunning()) {
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700239 mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
Lucas Dupinc516bac2018-06-19 10:50:04 -0700240 } else if (bouncerNeedsScrimming()) {
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700241 mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
Lucas Dupin1c327432019-01-03 13:37:53 -0800242 } else if (mShowing) {
Lucas Dupinaaac2cb2018-06-08 14:11:41 -0700243 if (!isWakeAndUnlocking() && !mStatusBar.isInLaunchTransition()) {
Lucas Dupin71dd4842018-05-29 15:41:03 -0700244 mBouncer.setExpansion(expansion);
245 }
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700246 if (expansion != KeyguardBouncer.EXPANSION_HIDDEN && tracking
247 && mStatusBar.isKeyguardCurrentlySecure()
Lucas Dupin52a95872018-04-20 10:28:07 +0800248 && !mBouncer.isShowing() && !mBouncer.isAnimatingAway()) {
Lucas Dupin71dd4842018-05-29 15:41:03 -0700249 mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
Lucas Dupin3d565fa2018-03-20 15:40:14 -0700250 }
Lucas Dupinf6a1f172019-04-18 20:57:40 -0700251 } else if (mPulsing && expansion == KeyguardBouncer.EXPANSION_VISIBLE) {
252 // Panel expanded while pulsing but didn't translate the bouncer (because we are
253 // unlocked.) Let's simply wake-up to dismiss the lock screen.
254 mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), mContainer, "BOUNCER_VISIBLE");
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800255 }
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700256 }
257
258 @Override
259 public void onQsExpansionChanged(float expansion) {
260 updateLockIcon();
261 }
262
263 private void updateLockIcon() {
Brad Stenning691c2742019-04-19 11:48:00 -0700264 // Not all form factors have a lock icon
265 if (mLockIconContainer == null) {
266 return;
267 }
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700268 boolean keyguardWithoutQs = mStatusBarStateController.getState() == StatusBarState.KEYGUARD
269 && !mNotificationPanelView.isQsExpanded();
Lucas Dupin269feda2019-04-29 17:11:02 -0700270 boolean lockVisible = (mBouncer.isShowing() || keyguardWithoutQs)
Selim Cinek84b2acc2019-07-07 00:40:38 -0700271 && !mBouncer.isAnimatingAway() && !mKeyguardMonitor.isKeyguardFadingAway();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700272
Lucas Dupin269feda2019-04-29 17:11:02 -0700273 if (mLastLockVisible != lockVisible) {
274 mLastLockVisible = lockVisible;
275 if (lockVisible) {
276 CrossFadeHelper.fadeIn(mLockIconContainer,
277 AppearAnimationUtils.DEFAULT_APPEAR_DURATION /* duration */,
278 0 /* delay */);
279 } else {
Selim Cinek84b2acc2019-07-07 00:40:38 -0700280 final long duration;
281 if (needsBypassFading()) {
282 duration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION;
283 } else {
284 duration = AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2;
285 }
Lucas Dupin269feda2019-04-29 17:11:02 -0700286 CrossFadeHelper.fadeOut(mLockIconContainer,
Selim Cinek84b2acc2019-07-07 00:40:38 -0700287 duration /* duration */,
Lucas Dupin269feda2019-04-29 17:11:02 -0700288 0 /* delay */, null /* runnable */);
289 }
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700290 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100291 }
292
293 /**
294 * Show the keyguard. Will handle creating and attaching to the view manager
295 * lazily.
296 */
297 public void show(Bundle options) {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200298 mShowing = true;
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700299 mStatusBarWindowController.setKeyguardShowing(true);
Evan Laird2d620fa2018-10-30 13:03:31 -0400300 mKeyguardMonitor.notifyKeyguardState(
301 mShowing, mKeyguardMonitor.isSecure(), mKeyguardMonitor.isOccluded());
Jorim Jaggife762342016-10-13 14:33:27 +0200302 reset(true /* hideBouncerWhenShowing */);
Tej Singhdd7bd352018-02-09 19:33:15 -0800303 StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
304 StatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100305 }
306
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200307 /**
308 * Shows the notification keyguard or the bouncer depending on
309 * {@link KeyguardBouncer#needsFullscreenBouncer()}.
310 */
Jorim Jaggife762342016-10-13 14:33:27 +0200311 protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
Adrian Roos41eecff2017-06-29 14:09:52 +0200312 if (mBouncer.needsFullscreenBouncer() && !mDozing) {
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200313 // The keyguard might be showing (already). So we need to hide it.
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500314 mStatusBar.hideKeyguard();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100315 mBouncer.show(true /* resetSecuritySelection */);
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200316 } else {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500317 mStatusBar.showKeyguard();
Jorim Jaggife762342016-10-13 14:33:27 +0200318 if (hideBouncerWhenShowing) {
Jian Jind1b63982018-05-21 15:20:40 -0700319 hideBouncer(shouldDestroyViewOnReset() /* destroyView */);
Jorim Jaggife762342016-10-13 14:33:27 +0200320 mBouncer.prepare();
321 }
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200322 }
Adrian Roos61676aa2017-08-03 16:24:32 +0200323 updateStates();
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200324 }
325
Jian Jind1b63982018-05-21 15:20:40 -0700326 protected boolean shouldDestroyViewOnReset() {
327 return false;
328 }
329
Lucas Dupin3c9df5a2018-02-27 11:32:16 -0800330 private void hideBouncer(boolean destroyView) {
Lucas Dupinafffbf92019-04-09 19:52:26 -0700331 if (mBouncer == null) {
332 return;
333 }
Adrian Roosfee661c2017-08-04 17:05:45 +0200334 mBouncer.hide(destroyView);
Adrian Roos34e65402017-08-07 19:32:45 +0200335 cancelPendingWakeupAction();
Adrian Roosfee661c2017-08-04 17:05:45 +0200336 }
337
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700338 public void showBouncer(boolean scrimmed) {
339 if (mShowing && !mBouncer.isShowing()) {
340 mBouncer.show(false /* resetSecuritySelection */, scrimmed);
Dan Sandler3806c772014-05-08 14:52:10 -0400341 }
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200342 updateStates();
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100343 }
344
Jorim Jaggid9449862015-05-29 14:49:08 -0700345 public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
346 boolean afterKeyguardGone) {
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800347 dismissWithAction(r, cancelAction, afterKeyguardGone, null /* message */);
348 }
349
350 public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
351 boolean afterKeyguardGone, String message) {
Adrian Roos0002a452014-07-03 13:46:07 +0200352 if (mShowing) {
Adrian Roos34e65402017-08-07 19:32:45 +0200353 cancelPendingWakeupAction();
Adrian Roosfee661c2017-08-04 17:05:45 +0200354 // If we're dozing, this needs to be delayed until after we wake up - unless we're
355 // wake-and-unlocking, because there dozing will last until the end of the transition.
356 if (mDozing && !isWakeAndUnlocking()) {
Adrian Roos34e65402017-08-07 19:32:45 +0200357 mPendingWakeupAction = new DismissWithActionRequest(
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800358 r, cancelAction, afterKeyguardGone, message);
Adrian Roosfee661c2017-08-04 17:05:45 +0200359 return;
360 }
361
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200362 if (!afterKeyguardGone) {
Jorim Jaggid9449862015-05-29 14:49:08 -0700363 mBouncer.showWithDismissAction(r, cancelAction);
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200364 } else {
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200365 mAfterKeyguardGoneAction = r;
Jorim Jaggi8d5a6e72016-11-02 21:57:33 -0700366 mBouncer.show(false /* resetSecuritySelection */);
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200367 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200368 }
369 updateStates();
370 }
371
Adrian Roosfee661c2017-08-04 17:05:45 +0200372 private boolean isWakeAndUnlocking() {
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200373 int mode = mBiometricUnlockController.getMode();
Adrian Roosfee661c2017-08-04 17:05:45 +0200374 return mode == MODE_WAKE_AND_UNLOCK || mode == MODE_WAKE_AND_UNLOCK_PULSING;
375 }
376
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100377 /**
Jorim Jaggibcbe9482016-11-23 17:37:49 +0100378 * Adds a {@param runnable} to be executed after Keyguard is gone.
379 */
380 public void addAfterKeyguardGoneRunnable(Runnable runnable) {
381 mAfterKeyguardGoneRunnables.add(runnable);
382 }
383
384 /**
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100385 * Reset the state of the view.
386 */
Jorim Jaggife762342016-10-13 14:33:27 +0200387 public void reset(boolean hideBouncerWhenShowing) {
Jorim Jaggi43bdbbd2014-05-09 16:05:53 +0200388 if (mShowing) {
Adrian Roos7a56d1a2017-08-04 15:04:43 +0200389 if (mOccluded && !mDozing) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500390 mStatusBar.hideKeyguard();
Adrian Roos91ffdc42017-08-04 18:14:41 +0200391 if (hideBouncerWhenShowing || mBouncer.needsFullscreenBouncer()) {
392 hideBouncer(false /* destroyView */);
393 }
Jorim Jaggi43bdbbd2014-05-09 16:05:53 +0200394 } else {
Jorim Jaggife762342016-10-13 14:33:27 +0200395 showBouncerOrKeyguard(hideBouncerWhenShowing);
Jorim Jaggi43bdbbd2014-05-09 16:05:53 +0200396 }
Selim Cinek1fcafc42015-07-20 14:39:25 -0700397 KeyguardUpdateMonitor.getInstance(mContext).sendKeyguardReset();
Jorim Jaggi43bdbbd2014-05-09 16:05:53 +0200398 updateStates();
Dan Sandler3806c772014-05-08 14:52:10 -0400399 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100400 }
401
Lucas Dupin16cfe452018-02-08 13:14:50 -0800402 public boolean isGoingToSleepVisibleNotOccluded() {
403 return mGoingToSleepVisibleNotOccluded;
404 }
405
Jorim Jaggi18f18ae2015-09-10 15:48:21 -0700406 public void onStartedGoingToSleep() {
Lucas Dupin16cfe452018-02-08 13:14:50 -0800407 mGoingToSleepVisibleNotOccluded = isShowing() && !isOccluded();
Jorim Jaggi18f18ae2015-09-10 15:48:21 -0700408 }
409
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700410 public void onFinishedGoingToSleep() {
Lucas Dupin16cfe452018-02-08 13:14:50 -0800411 mGoingToSleepVisibleNotOccluded = false;
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200412 mBouncer.onScreenTurnedOff();
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100413 }
414
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700415 public void onStartedWakingUp() {
Adrian Roos731d4df2017-07-18 15:10:39 +0200416 // TODO: remove
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100417 }
418
Jorim Jaggi93739112015-08-13 15:53:14 -0700419 public void onScreenTurningOn() {
Adrian Roos731d4df2017-07-18 15:10:39 +0200420 // TODO: remove
Selim Cinek372d1bd2015-08-14 13:19:37 -0700421 }
422
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700423 public void onScreenTurnedOn() {
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800424 // TODO: remove
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700425 }
426
Adrian Roosd28ccd72016-01-06 15:23:14 +0100427 @Override
428 public void onRemoteInputActive(boolean active) {
429 mRemoteInputActive = active;
430 updateStates();
431 }
432
Evan Laird878c8532018-10-15 15:54:29 -0400433 private void setDozing(boolean dozing) {
Adrian Roos41eecff2017-06-29 14:09:52 +0200434 if (mDozing != dozing) {
435 mDozing = dozing;
Adrian Roos61676aa2017-08-03 16:24:32 +0200436 if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) {
437 reset(dozing /* hideBouncerWhenShowing */);
438 }
Adrian Roos41eecff2017-06-29 14:09:52 +0200439 updateStates();
Adrian Roosfee661c2017-08-04 17:05:45 +0200440
441 if (!dozing) {
Adrian Roos34e65402017-08-07 19:32:45 +0200442 launchPendingWakeupAction();
Adrian Roosfee661c2017-08-04 17:05:45 +0200443 }
Adrian Roos41eecff2017-06-29 14:09:52 +0200444 }
Adrian Roos087826a2017-04-19 16:59:09 -0700445 }
446
Lucas Dupinafffbf92019-04-09 19:52:26 -0700447 /**
448 * If {@link StatusBar} is pulsing.
449 */
450 public void setPulsing(boolean pulsing) {
451 if (mPulsing != pulsing) {
452 mPulsing = pulsing;
453 updateStates();
454 }
455 }
456
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100457 public void setNeedsInput(boolean needsInput) {
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700458 mStatusBarWindowController.setKeyguardNeedsInput(needsInput);
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100459 }
460
Adrian Roosd5c2db62016-03-08 16:11:31 -0800461 public boolean isUnlockWithWallpaper() {
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700462 return mStatusBarWindowController.isShowingWallpaper();
Adrian Roosd5c2db62016-03-08 16:11:31 -0800463 }
464
Jorim Jaggi6626f542016-08-22 13:08:44 -0700465 public void setOccluded(boolean occluded, boolean animate) {
Selim Cinek3a49ba22017-08-10 11:17:39 -0700466 mStatusBar.setOccluded(occluded);
Selim Cinekbaa23272014-07-08 18:01:07 +0200467 if (occluded && !mOccluded && mShowing) {
Tej Singhdd7bd352018-02-09 19:33:15 -0800468 StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
469 StatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED);
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500470 if (mStatusBar.isInLaunchTransition()) {
Selim Cinekbaa23272014-07-08 18:01:07 +0200471 mOccluded = true;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500472 mStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */,
Selim Cinekbaa23272014-07-08 18:01:07 +0200473 new Runnable() {
474 @Override
475 public void run() {
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700476 mStatusBarWindowController.setKeyguardOccluded(mOccluded);
Jorim Jaggife762342016-10-13 14:33:27 +0200477 reset(true /* hideBouncerWhenShowing */);
Selim Cinekbaa23272014-07-08 18:01:07 +0200478 }
479 });
480 return;
481 }
Tej Singhdd7bd352018-02-09 19:33:15 -0800482 } else if (!occluded && mOccluded && mShowing) {
483 StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
484 StatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
Selim Cinekbaa23272014-07-08 18:01:07 +0200485 }
Lucas Dupin28f90292017-08-08 18:07:49 -0400486 boolean isOccluding = !mOccluded && occluded;
Jorim Jaggia6310292014-04-16 14:11:52 +0200487 mOccluded = occluded;
Adrian Roos909fe2d2016-10-12 12:03:24 -0700488 if (mShowing) {
Jason Monk297c04e2018-08-23 17:16:59 -0400489 mMediaManager.updateMediaMetaData(false, animate && !occluded);
Adrian Roos909fe2d2016-10-12 12:03:24 -0700490 }
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700491 mStatusBarWindowController.setKeyguardOccluded(occluded);
Jorim Jaggife762342016-10-13 14:33:27 +0200492
Adrian Roos7a56d1a2017-08-04 15:04:43 +0200493 // setDozing(false) will call reset once we stop dozing.
494 if (!mDozing) {
495 // If Keyguard is reshown, don't hide the bouncer as it might just have been requested
496 // by a FLAG_DISMISS_KEYGUARD_ACTIVITY.
Lucas Dupin28f90292017-08-08 18:07:49 -0400497 reset(isOccluding /* hideBouncerWhenShowing*/);
Adrian Roos7a56d1a2017-08-04 15:04:43 +0200498 }
Lucas Dupine9e70712019-05-01 14:41:49 -0700499 if (animate && !occluded && mShowing && !mBouncer.isShowing()) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500500 mStatusBar.animateKeyguardUnoccluding();
Jorim Jaggi6626f542016-08-22 13:08:44 -0700501 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100502 }
503
Dan Sandler4b22bdf2014-06-05 00:58:02 -0400504 public boolean isOccluded() {
505 return mOccluded;
506 }
507
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100508 /**
Jorim Jaggi76a16232014-08-08 17:00:47 +0200509 * Starts the animation before we dismiss Keyguard, i.e. an disappearing animation on the
510 * security view of the bouncer.
511 *
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200512 * @param finishRunnable the runnable to be run after the animation finished, or {@code null} if
513 * no action should be run
Jorim Jaggi76a16232014-08-08 17:00:47 +0200514 */
515 public void startPreHideAnimation(Runnable finishRunnable) {
516 if (mBouncer.isShowing()) {
517 mBouncer.startPreHideAnimation(finishRunnable);
Lucas Dupin93752552018-03-19 21:32:19 -0700518 mNotificationPanelView.onBouncerPreHideAnimation();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200519 } else if (finishRunnable != null) {
Jorim Jaggi76a16232014-08-08 17:00:47 +0200520 finishRunnable.run();
521 }
Lucas Dupind61974d2019-03-29 16:09:26 -0700522 mNotificationPanelView.blockExpansionForCurrentTouch();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700523 updateLockIcon();
Jorim Jaggi76a16232014-08-08 17:00:47 +0200524 }
525
526 /**
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100527 * Hides the keyguard view
528 */
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700529 public void hide(long startTime, long fadeoutDuration) {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200530 mShowing = false;
Evan Laird2d620fa2018-10-30 13:03:31 -0400531 mKeyguardMonitor.notifyKeyguardState(
532 mShowing, mKeyguardMonitor.isSecure(), mKeyguardMonitor.isOccluded());
Adrian Roos34e65402017-08-07 19:32:45 +0200533 launchPendingWakeupAction();
Jorim Jaggi44cf9192014-06-17 19:16:00 -0700534
Jorim Jaggi031f7952016-09-01 16:39:26 -0700535 if (KeyguardUpdateMonitor.getInstance(mContext).needsSlowUnlockTransition()) {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700536 fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED;
537 }
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200538 long uptimeMillis = SystemClock.uptimeMillis();
Jorim Jaggi76a16232014-08-08 17:00:47 +0200539 long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis);
Selim Cinekbaa23272014-07-08 18:01:07 +0200540
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500541 if (mStatusBar.isInLaunchTransition() ) {
542 mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() {
Selim Cinekbaa23272014-07-08 18:01:07 +0200543 @Override
544 public void run() {
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700545 mStatusBarWindowController.setKeyguardShowing(false);
546 mStatusBarWindowController.setKeyguardFadingAway(true);
Adrian Roosfee661c2017-08-04 17:05:45 +0200547 hideBouncer(true /* destroyView */);
Selim Cinekbaa23272014-07-08 18:01:07 +0200548 updateStates();
Selim Cinekbaa23272014-07-08 18:01:07 +0200549 }
550 }, new Runnable() {
551 @Override
552 public void run() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500553 mStatusBar.hideKeyguard();
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700554 mStatusBarWindowController.setKeyguardFadingAway(false);
Selim Cinekbaa23272014-07-08 18:01:07 +0200555 mViewMediatorCallback.keyguardGone();
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200556 executeAfterKeyguardGoneAction();
Selim Cinekbaa23272014-07-08 18:01:07 +0200557 }
558 });
559 } else {
Jorim Jaggi8d5a6e72016-11-02 21:57:33 -0700560 executeAfterKeyguardGoneAction();
Jorim Jaggie93698b2016-11-11 18:24:38 -0800561 boolean wakeUnlockPulsing =
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200562 mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
Selim Cinekc075f152019-07-24 15:32:17 -0700563 boolean needsFading = needsBypassFading();
564 if (needsFading) {
565 delay = 0;
566 fadeoutDuration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION;
567 } else if (wakeUnlockPulsing) {
Jorim Jaggie93698b2016-11-11 18:24:38 -0800568 delay = 0;
569 fadeoutDuration = 240;
570 }
Selim Cinekc075f152019-07-24 15:32:17 -0700571 mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration, needsFading);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200572 mBiometricUnlockController.startKeyguardFadingAway();
Adrian Roosfee661c2017-08-04 17:05:45 +0200573 hideBouncer(true /* destroyView */);
Jorim Jaggie93698b2016-11-11 18:24:38 -0800574 if (wakeUnlockPulsing) {
Selim Cinekc075f152019-07-24 15:32:17 -0700575 if (needsFading) {
Selim Cinek06c12d62019-07-01 19:44:18 -0700576 ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
577 mNotificationContainer,
Selim Cinekc075f152019-07-24 15:32:17 -0700578 fadeoutDuration,
Selim Cinek06c12d62019-07-01 19:44:18 -0700579 () -> {
580 mStatusBar.hideKeyguard();
581 onKeyguardFadedAway();
582 });
583 } else {
584 mStatusBar.fadeKeyguardWhilePulsing();
585 }
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800586 wakeAndUnlockDejank();
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200587 } else {
Selim Cinek06c12d62019-07-01 19:44:18 -0700588 boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700589 if (!staying) {
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700590 mStatusBarWindowController.setKeyguardFadingAway(true);
Selim Cinekc075f152019-07-24 15:32:17 -0700591 if (needsFading) {
Selim Cinek06c12d62019-07-01 19:44:18 -0700592 ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
593 mNotificationContainer,
Selim Cinekc075f152019-07-24 15:32:17 -0700594 fadeoutDuration,
Selim Cinek06c12d62019-07-01 19:44:18 -0700595 () -> {
596 mStatusBar.hideKeyguard();
597 });
598 } else {
599 mStatusBar.hideKeyguard();
600 }
Lucas Dupinf0a67e32018-09-19 15:23:54 -0700601 // hide() will happen asynchronously and might arrive after the scrims
602 // were already hidden, this means that the transition callback won't
603 // be triggered anymore and StatusBarWindowController will be forever in
604 // the fadingAway state.
605 mStatusBar.updateScrimController();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800606 wakeAndUnlockDejank();
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700607 } else {
Selim Cinek06c12d62019-07-01 19:44:18 -0700608 mStatusBar.hideKeyguard();
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500609 mStatusBar.finishKeyguardFadingAway();
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200610 mBiometricUnlockController.finishKeyguardFadingAway();
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700611 }
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200612 }
Selim Cinek84b2acc2019-07-07 00:40:38 -0700613 updateLockIcon();
Jorim Jaggi67b29d52017-06-09 18:00:00 -0700614 updateStates();
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700615 mStatusBarWindowController.setKeyguardShowing(false);
Selim Cinekbaa23272014-07-08 18:01:07 +0200616 mViewMediatorCallback.keyguardGone();
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200617 }
Tej Singhdd7bd352018-02-09 19:33:15 -0800618 StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
619 StatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN);
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100620 }
621
Selim Cinek06c12d62019-07-01 19:44:18 -0700622 private boolean needsBypassFading() {
623 return (mBiometricUnlockController.getMode() == MODE_UNLOCK_FADING
624 || mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING
625 || mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK)
626 && mBypassController.getBypassEnabled();
627 }
628
Lucas Dupinafffbf92019-04-09 19:52:26 -0700629 @Override
Selim Cinekaa8bbf12016-05-04 14:13:20 -0700630 public void onDensityOrFontScaleChanged() {
Adrian Roosfee661c2017-08-04 17:05:45 +0200631 hideBouncer(true /* destroyView */);
Selim Cinekaa8bbf12016-05-04 14:13:20 -0700632 }
633
Lucas Dupinafffbf92019-04-09 19:52:26 -0700634 @Override
Winson Chung1aa24b92019-04-24 15:17:33 -0700635 public void onNavigationModeChanged(int mode) {
636 boolean gesturalNav = QuickStepContract.isGesturalMode(mode);
Lucas Dupinafffbf92019-04-09 19:52:26 -0700637 if (gesturalNav != mGesturalNav) {
638 mGesturalNav = gesturalNav;
639 updateStates();
640 }
641 }
642
Lucas Dupin8c51ce22017-11-21 13:21:05 -0800643 public void onThemeChanged() {
Adrian Roosfee661c2017-08-04 17:05:45 +0200644 hideBouncer(true /* destroyView */);
Lucas Dupinf190a852017-07-31 17:11:26 -0700645 mBouncer.prepare();
Lucas Dupin89516d42017-07-05 13:29:18 -0700646 }
647
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800648 public void onKeyguardFadedAway() {
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700649 mContainer.postDelayed(() -> mStatusBarWindowController.setKeyguardFadingAway(false),
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800650 100);
Selim Cinek06c12d62019-07-01 19:44:18 -0700651 ViewGroupFadeHelper.reset(mNotificationPanelView);
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800652 mStatusBar.finishKeyguardFadingAway();
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200653 mBiometricUnlockController.finishKeyguardFadingAway();
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800654 WindowManagerGlobal.getInstance().trimMemory(
655 ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
656
Jorim Jaggi90978852015-08-18 19:55:53 -0700657 }
658
Lucas Dupin9e3fa102017-11-08 17:16:55 -0800659 private void wakeAndUnlockDejank() {
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200660 if (mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK
Jorim Jaggi8adb30c2016-09-13 15:02:22 -0700661 && LatencyTracker.isEnabled(mContext)) {
662 DejankUtils.postAfterTraversal(() ->
663 LatencyTracker.getInstance(mContext).onActionEnd(
664 LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK));
665 }
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700666 }
667
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200668 private void executeAfterKeyguardGoneAction() {
669 if (mAfterKeyguardGoneAction != null) {
670 mAfterKeyguardGoneAction.onDismiss();
671 mAfterKeyguardGoneAction = null;
672 }
Jorim Jaggibcbe9482016-11-23 17:37:49 +0100673 for (int i = 0; i < mAfterKeyguardGoneRunnables.size(); i++) {
674 mAfterKeyguardGoneRunnables.get(i).run();
675 }
676 mAfterKeyguardGoneRunnables.clear();
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200677 }
678
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100679 /**
680 * Dismisses the keyguard by going to the next screen or making it gone.
681 */
Jorim Jaggi8d5a6e72016-11-02 21:57:33 -0700682 public void dismissAndCollapse() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500683 mStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true);
Jorim Jaggi8d5a6e72016-11-02 21:57:33 -0700684 }
685
Christoph Studer2231c6e2014-12-19 12:40:13 +0100686 /**
687 * WARNING: This method might cause Binder calls.
688 */
Jorim Jaggi15682502014-04-23 12:01:36 +0200689 public boolean isSecure() {
690 return mBouncer.isSecure();
691 }
692
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100693 /**
694 * @return Whether the keyguard is showing
695 */
696 public boolean isShowing() {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200697 return mShowing;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100698 }
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200699
700 /**
701 * Notifies this manager that the back button has been pressed.
702 *
Lucas Dupin3f54fe22018-04-08 23:17:40 -0700703 * @param hideImmediately Hide bouncer when {@code true}, keep it around otherwise.
704 * Non-scrimmed bouncers have a special animation tied to the expansion
705 * of the notification panel.
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200706 * @return whether the back press has been handled
707 */
Lucas Dupin3f54fe22018-04-08 23:17:40 -0700708 public boolean onBackPressed(boolean hideImmediately) {
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200709 if (mBouncer.isShowing()) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500710 mStatusBar.endAffordanceLaunch();
Fabian Kozynskibaa47b62019-04-26 15:40:43 -0400711 // The second condition is for SIM card locked bouncer
712 if (mBouncer.isScrimmed() && !mBouncer.needsFullscreenBouncer()) {
713 hideBouncer(false);
714 updateStates();
715 } else {
716 reset(hideImmediately);
717 }
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200718 return true;
719 }
720 return false;
721 }
722
Jim Millerf41fc962014-06-18 16:33:51 -0700723 public boolean isBouncerShowing() {
724 return mBouncer.isShowing();
725 }
726
Lucas Dupinfa817a02019-07-02 15:22:54 -0700727 /**
728 * When bouncer is fully visible or {@link KeyguardBouncer#show(boolean)} was called but
729 * animation didn't finish yet.
730 */
731 public boolean bouncerIsOrWillBeShowing() {
Lucas Dupinb7d32742019-07-12 17:46:11 +0900732 return mBouncer.isShowing() || mBouncer.inTransit();
Lucas Dupinfa817a02019-07-02 15:22:54 -0700733 }
734
Jackal Guo42cae962018-04-18 18:41:19 +0800735 public boolean isFullscreenBouncer() {
736 return mBouncer.isFullscreenBouncer();
737 }
738
Jorim Jaggi416493b2014-09-13 03:57:32 +0200739 private long getNavBarShowDelay() {
Jason Monk1fd3fc32018-08-14 17:20:09 -0400740 if (mKeyguardMonitor.isKeyguardFadingAway()) {
741 return mKeyguardMonitor.getKeyguardFadingAwayDelay();
Adrian Roos087826a2017-04-19 16:59:09 -0700742 } else if (mBouncer.isShowing()) {
Jorim Jaggi416493b2014-09-13 03:57:32 +0200743 return NAV_BAR_SHOW_DELAY_BOUNCER;
Adrian Roos087826a2017-04-19 16:59:09 -0700744 } else {
745 // No longer dozing, or remote input is active. No delay.
746 return 0;
Jorim Jaggi416493b2014-09-13 03:57:32 +0200747 }
748 }
749
750 private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() {
751 @Override
752 public void run() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500753 mStatusBar.getNavigationBarView().getRootView().setVisibility(View.VISIBLE);
Jorim Jaggi416493b2014-09-13 03:57:32 +0200754 }
755 };
756
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800757 protected void updateStates() {
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200758 int vis = mContainer.getSystemUiVisibility();
Adrian Roosb6011622014-05-14 15:52:53 +0200759 boolean showing = mShowing;
760 boolean occluded = mOccluded;
761 boolean bouncerShowing = mBouncer.isShowing();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100762 boolean bouncerDismissible = !mBouncer.isFullscreenBouncer();
Adrian Roosd28ccd72016-01-06 15:23:14 +0100763 boolean remoteInputActive = mRemoteInputActive;
Adrian Roosb6011622014-05-14 15:52:53 +0200764
Adrian Roosd28ccd72016-01-06 15:23:14 +0100765 if ((bouncerDismissible || !showing || remoteInputActive) !=
766 (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive)
Adrian Roosb6011622014-05-14 15:52:53 +0200767 || mFirstUpdate) {
Adrian Roosd28ccd72016-01-06 15:23:14 +0100768 if (bouncerDismissible || !showing || remoteInputActive) {
Adrian Roosb6011622014-05-14 15:52:53 +0200769 mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK);
Jason Monk1e68fb32014-05-02 16:06:20 -0400770 } else {
Adrian Roosb6011622014-05-14 15:52:53 +0200771 mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
Jason Monk1e68fb32014-05-02 16:06:20 -0400772 }
Jorim Jaggia6310292014-04-16 14:11:52 +0200773 }
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700774
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800775 boolean navBarVisible = isNavBarVisible();
776 boolean lastNavBarVisible = getLastNavBarVisible();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700777 if (navBarVisible != lastNavBarVisible || mFirstUpdate) {
Brad Stenning7e411812018-04-13 22:52:39 -0700778 updateNavigationBarVisibility(navBarVisible);
Adrian Roosb6011622014-05-14 15:52:53 +0200779 }
780
781 if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
Lucas Dupin1a8588d2018-08-21 12:18:47 -0700782 mStatusBarWindowController.setBouncerShowing(bouncerShowing);
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500783 mStatusBar.setBouncerShowing(bouncerShowing);
Adrian Roosb6011622014-05-14 15:52:53 +0200784 }
785
786 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
787 if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) {
Jorim Jaggi6a15d522015-09-22 15:55:33 -0700788 updateMonitor.onKeyguardVisibilityChanged(showing && !occluded);
Adrian Roosb6011622014-05-14 15:52:53 +0200789 }
790 if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
791 updateMonitor.sendKeyguardBouncerChanged(bouncerShowing);
792 }
793
794 mFirstUpdate = false;
795 mLastShowing = showing;
796 mLastOccluded = occluded;
797 mLastBouncerShowing = bouncerShowing;
798 mLastBouncerDismissible = bouncerDismissible;
Adrian Roosd28ccd72016-01-06 15:23:14 +0100799 mLastRemoteInputActive = remoteInputActive;
Adrian Roos087826a2017-04-19 16:59:09 -0700800 mLastDozing = mDozing;
Lucas Dupinafffbf92019-04-09 19:52:26 -0700801 mLastPulsing = mPulsing;
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200802 mLastBiometricMode = mBiometricUnlockController.getMode();
Lucas Dupinafffbf92019-04-09 19:52:26 -0700803 mLastGesturalNav = mGesturalNav;
804 mLastIsDocked = mIsDocked;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500805 mStatusBar.onKeyguardViewManagerStatesUpdated();
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200806 }
Jorim Jaggi8c8bcc12014-04-16 21:36:51 +0200807
Brad Stenning7e411812018-04-13 22:52:39 -0700808 protected void updateNavigationBarVisibility(boolean navBarVisible) {
809 if (mStatusBar.getNavigationBarView() != null) {
810 if (navBarVisible) {
811 long delay = getNavBarShowDelay();
812 if (delay == 0) {
813 mMakeNavigationBarVisibleRunnable.run();
814 } else {
815 mContainer.postOnAnimationDelayed(mMakeNavigationBarVisibleRunnable,
816 delay);
817 }
818 } else {
819 mContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable);
820 mStatusBar.getNavigationBarView().getRootView().setVisibility(View.GONE);
821 }
822 }
823 }
824
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800825 /**
826 * @return Whether the navigation bar should be made visible based on the current state.
827 */
828 protected boolean isNavBarVisible() {
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200829 int biometricMode = mBiometricUnlockController.getMode();
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200830 boolean keyguardShowing = mShowing && !mOccluded;
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200831 boolean hideWhileDozing = mDozing && biometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
Lucas Dupinafffbf92019-04-09 19:52:26 -0700832 boolean keyguardWithGestureNav = (keyguardShowing && !mDozing || mPulsing && !mIsDocked)
833 && mGesturalNav;
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200834 return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing()
Lucas Dupinafffbf92019-04-09 19:52:26 -0700835 || mRemoteInputActive || keyguardWithGestureNav);
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800836 }
837
838 /**
839 * @return Whether the navigation bar was made visible based on the last known state.
840 */
841 protected boolean getLastNavBarVisible() {
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200842 boolean keyguardShowing = mLastShowing && !mLastOccluded;
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200843 boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
Lucas Dupinafffbf92019-04-09 19:52:26 -0700844 boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing
845 || mLastPulsing && !mLastIsDocked) && mLastGesturalNav;
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200846 return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing
Lucas Dupinafffbf92019-04-09 19:52:26 -0700847 || mLastRemoteInputActive || keyguardWithGestureNav);
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800848 }
849
Selim Cinek28540192016-02-19 17:25:08 -0800850 public boolean shouldDismissOnMenuPressed() {
851 return mBouncer.shouldDismissOnMenuPressed();
Jorim Jaggi8c8bcc12014-04-16 21:36:51 +0200852 }
Jorim Jaggidf993512014-05-13 23:06:35 +0200853
854 public boolean interceptMediaKey(KeyEvent event) {
855 return mBouncer.interceptMediaKey(event);
856 }
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200857
Jorim Jaggife762342016-10-13 14:33:27 +0200858 public void readyForKeyguardDone() {
859 mViewMediatorCallback.readyForKeyguardDone();
860 }
861
Jorim Jaggi84a3e7a2014-08-13 17:58:58 +0200862 public boolean shouldDisableWindowAnimationsForUnlock() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500863 return mStatusBar.isInLaunchTransition();
Jorim Jaggi84a3e7a2014-08-13 17:58:58 +0200864 }
865
Issei Suzuki5609ccb2019-06-13 15:04:08 +0200866
867 /**
868 * @return Whether subtle animation should be used for unlocking the device.
869 */
870 public boolean shouldSubtleWindowAnimationsForUnlock() {
Selim Cinek06c12d62019-07-01 19:44:18 -0700871 return needsBypassFading();
Issei Suzuki5609ccb2019-06-13 15:04:08 +0200872 }
873
Jorim Jaggi84a3e7a2014-08-13 17:58:58 +0200874 public boolean isGoingToNotificationShade() {
Beverly8fdb5332019-02-04 14:29:49 -0500875 return ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
876 .leaveOpenOnKeyguardHide();
Jorim Jaggi84a3e7a2014-08-13 17:58:58 +0200877 }
Adrian Roos31b844b2014-11-21 13:55:09 +0100878
879 public boolean isSecure(int userId) {
880 return mBouncer.isSecure() || mLockPatternUtils.isSecure(userId);
881 }
Jim Millerab954542014-10-10 18:21:49 -0700882
Jorim Jaggi33ae80e2015-02-04 16:37:11 +0100883 public void keyguardGoingAway() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500884 mStatusBar.keyguardGoingAway();
Jorim Jaggi33ae80e2015-02-04 16:37:11 +0100885 }
Jim Miller25d7e512015-03-03 17:12:09 -0800886
Jorim Jaggif3b3bee2015-04-16 14:57:34 -0700887 public void animateCollapsePanels(float speedUpFactor) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500888 mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
Jorim Jaggif3b3bee2015-04-16 14:57:34 -0700889 false /* delayed */, speedUpFactor);
Jim Miller25d7e512015-03-03 17:12:09 -0800890 }
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700891
Aarthi Balachander0a427ef2018-07-13 15:00:58 -0700892
893 /**
894 * Called when cancel button in bouncer is pressed.
895 */
896 public void onCancelClicked() {
897 // No-op
898 }
899
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700900 /**
901 * Notifies that the user has authenticated by other means than using the bouncer, for example,
902 * fingerprint.
903 */
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700904 public void notifyKeyguardAuthenticated(boolean strongAuth) {
905 mBouncer.notifyKeyguardAuthenticated(strongAuth);
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700906 }
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700907
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800908 public void showBouncerMessage(String message, ColorStateList colorState) {
909 mBouncer.showMessage(message, colorState);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700910 }
Jorim Jaggib774e552015-08-24 14:52:45 -0700911
912 public ViewRootImpl getViewRootImpl() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500913 return mStatusBar.getStatusBarView().getViewRootImpl();
Jorim Jaggib774e552015-08-24 14:52:45 -0700914 }
Adrian Roosfee661c2017-08-04 17:05:45 +0200915
Adrian Roos34e65402017-08-07 19:32:45 +0200916 public void launchPendingWakeupAction() {
917 DismissWithActionRequest request = mPendingWakeupAction;
918 mPendingWakeupAction = null;
Adrian Roosfee661c2017-08-04 17:05:45 +0200919 if (request != null) {
920 if (mShowing) {
921 dismissWithAction(request.dismissAction, request.cancelAction,
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800922 request.afterKeyguardGone, request.message);
Adrian Roosfee661c2017-08-04 17:05:45 +0200923 } else if (request.dismissAction != null) {
924 request.dismissAction.onDismiss();
925 }
926 }
927 }
928
Adrian Roos34e65402017-08-07 19:32:45 +0200929 public void cancelPendingWakeupAction() {
930 DismissWithActionRequest request = mPendingWakeupAction;
931 mPendingWakeupAction = null;
Adrian Roosfee661c2017-08-04 17:05:45 +0200932 if (request != null && request.cancelAction != null) {
933 request.cancelAction.run();
934 }
935 }
936
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700937 public boolean bouncerNeedsScrimming() {
Lucas Dupin300e3712019-03-27 19:33:36 -0700938 return mOccluded || mBouncer.willDismissWithAction()
Lucas Dupin93f714d2019-03-26 16:49:24 -0700939 || mStatusBar.isFullScreenUserSwitcherState()
Lucas Dupin300e3712019-03-27 19:33:36 -0700940 || (mBouncer.isShowing() && mBouncer.isScrimmed())
941 || mBouncer.isFullscreenBouncer();
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700942 }
943
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800944 public void dump(PrintWriter pw) {
945 pw.println("StatusBarKeyguardViewManager:");
946 pw.println(" mShowing: " + mShowing);
947 pw.println(" mOccluded: " + mOccluded);
948 pw.println(" mRemoteInputActive: " + mRemoteInputActive);
949 pw.println(" mDozing: " + mDozing);
950 pw.println(" mGoingToSleepVisibleNotOccluded: " + mGoingToSleepVisibleNotOccluded);
951 pw.println(" mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction);
952 pw.println(" mAfterKeyguardGoneRunnables: " + mAfterKeyguardGoneRunnables);
953 pw.println(" mPendingWakeupAction: " + mPendingWakeupAction);
954
955 if (mBouncer != null) {
956 mBouncer.dump(pw);
957 }
958 }
959
Evan Laird878c8532018-10-15 15:54:29 -0400960 @Override
961 public void onStateChanged(int newState) {
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700962 updateLockIcon();
Evan Laird878c8532018-10-15 15:54:29 -0400963 }
964
965 @Override
966 public void onDozingChanged(boolean isDozing) {
967 setDozing(isDozing);
968 }
969
Lucas Dupin407cc582019-03-11 21:04:31 -0700970 public KeyguardBouncer getBouncer() {
971 return mBouncer;
972 }
973
Adrian Roos34e65402017-08-07 19:32:45 +0200974 private static class DismissWithActionRequest {
Adrian Roosfee661c2017-08-04 17:05:45 +0200975 final OnDismissAction dismissAction;
976 final Runnable cancelAction;
977 final boolean afterKeyguardGone;
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800978 final String message;
Adrian Roosfee661c2017-08-04 17:05:45 +0200979
Adrian Roos34e65402017-08-07 19:32:45 +0200980 DismissWithActionRequest(OnDismissAction dismissAction, Runnable cancelAction,
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800981 boolean afterKeyguardGone, String message) {
Adrian Roosfee661c2017-08-04 17:05:45 +0200982 this.dismissAction = dismissAction;
983 this.cancelAction = cancelAction;
984 this.afterKeyguardGone = afterKeyguardGone;
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800985 this.message = message;
Adrian Roosfee661c2017-08-04 17:05:45 +0200986 }
987 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100988}