blob: 98704de612dbab183902554130484e92a30ce17d [file] [log] [blame]
Jorim Jaggi03c701e2014-04-02 12:39:51 +02001/*
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
Lucas Dupin0df9b7a2018-03-15 17:53:17 -070019import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
Gus Prevasab336792018-11-14 13:52:20 -050020import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
Lucas Dupin0df9b7a2018-03-15 17:53:17 -070021
Jorim Jaggi03c701e2014-04-02 12:39:51 +020022import android.content.Context;
Jason Chang1e4a4bd2018-05-22 17:30:19 +080023import android.content.res.ColorStateList;
Jorim Jaggifabc7432017-05-15 02:40:05 +020024import android.os.Handler;
Toni Barzic657f8852016-02-04 15:14:49 -080025import android.os.UserHandle;
Toni Barzicb799d3f2016-02-17 15:09:10 -080026import android.os.UserManager;
Lucas Dupin0df9b7a2018-03-15 17:53:17 -070027import android.util.Log;
Lucas Dupinbc9aac12018-03-04 20:18:15 -080028import android.util.MathUtils;
Toni Barzic657f8852016-02-04 15:14:49 -080029import android.util.Slog;
Tej Singhdd7bd352018-02-09 19:33:15 -080030import android.util.StatsLog;
Jorim Jaggidf993512014-05-13 23:06:35 +020031import android.view.KeyEvent;
Jorim Jaggi03c701e2014-04-02 12:39:51 +020032import android.view.LayoutInflater;
33import android.view.View;
34import android.view.ViewGroup;
Adrian Roosedfa96f2016-01-29 12:46:35 -080035import android.view.ViewTreeObserver;
Lucas Dupin6865b712017-09-11 12:28:03 -070036import android.view.WindowInsets;
Jorim Jaggi03c701e2014-04-02 12:39:51 +020037
Jorim Jaggi03c701e2014-04-02 12:39:51 +020038import com.android.internal.widget.LockPatternUtils;
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +010039import com.android.keyguard.KeyguardHostView;
Selim Cinek3122fa82015-06-18 01:38:59 -070040import com.android.keyguard.KeyguardSecurityView;
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -070041import com.android.keyguard.KeyguardUpdateMonitor;
42import com.android.keyguard.KeyguardUpdateMonitorCallback;
Jorim Jaggi03c701e2014-04-02 12:39:51 +020043import com.android.keyguard.R;
44import com.android.keyguard.ViewMediatorCallback;
Jorim Jaggi86b273f2015-07-14 18:08:43 -070045import com.android.systemui.DejankUtils;
Jorim Jaggi241ae102016-11-02 21:57:33 -070046import com.android.systemui.keyguard.DismissCallbackRegistry;
Dave Mankoff468d4f62019-05-08 14:56:29 -040047import com.android.systemui.plugins.FalsingManager;
Jorim Jaggi03c701e2014-04-02 12:39:51 +020048
Lucas Dupin15a6b6c2018-04-16 14:50:20 +080049import java.io.PrintWriter;
50
Jorim Jaggi03c701e2014-04-02 12:39:51 +020051/**
52 * A class which manages the bouncer on the lockscreen.
53 */
54public class KeyguardBouncer {
55
Lucas Dupinbc9aac12018-03-04 20:18:15 -080056 private static final String TAG = "KeyguardBouncer";
Lucas Dupin7825b942019-06-03 20:22:39 -070057 static final long BOUNCER_FACE_DELAY = 1200;
Lucas Dupinbc9aac12018-03-04 20:18:15 -080058 static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
Lucas Dupinf9ca35e2018-05-16 20:41:35 -070059 static final float EXPANSION_HIDDEN = 1f;
60 static final float EXPANSION_VISIBLE = 0f;
Toni Barzic657f8852016-02-04 15:14:49 -080061
Jorim Jaggi241ae102016-11-02 21:57:33 -070062 protected final Context mContext;
63 protected final ViewMediatorCallback mCallback;
64 protected final LockPatternUtils mLockPatternUtils;
65 protected final ViewGroup mContainer;
66 private final FalsingManager mFalsingManager;
67 private final DismissCallbackRegistry mDismissCallbackRegistry;
Jorim Jaggifabc7432017-05-15 02:40:05 +020068 private final Handler mHandler;
Lucas Dupin15a6b6c2018-04-16 14:50:20 +080069 private final BouncerExpansionCallback mExpansionCallback;
Lucas Dupin787f9a02019-04-24 14:56:52 -070070 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Lucas Dupin7825b942019-06-03 20:22:39 -070071 private final UnlockMethodCache mUnlockMethodCache;
Jorim Jaggi241ae102016-11-02 21:57:33 -070072 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -070073 new KeyguardUpdateMonitorCallback() {
74 @Override
Adrian Roos1de8bcb2015-08-19 16:52:52 -070075 public void onStrongAuthStateChanged(int userId) {
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -070076 mBouncerPromptReason = mCallback.getBouncerPromptReason();
77 }
78 };
Jorim Jaggifabc7432017-05-15 02:40:05 +020079 private final Runnable mRemoveViewRunnable = this::removeView;
Lucas Dupin70659002018-04-30 15:56:52 -070080 protected KeyguardHostView mKeyguardView;
81 private final Runnable mResetRunnable = ()-> {
82 if (mKeyguardView != null) {
Lucas Dupin80180492018-05-08 17:06:06 -070083 mKeyguardView.resetSecurityContainer();
Lucas Dupin70659002018-04-30 15:56:52 -070084 }
85 };
Lucas Dupin3d565fa2018-03-20 15:40:14 -070086
Selim Cinekcb3d45a2017-09-08 18:00:18 -070087 private int mStatusBarHeight;
Lucas Dupin70659002018-04-30 15:56:52 -070088 private float mExpansion = EXPANSION_HIDDEN;
Lucas Dupin3d565fa2018-03-20 15:40:14 -070089 protected ViewGroup mRoot;
90 private boolean mShowingSoon;
91 private int mBouncerPromptReason;
Lucas Dupin28dc9d72018-03-21 15:59:15 -070092 private boolean mIsAnimatingAway;
Lucas Dupinf9ca35e2018-05-16 20:41:35 -070093 private boolean mIsScrimmed;
Lucas Dupin407cc582019-03-11 21:04:31 -070094 private ViewGroup mLockIconContainer;
Jorim Jaggi03c701e2014-04-02 12:39:51 +020095
96 public KeyguardBouncer(Context context, ViewMediatorCallback callback,
Jorim Jaggi241ae102016-11-02 21:57:33 -070097 LockPatternUtils lockPatternUtils, ViewGroup container,
Lucas Dupin15a6b6c2018-04-16 14:50:20 +080098 DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
Lucas Dupin7825b942019-06-03 20:22:39 -070099 BouncerExpansionCallback expansionCallback, UnlockMethodCache unlockMethodCache,
Lucas Dupin787f9a02019-04-24 14:56:52 -0700100 KeyguardUpdateMonitor keyguardUpdateMonitor, Handler handler) {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200101 mContext = context;
102 mCallback = callback;
103 mLockPatternUtils = lockPatternUtils;
104 mContainer = container;
Lucas Dupin787f9a02019-04-24 14:56:52 -0700105 mKeyguardUpdateMonitor = keyguardUpdateMonitor;
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700106 mFalsingManager = falsingManager;
Jorim Jaggi241ae102016-11-02 21:57:33 -0700107 mDismissCallbackRegistry = dismissCallbackRegistry;
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800108 mExpansionCallback = expansionCallback;
Lucas Dupin787f9a02019-04-24 14:56:52 -0700109 mHandler = handler;
Lucas Dupin7825b942019-06-03 20:22:39 -0700110 mUnlockMethodCache = unlockMethodCache;
Lucas Dupin787f9a02019-04-24 14:56:52 -0700111 mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200112 }
113
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100114 public void show(boolean resetSecuritySelection) {
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700115 show(resetSecuritySelection, true /* scrimmed */);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800116 }
117
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700118 /**
119 * Shows the bouncer.
120 *
121 * @param resetSecuritySelection Cleans keyguard view
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700122 * @param isScrimmed true when the bouncer show show scrimmed, false when the user will be
123 * dragging it and translation should be deferred.
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700124 */
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700125 public void show(boolean resetSecuritySelection, boolean isScrimmed) {
Vadim Tryshevec018432016-02-10 14:11:03 -0800126 final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
127 if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
128 // In split system user mode, we never unlock system user.
129 return;
130 }
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200131 ensureView();
Lucas Dupin93f714d2019-03-26 16:49:24 -0700132 mIsScrimmed = isScrimmed;
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800133
134 // On the keyguard, we want to show the bouncer when the user drags up, but it's
135 // not correct to end the falsing session. We still need to verify if those touches
136 // are valid.
137 // Later, at the end of the animation, when the bouncer is at the top of the screen,
138 // onFullyShown() will be called and FalsingManager will stop recording touches.
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700139 if (isScrimmed) {
Lucas Dupin70659002018-04-30 15:56:52 -0700140 setExpansion(EXPANSION_VISIBLE);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800141 }
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700142
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100143 if (resetSecuritySelection) {
144 // showPrimarySecurityScreen() updates the current security method. This is needed in
145 // case we are already showing and the current security method changed.
Lucas Dupin27321c42019-03-20 16:22:24 -0700146 showPrimarySecurityScreen();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100147 }
Lucas Dupin93f714d2019-03-26 16:49:24 -0700148
Jorim Jaggi416493b2014-09-13 03:57:32 +0200149 if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200150 return;
151 }
Jorim Jaggi0bed7f22014-04-03 16:12:54 +0200152
Selim Cinek1a891a92017-12-04 17:41:27 +0100153 final int activeUserId = KeyguardUpdateMonitor.getCurrentUser();
Xiaohui Chend743cef2016-10-03 09:55:53 -0700154 final boolean isSystemUser =
155 UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
156 final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
157
Toni Barzic657f8852016-02-04 15:14:49 -0800158 // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
159 // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700160 if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {
Toni Barzic657f8852016-02-04 15:14:49 -0800161 return;
Jorim Jaggi416493b2014-09-13 03:57:32 +0200162 }
Toni Barzic657f8852016-02-04 15:14:49 -0800163
164 // This condition may indicate an error on Android, so log it.
165 if (!allowDismissKeyguard) {
166 Slog.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != " + keyguardUserId);
167 }
168
169 mShowingSoon = true;
170
171 // Split up the work over multiple frames.
Lucas Dupin70659002018-04-30 15:56:52 -0700172 DejankUtils.removeCallbacks(mResetRunnable);
Lucas Dupin4c507042019-07-22 16:47:34 -0700173 if (mUnlockMethodCache.isFaceAuthEnabled() && !needsFullscreenBouncer()
Lucas Dupin7825b942019-06-03 20:22:39 -0700174 && !mKeyguardUpdateMonitor.userNeedsStrongAuth()) {
Lucas Dupin787f9a02019-04-24 14:56:52 -0700175 mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
176 } else {
177 DejankUtils.postAfterTraversal(mShowRunnable);
178 }
Matthew Ng66f0b702017-12-08 12:58:42 -0800179
180 mCallback.onBouncerVisiblityChanged(true /* shown */);
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700181 mExpansionCallback.onStartingToShow();
Jorim Jaggi416493b2014-09-13 03:57:32 +0200182 }
183
Lucas Dupin93f714d2019-03-26 16:49:24 -0700184 public boolean isScrimmed() {
185 return mIsScrimmed;
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700186 }
187
Lucas Dupin407cc582019-03-11 21:04:31 -0700188 public ViewGroup getLockIconContainer() {
189 return mRoot == null || mRoot.getVisibility() != View.VISIBLE ? null : mLockIconContainer;
190 }
191
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800192 /**
193 * This method must be called at the end of the bouncer animation when
194 * the translation is performed manually by the user, otherwise FalsingManager
195 * will never be notified and its internal state will be out of sync.
196 */
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800197 private void onFullyShown() {
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800198 mFalsingManager.onBouncerShown();
Lucas Dupind2ce46d2018-04-04 17:00:29 -0700199 if (mKeyguardView == null) {
200 Log.wtf(TAG, "onFullyShown when view was null");
201 } else {
202 mKeyguardView.onResume();
203 }
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800204 }
205
206 /**
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800207 * @see #onFullyShown()
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800208 */
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800209 private void onFullyHidden() {
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800210 if (!mShowingSoon) {
211 cancelShowRunnable();
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700212 if (mRoot != null) {
213 mRoot.setVisibility(View.INVISIBLE);
214 }
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800215 mFalsingManager.onBouncerHidden();
Lucas Dupin70659002018-04-30 15:56:52 -0700216 DejankUtils.postAfterTraversal(mResetRunnable);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800217 }
218 }
219
Jorim Jaggi416493b2014-09-13 03:57:32 +0200220 private final Runnable mShowRunnable = new Runnable() {
221 @Override
222 public void run() {
Jorim Jaggi0bed7f22014-04-03 16:12:54 +0200223 mRoot.setVisibility(View.VISIBLE);
Selim Cinek3122fa82015-06-18 01:38:59 -0700224 showPromptReason(mBouncerPromptReason);
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800225 final CharSequence customMessage = mCallback.consumeCustomMessage();
226 if (customMessage != null) {
227 mKeyguardView.showErrorMessage(customMessage);
228 }
Selim Cinekcb3d45a2017-09-08 18:00:18 -0700229 // We might still be collapsed and the view didn't have time to layout yet or still
230 // be small, let's wait on the predraw to do the animation in that case.
231 if (mKeyguardView.getHeight() != 0 && mKeyguardView.getHeight() != mStatusBarHeight) {
Adrian Roosedfa96f2016-01-29 12:46:35 -0800232 mKeyguardView.startAppearAnimation();
233 } else {
234 mKeyguardView.getViewTreeObserver().addOnPreDrawListener(
235 new ViewTreeObserver.OnPreDrawListener() {
236 @Override
237 public boolean onPreDraw() {
238 mKeyguardView.getViewTreeObserver().removeOnPreDrawListener(this);
239 mKeyguardView.startAppearAnimation();
240 return true;
241 }
242 });
243 mKeyguardView.requestLayout();
244 }
Jorim Jaggi416493b2014-09-13 03:57:32 +0200245 mShowingSoon = false;
Lucas Dupin70659002018-04-30 15:56:52 -0700246 if (mExpansion == EXPANSION_VISIBLE) {
247 mKeyguardView.onResume();
Wang, ArvinXa2d94c52018-09-12 11:31:32 +0800248 mKeyguardView.resetSecurityContainer();
Lucas Dupin70659002018-04-30 15:56:52 -0700249 }
Tej Singhdd7bd352018-02-09 19:33:15 -0800250 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
251 StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN);
Jorim Jaggi0bed7f22014-04-03 16:12:54 +0200252 }
Jorim Jaggi416493b2014-09-13 03:57:32 +0200253 };
254
Selim Cinek3122fa82015-06-18 01:38:59 -0700255 /**
256 * Show a string explaining why the security view needs to be solved.
257 *
258 * @param reason a flag indicating which string should be shown, see
259 * {@link KeyguardSecurityView#PROMPT_REASON_NONE}
260 * and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
261 */
262 public void showPromptReason(int reason) {
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700263 if (mKeyguardView != null) {
264 mKeyguardView.showPromptReason(reason);
265 } else {
266 Log.w(TAG, "Trying to show prompt reason on empty bouncer");
267 }
Selim Cinek3122fa82015-06-18 01:38:59 -0700268 }
269
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800270 public void showMessage(String message, ColorStateList colorState) {
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700271 if (mKeyguardView != null) {
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800272 mKeyguardView.showMessage(message, colorState);
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700273 } else {
274 Log.w(TAG, "Trying to show message on empty bouncer");
275 }
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700276 }
277
Jorim Jaggi416493b2014-09-13 03:57:32 +0200278 private void cancelShowRunnable() {
Jorim Jaggi86b273f2015-07-14 18:08:43 -0700279 DejankUtils.removeCallbacks(mShowRunnable);
Lucas Dupin787f9a02019-04-24 14:56:52 -0700280 mHandler.removeCallbacks(mShowRunnable);
Jorim Jaggi416493b2014-09-13 03:57:32 +0200281 mShowingSoon = false;
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200282 }
283
Jorim Jaggid9449862015-05-29 14:49:08 -0700284 public void showWithDismissAction(OnDismissAction r, Runnable cancelAction) {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200285 ensureView();
Jorim Jaggid9449862015-05-29 14:49:08 -0700286 mKeyguardView.setOnDismissAction(r, cancelAction);
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100287 show(false /* resetSecuritySelection */);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200288 }
289
Jorim Jaggia0be6d52014-05-26 03:01:13 +0200290 public void hide(boolean destroyView) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700291 if (isShowing()) {
Tej Singhdd7bd352018-02-09 19:33:15 -0800292 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
293 StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
Jorim Jaggi241ae102016-11-02 21:57:33 -0700294 mDismissCallbackRegistry.notifyDismissCancelled();
295 }
Lucas Dupin93f714d2019-03-26 16:49:24 -0700296 mIsScrimmed = false;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700297 mFalsingManager.onBouncerHidden();
Matthew Ng66f0b702017-12-08 12:58:42 -0800298 mCallback.onBouncerVisiblityChanged(false /* shown */);
Jorim Jaggi416493b2014-09-13 03:57:32 +0200299 cancelShowRunnable();
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800300 if (mKeyguardView != null) {
Jorim Jaggid9449862015-05-29 14:49:08 -0700301 mKeyguardView.cancelDismissAction();
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200302 mKeyguardView.cleanUp();
303 }
Lucas Dupin28dc9d72018-03-21 15:59:15 -0700304 mIsAnimatingAway = false;
Jorim Jaggifabc7432017-05-15 02:40:05 +0200305 if (mRoot != null) {
Jorim Jaggia0be6d52014-05-26 03:01:13 +0200306 mRoot.setVisibility(View.INVISIBLE);
Jorim Jaggifabc7432017-05-15 02:40:05 +0200307 if (destroyView) {
308
309 // We have a ViewFlipper that unregisters a broadcast when being detached, which may
310 // be slow because of AM lock contention during unlocking. We can delay it a bit.
311 mHandler.postDelayed(mRemoveViewRunnable, 50);
312 }
Jorim Jaggia0be6d52014-05-26 03:01:13 +0200313 }
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200314 }
315
Jorim Jaggi76a16232014-08-08 17:00:47 +0200316 /**
317 * See {@link StatusBarKeyguardViewManager#startPreHideAnimation}.
318 */
319 public void startPreHideAnimation(Runnable runnable) {
Lucas Dupin28dc9d72018-03-21 15:59:15 -0700320 mIsAnimatingAway = true;
Jorim Jaggi76a16232014-08-08 17:00:47 +0200321 if (mKeyguardView != null) {
322 mKeyguardView.startDisappearAnimation(runnable);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200323 } else if (runnable != null) {
Jorim Jaggi76a16232014-08-08 17:00:47 +0200324 runnable.run();
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200325 }
326 }
327
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200328 /**
329 * Reset the state of the view.
330 */
331 public void reset() {
Jorim Jaggi416493b2014-09-13 03:57:32 +0200332 cancelShowRunnable();
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200333 inflateView();
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700334 mFalsingManager.onBouncerHidden();
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200335 }
336
337 public void onScreenTurnedOff() {
Dan Sandler9ee256d2014-04-21 12:05:00 -0400338 if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200339 mKeyguardView.onPause();
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200340 }
341 }
342
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200343 public boolean isShowing() {
Lucas Dupin3d565fa2018-03-20 15:40:14 -0700344 return (mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE))
Lucas Dupin70659002018-04-30 15:56:52 -0700345 && mExpansion == EXPANSION_VISIBLE && !isAnimatingAway();
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200346 }
347
Lucas Dupin28dc9d72018-03-21 15:59:15 -0700348 /**
Lucas Dupinb7d32742019-07-12 17:46:11 +0900349 * {@link #show(boolean)} was called but we're not showing yet, or being dragged.
Lucas Dupinfa817a02019-07-02 15:22:54 -0700350 */
Lucas Dupinb7d32742019-07-12 17:46:11 +0900351 public boolean inTransit() {
352 return mShowingSoon || mExpansion != EXPANSION_HIDDEN;
Lucas Dupinfa817a02019-07-02 15:22:54 -0700353 }
354
355 /**
Lucas Dupin28dc9d72018-03-21 15:59:15 -0700356 * @return {@code true} when bouncer's pre-hide animation already started but isn't completely
357 * hidden yet, {@code false} otherwise.
358 */
359 public boolean isAnimatingAway() {
360 return mIsAnimatingAway;
361 }
362
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200363 public void prepare() {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100364 boolean wasInitialized = mRoot != null;
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200365 ensureView();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100366 if (wasInitialized) {
Lucas Dupin27321c42019-03-20 16:22:24 -0700367 showPrimarySecurityScreen();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100368 }
Jorim Jaggi86b273f2015-07-14 18:08:43 -0700369 mBouncerPromptReason = mCallback.getBouncerPromptReason();
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200370 }
371
Lucas Dupin27321c42019-03-20 16:22:24 -0700372 private void showPrimarySecurityScreen() {
373 mKeyguardView.showPrimarySecurityScreen();
374 KeyguardSecurityView keyguardSecurityView = mKeyguardView.getCurrentSecurityView();
375 if (keyguardSecurityView != null) {
376 mLockIconContainer = ((ViewGroup) keyguardSecurityView)
377 .findViewById(R.id.lock_icon_container);
378 }
379 }
380
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800381 /**
382 * Current notification panel expansion
383 * @param fraction 0 when notification panel is collapsed and 1 when expanded.
384 * @see StatusBarKeyguardViewManager#onPanelExpansionChanged
385 */
386 public void setExpansion(float fraction) {
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800387 float oldExpansion = mExpansion;
Lucas Dupin3d565fa2018-03-20 15:40:14 -0700388 mExpansion = fraction;
Lucas Dupin28dc9d72018-03-21 15:59:15 -0700389 if (mKeyguardView != null && !mIsAnimatingAway) {
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700390 float alpha = MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
391 mKeyguardView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800392 mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
393 }
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800394
Lucas Dupin70659002018-04-30 15:56:52 -0700395 if (fraction == EXPANSION_VISIBLE && oldExpansion != EXPANSION_VISIBLE) {
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800396 onFullyShown();
397 mExpansionCallback.onFullyShown();
Lucas Dupin70659002018-04-30 15:56:52 -0700398 } else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800399 onFullyHidden();
400 mExpansionCallback.onFullyHidden();
Lucas Dupin84993542018-10-11 19:23:45 -0700401 } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
402 mExpansionCallback.onStartingToHide();
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800403 }
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800404 }
405
Lucas Dupin6f0d71f2018-03-23 17:26:06 -0700406 public boolean willDismissWithAction() {
407 return mKeyguardView != null && mKeyguardView.hasDismissActions();
408 }
409
Lucas Dupin4c2aa392018-03-28 18:00:45 -0700410 public int getTop() {
411 if (mKeyguardView == null) {
412 return 0;
413 }
414
415 int top = mKeyguardView.getTop();
416 // The password view has an extra top padding that should be ignored.
417 if (mKeyguardView.getCurrentSecurityMode() == SecurityMode.Password) {
418 View messageArea = mKeyguardView.findViewById(R.id.keyguard_message_area);
419 top += messageArea.getTop();
420 }
421 return top;
422 }
423
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800424 protected void ensureView() {
Lucas Dupinf190a852017-07-31 17:11:26 -0700425 // Removal of the view might be deferred to reduce unlock latency,
426 // in this case we need to force the removal, otherwise we'll
427 // end up in an unpredictable state.
428 boolean forceRemoval = mHandler.hasCallbacks(mRemoveViewRunnable);
429 if (mRoot == null || forceRemoval) {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200430 inflateView();
431 }
432 }
433
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800434 protected void inflateView() {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200435 removeView();
Jorim Jaggifabc7432017-05-15 02:40:05 +0200436 mHandler.removeCallbacks(mRemoveViewRunnable);
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200437 mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
Lucas Dupin6865b712017-09-11 12:28:03 -0700438 mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view);
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200439 mKeyguardView.setLockPatternUtils(mLockPatternUtils);
440 mKeyguardView.setViewMediatorCallback(mCallback);
441 mContainer.addView(mRoot, mContainer.getChildCount());
Selim Cinekcb3d45a2017-09-08 18:00:18 -0700442 mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset(
443 com.android.systemui.R.dimen.status_bar_height);
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200444 mRoot.setVisibility(View.INVISIBLE);
Phil Weaver7d847b02018-02-13 16:02:35 -0800445 mRoot.setAccessibilityPaneTitle(mKeyguardView.getAccessibilityTitleForCurrentMode());
Lucas Dupin6865b712017-09-11 12:28:03 -0700446
447 final WindowInsets rootInsets = mRoot.getRootWindowInsets();
448 if (rootInsets != null) {
449 mRoot.dispatchApplyWindowInsets(rootInsets);
450 }
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200451 }
452
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800453 protected void removeView() {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200454 if (mRoot != null && mRoot.getParent() == mContainer) {
455 mContainer.removeView(mRoot);
456 mRoot = null;
457 }
458 }
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200459
460 public boolean onBackPressed() {
461 return mKeyguardView != null && mKeyguardView.handleBackKey();
462 }
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200463
464 /**
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100465 * @return True if and only if the security method should be shown before showing the
466 * notifications on Keyguard, like SIM PIN/PUK.
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200467 */
468 public boolean needsFullscreenBouncer() {
Selim Cinekedd32b82015-06-23 22:05:58 -0400469 ensureView();
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200470 if (mKeyguardView != null) {
471 SecurityMode mode = mKeyguardView.getSecurityMode();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100472 return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
473 }
474 return false;
475 }
476
477 /**
478 * Like {@link #needsFullscreenBouncer}, but uses the currently visible security method, which
479 * makes this method much faster.
480 */
481 public boolean isFullscreenBouncer() {
482 if (mKeyguardView != null) {
483 SecurityMode mode = mKeyguardView.getCurrentSecurityMode();
484 return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200485 }
486 return false;
487 }
Jorim Jaggi8c8bcc12014-04-16 21:36:51 +0200488
Christoph Studer2231c6e2014-12-19 12:40:13 +0100489 /**
490 * WARNING: This method might cause Binder calls.
491 */
Jorim Jaggi15682502014-04-23 12:01:36 +0200492 public boolean isSecure() {
493 return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None;
494 }
495
Selim Cinek28540192016-02-19 17:25:08 -0800496 public boolean shouldDismissOnMenuPressed() {
497 return mKeyguardView.shouldEnableMenuKey();
Jorim Jaggi8c8bcc12014-04-16 21:36:51 +0200498 }
Jorim Jaggidf993512014-05-13 23:06:35 +0200499
500 public boolean interceptMediaKey(KeyEvent event) {
501 ensureView();
502 return mKeyguardView.interceptMediaKey(event);
503 }
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700504
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700505 public void notifyKeyguardAuthenticated(boolean strongAuth) {
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700506 ensureView();
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700507 mKeyguardView.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser());
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700508 }
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800509
510 public void dump(PrintWriter pw) {
511 pw.println("KeyguardBouncer");
512 pw.println(" isShowing(): " + isShowing());
513 pw.println(" mStatusBarHeight: " + mStatusBarHeight);
514 pw.println(" mExpansion: " + mExpansion);
515 pw.println(" mKeyguardView; " + mKeyguardView);
516 pw.println(" mShowingSoon: " + mKeyguardView);
517 pw.println(" mBouncerPromptReason: " + mBouncerPromptReason);
518 pw.println(" mIsAnimatingAway: " + mIsAnimatingAway);
519 }
520
521 public interface BouncerExpansionCallback {
522 void onFullyShown();
Lucas Dupin84993542018-10-11 19:23:45 -0700523 void onStartingToHide();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700524 void onStartingToShow();
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800525 void onFullyHidden();
526 }
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200527}