blob: 3913254aab236c535ebe9f9c353178fc1010f4c0 [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
Jorim Jaggif5304ad2017-07-17 18:31:13 +020019import static com.android.keyguard.KeyguardHostView.OnDismissAction;
20import static com.android.systemui.statusbar.phone.FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
21import static com.android.systemui.statusbar.phone.FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
22
Jorim Jaggi786afcb2014-09-25 02:41:29 +020023import android.content.ComponentCallbacks2;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010024import android.content.Context;
25import android.os.Bundle;
Jorim Jaggie29b2db2014-05-30 23:17:03 +020026import android.os.SystemClock;
Jorim Jaggi0d210f62015-07-10 14:24:44 -070027import android.os.Trace;
Jorim Jaggidf993512014-05-13 23:06:35 +020028import android.view.KeyEvent;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010029import android.view.View;
30import android.view.ViewGroup;
Jorim Jaggib774e552015-08-24 14:52:45 -070031import android.view.ViewRootImpl;
Jorim Jaggi786afcb2014-09-25 02:41:29 +020032import android.view.WindowManagerGlobal;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010033
Jorim Jaggi5cf17872014-03-26 18:31:48 +010034import com.android.internal.widget.LockPatternUtils;
Adrian Roosb6011622014-05-14 15:52:53 +020035import com.android.keyguard.KeyguardUpdateMonitor;
Jorim Jaggia9d7fcd2017-05-18 01:08:12 +020036import com.android.keyguard.KeyguardUpdateMonitorCallback;
Jorim Jaggif5304ad2017-07-17 18:31:13 +020037import com.android.keyguard.LatencyTracker;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010038import com.android.keyguard.ViewMediatorCallback;
Jorim Jaggi8adb30c2016-09-13 15:02:22 -070039import com.android.systemui.DejankUtils;
Jason Monk421a9412017-02-06 09:15:21 -080040import com.android.systemui.Dependency;
Xiyuan Xia1b30f792016-01-06 08:50:30 -080041import com.android.systemui.SystemUIFactory;
Jorim Jaggi241ae102016-11-02 21:57:33 -070042import com.android.systemui.keyguard.DismissCallbackRegistry;
Jim Miller25d7e512015-03-03 17:12:09 -080043import com.android.systemui.statusbar.CommandQueue;
Adrian Roosd28ccd72016-01-06 15:23:14 +010044import com.android.systemui.statusbar.RemoteInputController;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010045
Jorim Jaggibcbe9482016-11-23 17:37:49 +010046import java.util.ArrayList;
47
Jorim Jaggi5cf17872014-03-26 18:31:48 +010048/**
49 * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
50 * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
51 * which is in turn, reported to this class by the current
52 * {@link com.android.keyguard.KeyguardViewBase}.
53 */
Adrian Roosd28ccd72016-01-06 15:23:14 +010054public class StatusBarKeyguardViewManager implements RemoteInputController.Callback {
Jorim Jaggi76a16232014-08-08 17:00:47 +020055
56 // When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
Jorim Jaggi56fd70c2016-10-27 19:57:08 -070057 private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
Jorim Jaggi76a16232014-08-08 17:00:47 +020058
Jorim Jaggi416493b2014-09-13 03:57:32 +020059 // Delay for showing the navigation bar when the bouncer appears. This should be kept in sync
60 // with the appear animations of the PIN/pattern/password views.
61 private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320;
62
Jorim Jaggi007f0e82015-08-14 13:56:01 -070063 private static final long WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS = 200;
64
Jorim Jaggie8fde5d2016-06-30 23:41:37 -070065 // Duration of the Keyguard dismissal animation in case the user is currently locked. This is to
66 // make everything a bit slower to bridge a gap until the user is unlocked and home screen has
67 // dranw its first frame.
68 private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
69
Jorim Jaggi5cf17872014-03-26 18:31:48 +010070 private static String TAG = "StatusBarKeyguardViewManager";
71
Xiyuan Xia1b30f792016-01-06 08:50:30 -080072 protected final Context mContext;
Jason Monk421a9412017-02-06 09:15:21 -080073 private final StatusBarWindowManager mStatusBarWindowManager;
Adrian Roos7a5e4c92017-07-31 16:40:19 +020074 private final boolean mDisplayBlanksAfterDoze;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010075
Xiyuan Xia1b30f792016-01-06 08:50:30 -080076 protected LockPatternUtils mLockPatternUtils;
77 protected ViewMediatorCallback mViewMediatorCallback;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050078 protected StatusBar mStatusBar;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020079 private ScrimController mScrimController;
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -070080 private FingerprintUnlockController mFingerprintUnlockController;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010081
Jorim Jaggi5cf17872014-03-26 18:31:48 +010082 private ViewGroup mContainer;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010083
Jorim Jaggi0d210f62015-07-10 14:24:44 -070084 private boolean mScreenTurnedOn;
Xiyuan Xia1b30f792016-01-06 08:50:30 -080085 protected KeyguardBouncer mBouncer;
86 protected boolean mShowing;
87 protected boolean mOccluded;
88 protected boolean mRemoteInputActive;
Adrian Roos087826a2017-04-19 16:59:09 -070089 private boolean mDozing;
Jorim Jaggi5cf17872014-03-26 18:31:48 +010090
Xiyuan Xia1b30f792016-01-06 08:50:30 -080091 protected boolean mFirstUpdate = true;
92 protected boolean mLastShowing;
93 protected boolean mLastOccluded;
Adrian Roosb6011622014-05-14 15:52:53 +020094 private boolean mLastBouncerShowing;
95 private boolean mLastBouncerDismissible;
Xiyuan Xia1b30f792016-01-06 08:50:30 -080096 protected boolean mLastRemoteInputActive;
Adrian Roos087826a2017-04-19 16:59:09 -070097 private boolean mLastDozing;
Jorim Jaggi67b29d52017-06-09 18:00:00 -070098 private boolean mLastDeferScrimFadeOut;
Jorim Jaggif5304ad2017-07-17 18:31:13 +020099 private int mLastFpMode;
Adrian Roosd28ccd72016-01-06 15:23:14 +0100100
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200101 private OnDismissAction mAfterKeyguardGoneAction;
Jorim Jaggibcbe9482016-11-23 17:37:49 +0100102 private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700103 private boolean mDeferScrimFadeOut;
Adrian Roosb6011622014-05-14 15:52:53 +0200104
Jorim Jaggia9d7fcd2017-05-18 01:08:12 +0200105 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
106 new KeyguardUpdateMonitorCallback() {
107 @Override
108 public void onEmergencyCallAction() {
109
110 // Since we won't get a setOccluded call we have to reset the view manually such that
111 // the bouncer goes away.
112 if (mOccluded) {
113 reset(false /* hideBouncerWhenShowing */);
114 }
115 }
116 };
117
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100118 public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback,
119 LockPatternUtils lockPatternUtils) {
120 mContext = context;
121 mViewMediatorCallback = callback;
122 mLockPatternUtils = lockPatternUtils;
Jason Monk421a9412017-02-06 09:15:21 -0800123 mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
Jorim Jaggia9d7fcd2017-05-18 01:08:12 +0200124 KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback);
Adrian Roos7a5e4c92017-07-31 16:40:19 +0200125 mDisplayBlanksAfterDoze = context.getResources().getBoolean(
126 com.android.internal.R.bool.config_displayBlanksAfterDoze);
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100127 }
128
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500129 public void registerStatusBar(StatusBar statusBar,
Jason Monk421a9412017-02-06 09:15:21 -0800130 ViewGroup container,
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700131 ScrimController scrimController,
Jorim Jaggi241ae102016-11-02 21:57:33 -0700132 FingerprintUnlockController fingerprintUnlockController,
133 DismissCallbackRegistry dismissCallbackRegistry) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500134 mStatusBar = statusBar;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100135 mContainer = container;
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200136 mScrimController = scrimController;
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700137 mFingerprintUnlockController = fingerprintUnlockController;
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800138 mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
Jorim Jaggi241ae102016-11-02 21:57:33 -0700139 mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100140 }
141
142 /**
143 * Show the keyguard. Will handle creating and attaching to the view manager
144 * lazily.
145 */
146 public void show(Bundle options) {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200147 mShowing = true;
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200148 mStatusBarWindowManager.setKeyguardShowing(true);
Selim Cinekedd32b82015-06-23 22:05:58 -0400149 mScrimController.abortKeyguardFadingOut();
Jorim Jaggife762342016-10-13 14:33:27 +0200150 reset(true /* hideBouncerWhenShowing */);
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100151 }
152
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200153 /**
154 * Shows the notification keyguard or the bouncer depending on
155 * {@link KeyguardBouncer#needsFullscreenBouncer()}.
156 */
Jorim Jaggife762342016-10-13 14:33:27 +0200157 protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
Adrian Roos41eecff2017-06-29 14:09:52 +0200158 if (mBouncer.needsFullscreenBouncer() && !mDozing) {
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200159 // The keyguard might be showing (already). So we need to hide it.
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500160 mStatusBar.hideKeyguard();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100161 mBouncer.show(true /* resetSecuritySelection */);
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200162 } else {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500163 mStatusBar.showKeyguard();
Jorim Jaggife762342016-10-13 14:33:27 +0200164 if (hideBouncerWhenShowing) {
165 mBouncer.hide(false /* destroyView */);
166 mBouncer.prepare();
167 }
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200168 }
Adrian Roos61676aa2017-08-03 16:24:32 +0200169 updateStates();
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200170 }
171
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200172 private void showBouncer() {
Adrian Roos0002a452014-07-03 13:46:07 +0200173 if (mShowing) {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100174 mBouncer.show(false /* resetSecuritySelection */);
Dan Sandler3806c772014-05-08 14:52:10 -0400175 }
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200176 updateStates();
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100177 }
178
Jorim Jaggid9449862015-05-29 14:49:08 -0700179 public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
180 boolean afterKeyguardGone) {
Adrian Roos0002a452014-07-03 13:46:07 +0200181 if (mShowing) {
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200182 if (!afterKeyguardGone) {
Jorim Jaggid9449862015-05-29 14:49:08 -0700183 mBouncer.showWithDismissAction(r, cancelAction);
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200184 } else {
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200185 mAfterKeyguardGoneAction = r;
Jorim Jaggi8d5a6e72016-11-02 21:57:33 -0700186 mBouncer.show(false /* resetSecuritySelection */);
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200187 }
Adrian Roos7d7090d2014-05-21 13:10:23 +0200188 }
189 updateStates();
190 }
191
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100192 /**
Jorim Jaggibcbe9482016-11-23 17:37:49 +0100193 * Adds a {@param runnable} to be executed after Keyguard is gone.
194 */
195 public void addAfterKeyguardGoneRunnable(Runnable runnable) {
196 mAfterKeyguardGoneRunnables.add(runnable);
197 }
198
199 /**
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100200 * Reset the state of the view.
201 */
Jorim Jaggife762342016-10-13 14:33:27 +0200202 public void reset(boolean hideBouncerWhenShowing) {
Jorim Jaggi43bdbbd2014-05-09 16:05:53 +0200203 if (mShowing) {
Adrian Roos7a56d1a2017-08-04 15:04:43 +0200204 if (mOccluded && !mDozing) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500205 mStatusBar.hideKeyguard();
206 mStatusBar.stopWaitingForKeyguardExit();
Jorim Jaggia0be6d52014-05-26 03:01:13 +0200207 mBouncer.hide(false /* destroyView */);
Jorim Jaggi43bdbbd2014-05-09 16:05:53 +0200208 } else {
Jorim Jaggife762342016-10-13 14:33:27 +0200209 showBouncerOrKeyguard(hideBouncerWhenShowing);
Jorim Jaggi43bdbbd2014-05-09 16:05:53 +0200210 }
Selim Cinek1fcafc42015-07-20 14:39:25 -0700211 KeyguardUpdateMonitor.getInstance(mContext).sendKeyguardReset();
Jorim Jaggi43bdbbd2014-05-09 16:05:53 +0200212 updateStates();
Dan Sandler3806c772014-05-08 14:52:10 -0400213 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100214 }
215
Jorim Jaggi18f18ae2015-09-10 15:48:21 -0700216 public void onStartedGoingToSleep() {
Adrian Roos731d4df2017-07-18 15:10:39 +0200217 // TODO: remove
Jorim Jaggi18f18ae2015-09-10 15:48:21 -0700218 }
219
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700220 public void onFinishedGoingToSleep() {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200221 mBouncer.onScreenTurnedOff();
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100222 }
223
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700224 public void onStartedWakingUp() {
Adrian Roos731d4df2017-07-18 15:10:39 +0200225 // TODO: remove
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100226 }
227
Jorim Jaggi93739112015-08-13 15:53:14 -0700228 public void onScreenTurningOn() {
Adrian Roos731d4df2017-07-18 15:10:39 +0200229 // TODO: remove
Selim Cinek372d1bd2015-08-14 13:19:37 -0700230 }
231
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700232 public void onScreenTurnedOn() {
Nick Desaulniers1d396752016-07-25 15:05:33 -0700233 Trace.beginSection("StatusBarKeyguardViewManager#onScreenTurnedOn");
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700234 mScreenTurnedOn = true;
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700235 if (mDeferScrimFadeOut) {
236 mDeferScrimFadeOut = false;
Jorim Jaggiab45a212015-08-20 16:59:44 -0700237 animateScrimControllerKeyguardFadingOut(0, WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS,
238 true /* skipFirstFrame */);
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700239 updateStates();
240 }
Nick Desaulniers1d396752016-07-25 15:05:33 -0700241 Trace.endSection();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700242 }
243
Adrian Roosd28ccd72016-01-06 15:23:14 +0100244 @Override
245 public void onRemoteInputActive(boolean active) {
246 mRemoteInputActive = active;
247 updateStates();
248 }
249
Adrian Roos087826a2017-04-19 16:59:09 -0700250 public void setDozing(boolean dozing) {
Adrian Roos41eecff2017-06-29 14:09:52 +0200251 if (mDozing != dozing) {
252 mDozing = dozing;
Adrian Roos61676aa2017-08-03 16:24:32 +0200253 if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) {
254 reset(dozing /* hideBouncerWhenShowing */);
255 }
Adrian Roos41eecff2017-06-29 14:09:52 +0200256 updateStates();
257 }
Adrian Roos087826a2017-04-19 16:59:09 -0700258 }
259
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700260 public void onScreenTurnedOff() {
261 mScreenTurnedOn = false;
262 }
263
264 public void notifyDeviceWakeUpRequested() {
Adrian Roos731d4df2017-07-18 15:10:39 +0200265 // TODO: remove
Selim Cinekf8fbc2a72015-06-22 16:42:07 -0400266 }
267
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100268 public void setNeedsInput(boolean needsInput) {
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200269 mStatusBarWindowManager.setKeyguardNeedsInput(needsInput);
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100270 }
271
Adrian Roosd5c2db62016-03-08 16:11:31 -0800272 public boolean isUnlockWithWallpaper() {
273 return mStatusBarWindowManager.isShowingWallpaper();
274 }
275
Jorim Jaggi6626f542016-08-22 13:08:44 -0700276 public void setOccluded(boolean occluded, boolean animate) {
Selim Cinekbaa23272014-07-08 18:01:07 +0200277 if (occluded && !mOccluded && mShowing) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500278 if (mStatusBar.isInLaunchTransition()) {
Selim Cinekbaa23272014-07-08 18:01:07 +0200279 mOccluded = true;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500280 mStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */,
Selim Cinekbaa23272014-07-08 18:01:07 +0200281 new Runnable() {
282 @Override
283 public void run() {
Jorim Jaggi826730a2014-12-08 21:05:13 +0100284 mStatusBarWindowManager.setKeyguardOccluded(mOccluded);
Jorim Jaggife762342016-10-13 14:33:27 +0200285 reset(true /* hideBouncerWhenShowing */);
Selim Cinekbaa23272014-07-08 18:01:07 +0200286 }
287 });
288 return;
289 }
290 }
Jorim Jaggia6310292014-04-16 14:11:52 +0200291 mOccluded = occluded;
Adrian Roos909fe2d2016-10-12 12:03:24 -0700292 if (mShowing) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500293 mStatusBar.updateMediaMetaData(false, animate && !occluded);
Adrian Roos909fe2d2016-10-12 12:03:24 -0700294 }
Jorim Jaggicff0acb2014-03-31 16:35:15 +0200295 mStatusBarWindowManager.setKeyguardOccluded(occluded);
Jorim Jaggife762342016-10-13 14:33:27 +0200296
Adrian Roos7a56d1a2017-08-04 15:04:43 +0200297 // setDozing(false) will call reset once we stop dozing.
298 if (!mDozing) {
299 // If Keyguard is reshown, don't hide the bouncer as it might just have been requested
300 // by a FLAG_DISMISS_KEYGUARD_ACTIVITY.
301 reset(false /* hideBouncerWhenShowing*/);
302 }
Adrian Roos909fe2d2016-10-12 12:03:24 -0700303 if (animate && !occluded && mShowing) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500304 mStatusBar.animateKeyguardUnoccluding();
Jorim Jaggi6626f542016-08-22 13:08:44 -0700305 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100306 }
307
Dan Sandler4b22bdf2014-06-05 00:58:02 -0400308 public boolean isOccluded() {
309 return mOccluded;
310 }
311
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100312 /**
Jorim Jaggi76a16232014-08-08 17:00:47 +0200313 * Starts the animation before we dismiss Keyguard, i.e. an disappearing animation on the
314 * security view of the bouncer.
315 *
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200316 * @param finishRunnable the runnable to be run after the animation finished, or {@code null} if
317 * no action should be run
Jorim Jaggi76a16232014-08-08 17:00:47 +0200318 */
319 public void startPreHideAnimation(Runnable finishRunnable) {
320 if (mBouncer.isShowing()) {
321 mBouncer.startPreHideAnimation(finishRunnable);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200322 } else if (finishRunnable != null) {
Jorim Jaggi76a16232014-08-08 17:00:47 +0200323 finishRunnable.run();
324 }
325 }
326
327 /**
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100328 * Hides the keyguard view
329 */
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700330 public void hide(long startTime, long fadeoutDuration) {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200331 mShowing = false;
Jorim Jaggi44cf9192014-06-17 19:16:00 -0700332
Jorim Jaggi031f7952016-09-01 16:39:26 -0700333 if (KeyguardUpdateMonitor.getInstance(mContext).needsSlowUnlockTransition()) {
Jorim Jaggie8fde5d2016-06-30 23:41:37 -0700334 fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED;
335 }
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200336 long uptimeMillis = SystemClock.uptimeMillis();
Jorim Jaggi76a16232014-08-08 17:00:47 +0200337 long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis);
Selim Cinekbaa23272014-07-08 18:01:07 +0200338
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500339 if (mStatusBar.isInLaunchTransition() ) {
340 mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() {
Selim Cinekbaa23272014-07-08 18:01:07 +0200341 @Override
342 public void run() {
343 mStatusBarWindowManager.setKeyguardShowing(false);
344 mStatusBarWindowManager.setKeyguardFadingAway(true);
Jorim Jaggi76a16232014-08-08 17:00:47 +0200345 mBouncer.hide(true /* destroyView */);
Selim Cinekbaa23272014-07-08 18:01:07 +0200346 updateStates();
347 mScrimController.animateKeyguardFadingOut(
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500348 StatusBar.FADE_KEYGUARD_START_DELAY,
349 StatusBar.FADE_KEYGUARD_DURATION, null,
Jorim Jaggiab45a212015-08-20 16:59:44 -0700350 false /* skipFirstFrame */);
Selim Cinekbaa23272014-07-08 18:01:07 +0200351 }
352 }, new Runnable() {
353 @Override
354 public void run() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500355 mStatusBar.hideKeyguard();
Selim Cinekbaa23272014-07-08 18:01:07 +0200356 mStatusBarWindowManager.setKeyguardFadingAway(false);
357 mViewMediatorCallback.keyguardGone();
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200358 executeAfterKeyguardGoneAction();
Selim Cinekbaa23272014-07-08 18:01:07 +0200359 }
360 });
361 } else {
Jorim Jaggi8d5a6e72016-11-02 21:57:33 -0700362 executeAfterKeyguardGoneAction();
Jorim Jaggie93698b2016-11-11 18:24:38 -0800363 boolean wakeUnlockPulsing =
364 mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
365 if (wakeUnlockPulsing) {
366 delay = 0;
367 fadeoutDuration = 240;
368 }
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500369 mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
Jorim Jaggie93698b2016-11-11 18:24:38 -0800370 mFingerprintUnlockController.startKeyguardFadingAway();
371 mBouncer.hide(true /* destroyView */);
Jorim Jaggie93698b2016-11-11 18:24:38 -0800372 if (wakeUnlockPulsing) {
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700373 mStatusBarWindowManager.setKeyguardFadingAway(true);
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500374 mStatusBar.fadeKeyguardWhilePulsing();
Jorim Jaggie93698b2016-11-11 18:24:38 -0800375 animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500376 mStatusBar::hideKeyguard, false /* skipFirstFrame */);
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200377 } else {
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700378 mFingerprintUnlockController.startKeyguardFadingAway();
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500379 mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
380 boolean staying = mStatusBar.hideKeyguard();
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700381 if (!staying) {
382 mStatusBarWindowManager.setKeyguardFadingAway(true);
Jorim Jaggi8adb30c2016-09-13 15:02:22 -0700383 if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK) {
Adrian Roos7a5e4c92017-07-31 16:40:19 +0200384 boolean turnedOnSinceAuth =
385 mFingerprintUnlockController.hasScreenTurnedOnSinceAuthenticating();
386 if (!mScreenTurnedOn || mDisplayBlanksAfterDoze && !turnedOnSinceAuth) {
387 // Not ready to animate yet; either because the screen is not on yet,
388 // or it is on but will turn off before waking out of doze.
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700389 mDeferScrimFadeOut = true;
390 } else {
391
392 // Screen is already on, don't defer with fading out.
393 animateScrimControllerKeyguardFadingOut(0,
Jorim Jaggiab45a212015-08-20 16:59:44 -0700394 WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS,
395 true /* skipFirstFrame */);
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700396 }
397 } else {
Jorim Jaggiab45a212015-08-20 16:59:44 -0700398 animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
399 false /* skipFirstFrame */);
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700400 }
401 } else {
402 mScrimController.animateGoingToFullShade(delay, fadeoutDuration);
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500403 mStatusBar.finishKeyguardFadingAway();
Adrian Roos88e61aa2017-05-23 16:16:50 -0700404 mFingerprintUnlockController.finishKeyguardFadingAway();
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700405 }
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200406 }
Jorim Jaggi67b29d52017-06-09 18:00:00 -0700407 updateStates();
Selim Cinekbaa23272014-07-08 18:01:07 +0200408 mStatusBarWindowManager.setKeyguardShowing(false);
Selim Cinekbaa23272014-07-08 18:01:07 +0200409 mViewMediatorCallback.keyguardGone();
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200410 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100411 }
412
Selim Cinekaa8bbf12016-05-04 14:13:20 -0700413 public void onDensityOrFontScaleChanged() {
414 mBouncer.hide(true /* destroyView */);
415 }
416
Lucas Dupin89516d42017-07-05 13:29:18 -0700417 public void onOverlayChanged() {
418 mBouncer.hide(true /* destroyView */);
Lucas Dupinf190a852017-07-31 17:11:26 -0700419 mBouncer.prepare();
Lucas Dupin89516d42017-07-05 13:29:18 -0700420 }
421
Jorim Jaggiab45a212015-08-20 16:59:44 -0700422 private void animateScrimControllerKeyguardFadingOut(long delay, long duration,
423 boolean skipFirstFrame) {
424 animateScrimControllerKeyguardFadingOut(delay, duration, null /* endRunnable */,
425 skipFirstFrame);
Jorim Jaggi90978852015-08-18 19:55:53 -0700426 }
427
428 private void animateScrimControllerKeyguardFadingOut(long delay, long duration,
Jorim Jaggiab45a212015-08-20 16:59:44 -0700429 final Runnable endRunnable, boolean skipFirstFrame) {
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700430 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "Fading out", 0);
431 mScrimController.animateKeyguardFadingOut(delay, duration, new Runnable() {
432 @Override
433 public void run() {
Jorim Jaggi90978852015-08-18 19:55:53 -0700434 if (endRunnable != null) {
435 endRunnable.run();
436 }
Jorim Jaggi56fd70c2016-10-27 19:57:08 -0700437 mContainer.postDelayed(() -> mStatusBarWindowManager.setKeyguardFadingAway(false),
438 100);
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500439 mStatusBar.finishKeyguardFadingAway();
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700440 mFingerprintUnlockController.finishKeyguardFadingAway();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700441 WindowManagerGlobal.getInstance().trimMemory(
442 ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
443 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "Fading out", 0);
444 }
Jorim Jaggiab45a212015-08-20 16:59:44 -0700445 }, skipFirstFrame);
Jorim Jaggi8adb30c2016-09-13 15:02:22 -0700446 if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK
447 && LatencyTracker.isEnabled(mContext)) {
448 DejankUtils.postAfterTraversal(() ->
449 LatencyTracker.getInstance(mContext).onActionEnd(
450 LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK));
451 }
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700452 }
453
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200454 private void executeAfterKeyguardGoneAction() {
455 if (mAfterKeyguardGoneAction != null) {
456 mAfterKeyguardGoneAction.onDismiss();
457 mAfterKeyguardGoneAction = null;
458 }
Jorim Jaggibcbe9482016-11-23 17:37:49 +0100459 for (int i = 0; i < mAfterKeyguardGoneRunnables.size(); i++) {
460 mAfterKeyguardGoneRunnables.get(i).run();
461 }
462 mAfterKeyguardGoneRunnables.clear();
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200463 }
464
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100465 /**
466 * Dismisses the keyguard by going to the next screen or making it gone.
467 */
Jorim Jaggi8d5a6e72016-11-02 21:57:33 -0700468 public void dismissAndCollapse() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500469 mStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true);
Jorim Jaggi8d5a6e72016-11-02 21:57:33 -0700470 }
471
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100472 public void dismiss() {
Jorim Jaggife762342016-10-13 14:33:27 +0200473 showBouncer();
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100474 }
475
Christoph Studer2231c6e2014-12-19 12:40:13 +0100476 /**
477 * WARNING: This method might cause Binder calls.
478 */
Jorim Jaggi15682502014-04-23 12:01:36 +0200479 public boolean isSecure() {
480 return mBouncer.isSecure();
481 }
482
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100483 /**
484 * @return Whether the keyguard is showing
485 */
486 public boolean isShowing() {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200487 return mShowing;
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100488 }
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200489
490 /**
491 * Notifies this manager that the back button has been pressed.
492 *
493 * @return whether the back press has been handled
494 */
495 public boolean onBackPressed() {
496 if (mBouncer.isShowing()) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500497 mStatusBar.endAffordanceLaunch();
Jorim Jaggife762342016-10-13 14:33:27 +0200498 reset(true /* hideBouncerWhenShowing */);
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200499 return true;
500 }
501 return false;
502 }
503
Jim Millerf41fc962014-06-18 16:33:51 -0700504 public boolean isBouncerShowing() {
505 return mBouncer.isShowing();
506 }
507
Jorim Jaggi416493b2014-09-13 03:57:32 +0200508 private long getNavBarShowDelay() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500509 if (mStatusBar.isKeyguardFadingAway()) {
510 return mStatusBar.getKeyguardFadingAwayDelay();
Adrian Roos087826a2017-04-19 16:59:09 -0700511 } else if (mBouncer.isShowing()) {
Jorim Jaggi416493b2014-09-13 03:57:32 +0200512 return NAV_BAR_SHOW_DELAY_BOUNCER;
Adrian Roos087826a2017-04-19 16:59:09 -0700513 } else {
514 // No longer dozing, or remote input is active. No delay.
515 return 0;
Jorim Jaggi416493b2014-09-13 03:57:32 +0200516 }
517 }
518
519 private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() {
520 @Override
521 public void run() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500522 mStatusBar.getNavigationBarView().getRootView().setVisibility(View.VISIBLE);
Jorim Jaggi416493b2014-09-13 03:57:32 +0200523 }
524 };
525
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800526 protected void updateStates() {
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200527 int vis = mContainer.getSystemUiVisibility();
Adrian Roosb6011622014-05-14 15:52:53 +0200528 boolean showing = mShowing;
529 boolean occluded = mOccluded;
530 boolean bouncerShowing = mBouncer.isShowing();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100531 boolean bouncerDismissible = !mBouncer.isFullscreenBouncer();
Adrian Roosd28ccd72016-01-06 15:23:14 +0100532 boolean remoteInputActive = mRemoteInputActive;
Adrian Roosb6011622014-05-14 15:52:53 +0200533
Adrian Roosd28ccd72016-01-06 15:23:14 +0100534 if ((bouncerDismissible || !showing || remoteInputActive) !=
535 (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive)
Adrian Roosb6011622014-05-14 15:52:53 +0200536 || mFirstUpdate) {
Adrian Roosd28ccd72016-01-06 15:23:14 +0100537 if (bouncerDismissible || !showing || remoteInputActive) {
Adrian Roosb6011622014-05-14 15:52:53 +0200538 mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK);
Jason Monk1e68fb32014-05-02 16:06:20 -0400539 } else {
Adrian Roosb6011622014-05-14 15:52:53 +0200540 mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
Jason Monk1e68fb32014-05-02 16:06:20 -0400541 }
Jorim Jaggia6310292014-04-16 14:11:52 +0200542 }
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700543
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800544 boolean navBarVisible = isNavBarVisible();
545 boolean lastNavBarVisible = getLastNavBarVisible();
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700546 if (navBarVisible != lastNavBarVisible || mFirstUpdate) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500547 if (mStatusBar.getNavigationBarView() != null) {
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700548 if (navBarVisible) {
Jorim Jaggi83eb6bb2015-08-17 17:38:58 -0700549 long delay = getNavBarShowDelay();
550 if (delay == 0) {
551 mMakeNavigationBarVisibleRunnable.run();
552 } else {
553 mContainer.postOnAnimationDelayed(mMakeNavigationBarVisibleRunnable,
554 delay);
555 }
Adrian Roosb6011622014-05-14 15:52:53 +0200556 } else {
Jorim Jaggi416493b2014-09-13 03:57:32 +0200557 mContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable);
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500558 mStatusBar.getNavigationBarView().getRootView().setVisibility(View.GONE);
Adrian Roosb6011622014-05-14 15:52:53 +0200559 }
560 }
561 }
562
563 if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
564 mStatusBarWindowManager.setBouncerShowing(bouncerShowing);
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500565 mStatusBar.setBouncerShowing(bouncerShowing);
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200566 mScrimController.setBouncerShowing(bouncerShowing);
Adrian Roosb6011622014-05-14 15:52:53 +0200567 }
568
569 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
570 if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) {
Jorim Jaggi6a15d522015-09-22 15:55:33 -0700571 updateMonitor.onKeyguardVisibilityChanged(showing && !occluded);
Adrian Roosb6011622014-05-14 15:52:53 +0200572 }
573 if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
574 updateMonitor.sendKeyguardBouncerChanged(bouncerShowing);
575 }
576
577 mFirstUpdate = false;
578 mLastShowing = showing;
579 mLastOccluded = occluded;
580 mLastBouncerShowing = bouncerShowing;
581 mLastBouncerDismissible = bouncerDismissible;
Adrian Roosd28ccd72016-01-06 15:23:14 +0100582 mLastRemoteInputActive = remoteInputActive;
Adrian Roos087826a2017-04-19 16:59:09 -0700583 mLastDozing = mDozing;
Jorim Jaggi67b29d52017-06-09 18:00:00 -0700584 mLastDeferScrimFadeOut = mDeferScrimFadeOut;
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200585 mLastFpMode = mFingerprintUnlockController.getMode();
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500586 mStatusBar.onKeyguardViewManagerStatesUpdated();
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200587 }
Jorim Jaggi8c8bcc12014-04-16 21:36:51 +0200588
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800589 /**
590 * @return Whether the navigation bar should be made visible based on the current state.
591 */
592 protected boolean isNavBarVisible() {
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200593 int fpMode = mFingerprintUnlockController.getMode();
594 boolean keyguardShowing = mShowing && !mOccluded;
595 boolean hideWhileDozing = mDozing && fpMode != MODE_WAKE_AND_UNLOCK_PULSING;
596 return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing()
597 || mRemoteInputActive) && !mDeferScrimFadeOut;
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800598 }
599
600 /**
601 * @return Whether the navigation bar was made visible based on the last known state.
602 */
603 protected boolean getLastNavBarVisible() {
Jorim Jaggif5304ad2017-07-17 18:31:13 +0200604 boolean keyguardShowing = mLastShowing && !mLastOccluded;
605 boolean hideWhileDozing = mLastDozing && mLastFpMode != MODE_WAKE_AND_UNLOCK_PULSING;
606 return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing
Jorim Jaggiee18e782017-06-12 13:45:50 -0700607 || mLastRemoteInputActive) && !mLastDeferScrimFadeOut;
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800608 }
609
Selim Cinek28540192016-02-19 17:25:08 -0800610 public boolean shouldDismissOnMenuPressed() {
611 return mBouncer.shouldDismissOnMenuPressed();
Jorim Jaggi8c8bcc12014-04-16 21:36:51 +0200612 }
Jorim Jaggidf993512014-05-13 23:06:35 +0200613
614 public boolean interceptMediaKey(KeyEvent event) {
615 return mBouncer.interceptMediaKey(event);
616 }
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200617
Jorim Jaggife762342016-10-13 14:33:27 +0200618 public void readyForKeyguardDone() {
619 mViewMediatorCallback.readyForKeyguardDone();
620 }
621
Jorim Jaggi84a3e7a2014-08-13 17:58:58 +0200622 public boolean shouldDisableWindowAnimationsForUnlock() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500623 return mStatusBar.isInLaunchTransition();
Jorim Jaggi84a3e7a2014-08-13 17:58:58 +0200624 }
625
626 public boolean isGoingToNotificationShade() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500627 return mStatusBar.isGoingToNotificationShade();
Jorim Jaggi84a3e7a2014-08-13 17:58:58 +0200628 }
Adrian Roos31b844b2014-11-21 13:55:09 +0100629
630 public boolean isSecure(int userId) {
631 return mBouncer.isSecure() || mLockPatternUtils.isSecure(userId);
632 }
Jim Millerab954542014-10-10 18:21:49 -0700633
Jorim Jaggi33ae80e2015-02-04 16:37:11 +0100634 public void keyguardGoingAway() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500635 mStatusBar.keyguardGoingAway();
Jorim Jaggi33ae80e2015-02-04 16:37:11 +0100636 }
Jim Miller25d7e512015-03-03 17:12:09 -0800637
Jorim Jaggif3b3bee2015-04-16 14:57:34 -0700638 public void animateCollapsePanels(float speedUpFactor) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500639 mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
Jorim Jaggif3b3bee2015-04-16 14:57:34 -0700640 false /* delayed */, speedUpFactor);
Jim Miller25d7e512015-03-03 17:12:09 -0800641 }
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700642
643 /**
644 * Notifies that the user has authenticated by other means than using the bouncer, for example,
645 * fingerprint.
646 */
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700647 public void notifyKeyguardAuthenticated(boolean strongAuth) {
648 mBouncer.notifyKeyguardAuthenticated(strongAuth);
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700649 }
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700650
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700651 public void showBouncerMessage(String message, int color) {
652 mBouncer.showMessage(message, color);
653 }
Jorim Jaggib774e552015-08-24 14:52:45 -0700654
655 public ViewRootImpl getViewRootImpl() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500656 return mStatusBar.getStatusBarView().getViewRootImpl();
Jorim Jaggib774e552015-08-24 14:52:45 -0700657 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100658}