blob: 3074e33c46a80a6f69212fe3ec50f93140aa76e2 [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;
Jorim Jaggidf993512014-05-13 23:06:35 +020030import android.view.KeyEvent;
Jorim Jaggi03c701e2014-04-02 12:39:51 +020031import android.view.LayoutInflater;
32import android.view.View;
33import android.view.ViewGroup;
Adrian Roosedfa96f2016-01-29 12:46:35 -080034import android.view.ViewTreeObserver;
Lucas Dupin6865b712017-09-11 12:28:03 -070035import android.view.WindowInsets;
Jorim Jaggi03c701e2014-04-02 12:39:51 +020036
Jorim Jaggi03c701e2014-04-02 12:39:51 +020037import com.android.internal.widget.LockPatternUtils;
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +010038import com.android.keyguard.KeyguardHostView;
Dave Mankofff44b13a2019-10-03 17:29:58 -040039import com.android.keyguard.KeyguardSecurityModel;
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.ViewMediatorCallback;
Jorim Jaggi86b273f2015-07-14 18:08:43 -070044import com.android.systemui.DejankUtils;
Dave Mankofff44b13a2019-10-03 17:29:58 -040045import com.android.systemui.Dependency;
Hyunyoung Song8f9d34c2019-08-30 14:47:43 -070046import com.android.systemui.R;
Jorim Jaggi241ae102016-11-02 21:57:33 -070047import com.android.systemui.keyguard.DismissCallbackRegistry;
Dave Mankoff468d4f62019-05-08 14:56:29 -040048import com.android.systemui.plugins.FalsingManager;
Muhammad Qureshi9bced7d2020-01-16 15:22:12 -080049import com.android.systemui.shared.system.SysUiStatsLog;
Lucas Dupinc8f16e82019-09-17 18:24:50 -040050import com.android.systemui.statusbar.policy.KeyguardStateController;
Jorim Jaggi03c701e2014-04-02 12:39:51 +020051
Lucas Dupin15a6b6c2018-04-16 14:50:20 +080052import java.io.PrintWriter;
53
Jorim Jaggi03c701e2014-04-02 12:39:51 +020054/**
55 * A class which manages the bouncer on the lockscreen.
56 */
57public class KeyguardBouncer {
58
Lucas Dupinbc9aac12018-03-04 20:18:15 -080059 private static final String TAG = "KeyguardBouncer";
Lucas Dupin7825b942019-06-03 20:22:39 -070060 static final long BOUNCER_FACE_DELAY = 1200;
Lucas Dupinbc9aac12018-03-04 20:18:15 -080061 static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
Lucas Dupinf9ca35e2018-05-16 20:41:35 -070062 static final float EXPANSION_HIDDEN = 1f;
63 static final float EXPANSION_VISIBLE = 0f;
Toni Barzic657f8852016-02-04 15:14:49 -080064
Jorim Jaggi241ae102016-11-02 21:57:33 -070065 protected final Context mContext;
66 protected final ViewMediatorCallback mCallback;
67 protected final LockPatternUtils mLockPatternUtils;
68 protected final ViewGroup mContainer;
69 private final FalsingManager mFalsingManager;
70 private final DismissCallbackRegistry mDismissCallbackRegistry;
Jorim Jaggifabc7432017-05-15 02:40:05 +020071 private final Handler mHandler;
Lucas Dupin15a6b6c2018-04-16 14:50:20 +080072 private final BouncerExpansionCallback mExpansionCallback;
Lucas Dupin787f9a02019-04-24 14:56:52 -070073 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Lucas Dupinc8f16e82019-09-17 18:24:50 -040074 private final KeyguardStateController mKeyguardStateController;
Jorim Jaggi241ae102016-11-02 21:57:33 -070075 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -070076 new KeyguardUpdateMonitorCallback() {
77 @Override
Adrian Roos1de8bcb2015-08-19 16:52:52 -070078 public void onStrongAuthStateChanged(int userId) {
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -070079 mBouncerPromptReason = mCallback.getBouncerPromptReason();
80 }
81 };
Jorim Jaggifabc7432017-05-15 02:40:05 +020082 private final Runnable mRemoveViewRunnable = this::removeView;
Lucas Dupin055ef942019-08-15 11:41:52 -070083 private final KeyguardBypassController mKeyguardBypassController;
Lucas Dupin70659002018-04-30 15:56:52 -070084 protected KeyguardHostView mKeyguardView;
85 private final Runnable mResetRunnable = ()-> {
86 if (mKeyguardView != null) {
Lucas Dupin80180492018-05-08 17:06:06 -070087 mKeyguardView.resetSecurityContainer();
Lucas Dupin70659002018-04-30 15:56:52 -070088 }
89 };
Lucas Dupin3d565fa2018-03-20 15:40:14 -070090
Selim Cinekcb3d45a2017-09-08 18:00:18 -070091 private int mStatusBarHeight;
Lucas Dupin70659002018-04-30 15:56:52 -070092 private float mExpansion = EXPANSION_HIDDEN;
Lucas Dupin3d565fa2018-03-20 15:40:14 -070093 protected ViewGroup mRoot;
94 private boolean mShowingSoon;
95 private int mBouncerPromptReason;
Lucas Dupin28dc9d72018-03-21 15:59:15 -070096 private boolean mIsAnimatingAway;
Lucas Dupinf9ca35e2018-05-16 20:41:35 -070097 private boolean mIsScrimmed;
Jorim Jaggi03c701e2014-04-02 12:39:51 +020098
99 public KeyguardBouncer(Context context, ViewMediatorCallback callback,
Jorim Jaggi241ae102016-11-02 21:57:33 -0700100 LockPatternUtils lockPatternUtils, ViewGroup container,
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800101 DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400102 BouncerExpansionCallback expansionCallback,
103 KeyguardStateController keyguardStateController,
Lucas Dupin055ef942019-08-15 11:41:52 -0700104 KeyguardUpdateMonitor keyguardUpdateMonitor,
105 KeyguardBypassController keyguardBypassController, Handler handler) {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200106 mContext = context;
107 mCallback = callback;
108 mLockPatternUtils = lockPatternUtils;
109 mContainer = container;
Lucas Dupin787f9a02019-04-24 14:56:52 -0700110 mKeyguardUpdateMonitor = keyguardUpdateMonitor;
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700111 mFalsingManager = falsingManager;
Jorim Jaggi241ae102016-11-02 21:57:33 -0700112 mDismissCallbackRegistry = dismissCallbackRegistry;
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800113 mExpansionCallback = expansionCallback;
Lucas Dupin787f9a02019-04-24 14:56:52 -0700114 mHandler = handler;
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400115 mKeyguardStateController = keyguardStateController;
Lucas Dupin787f9a02019-04-24 14:56:52 -0700116 mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
Lucas Dupin055ef942019-08-15 11:41:52 -0700117 mKeyguardBypassController = keyguardBypassController;
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200118 }
119
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100120 public void show(boolean resetSecuritySelection) {
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700121 show(resetSecuritySelection, true /* scrimmed */);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800122 }
123
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700124 /**
125 * Shows the bouncer.
126 *
127 * @param resetSecuritySelection Cleans keyguard view
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700128 * @param isScrimmed true when the bouncer show show scrimmed, false when the user will be
129 * dragging it and translation should be deferred.
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700130 */
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700131 public void show(boolean resetSecuritySelection, boolean isScrimmed) {
Vadim Tryshevec018432016-02-10 14:11:03 -0800132 final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
133 if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
134 // In split system user mode, we never unlock system user.
135 return;
136 }
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200137 ensureView();
Lucas Dupin93f714d2019-03-26 16:49:24 -0700138 mIsScrimmed = isScrimmed;
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800139
140 // On the keyguard, we want to show the bouncer when the user drags up, but it's
141 // not correct to end the falsing session. We still need to verify if those touches
142 // are valid.
143 // Later, at the end of the animation, when the bouncer is at the top of the screen,
144 // onFullyShown() will be called and FalsingManager will stop recording touches.
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700145 if (isScrimmed) {
Lucas Dupin70659002018-04-30 15:56:52 -0700146 setExpansion(EXPANSION_VISIBLE);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800147 }
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700148
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100149 if (resetSecuritySelection) {
150 // showPrimarySecurityScreen() updates the current security method. This is needed in
151 // case we are already showing and the current security method changed.
Lucas Dupin27321c42019-03-20 16:22:24 -0700152 showPrimarySecurityScreen();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100153 }
Lucas Dupin93f714d2019-03-26 16:49:24 -0700154
Jorim Jaggi416493b2014-09-13 03:57:32 +0200155 if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200156 return;
157 }
Jorim Jaggi0bed7f22014-04-03 16:12:54 +0200158
Selim Cinek1a891a92017-12-04 17:41:27 +0100159 final int activeUserId = KeyguardUpdateMonitor.getCurrentUser();
Xiaohui Chend743cef2016-10-03 09:55:53 -0700160 final boolean isSystemUser =
161 UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
162 final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
163
Toni Barzic657f8852016-02-04 15:14:49 -0800164 // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
165 // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700166 if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {
Toni Barzic657f8852016-02-04 15:14:49 -0800167 return;
Jorim Jaggi416493b2014-09-13 03:57:32 +0200168 }
Toni Barzic657f8852016-02-04 15:14:49 -0800169
170 // This condition may indicate an error on Android, so log it.
171 if (!allowDismissKeyguard) {
172 Slog.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != " + keyguardUserId);
173 }
174
175 mShowingSoon = true;
176
177 // Split up the work over multiple frames.
Lucas Dupin70659002018-04-30 15:56:52 -0700178 DejankUtils.removeCallbacks(mResetRunnable);
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400179 if (mKeyguardStateController.isFaceAuthEnabled() && !needsFullscreenBouncer()
Lucas Dupin055ef942019-08-15 11:41:52 -0700180 && !mKeyguardUpdateMonitor.userNeedsStrongAuth()
181 && !mKeyguardBypassController.getBypassEnabled()) {
Lucas Dupin787f9a02019-04-24 14:56:52 -0700182 mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
183 } else {
184 DejankUtils.postAfterTraversal(mShowRunnable);
185 }
Matthew Ng66f0b702017-12-08 12:58:42 -0800186
187 mCallback.onBouncerVisiblityChanged(true /* shown */);
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700188 mExpansionCallback.onStartingToShow();
Jorim Jaggi416493b2014-09-13 03:57:32 +0200189 }
190
Lucas Dupin93f714d2019-03-26 16:49:24 -0700191 public boolean isScrimmed() {
192 return mIsScrimmed;
Lucas Dupinf9ca35e2018-05-16 20:41:35 -0700193 }
194
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800195 /**
196 * This method must be called at the end of the bouncer animation when
197 * the translation is performed manually by the user, otherwise FalsingManager
198 * will never be notified and its internal state will be out of sync.
199 */
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800200 private void onFullyShown() {
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800201 mFalsingManager.onBouncerShown();
Lucas Dupind2ce46d2018-04-04 17:00:29 -0700202 if (mKeyguardView == null) {
203 Log.wtf(TAG, "onFullyShown when view was null");
204 } else {
205 mKeyguardView.onResume();
206 }
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800207 }
208
209 /**
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800210 * @see #onFullyShown()
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800211 */
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800212 private void onFullyHidden() {
Lucas Dupin9b8e5e32019-07-24 16:36:14 -0700213 cancelShowRunnable();
214 if (mRoot != null) {
215 mRoot.setVisibility(View.INVISIBLE);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800216 }
Lucas Dupin9b8e5e32019-07-24 16:36:14 -0700217 mFalsingManager.onBouncerHidden();
218 DejankUtils.postAfterTraversal(mResetRunnable);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800219 }
220
Jorim Jaggi416493b2014-09-13 03:57:32 +0200221 private final Runnable mShowRunnable = new Runnable() {
222 @Override
223 public void run() {
Jorim Jaggi0bed7f22014-04-03 16:12:54 +0200224 mRoot.setVisibility(View.VISIBLE);
Selim Cinek3122fa82015-06-18 01:38:59 -0700225 showPromptReason(mBouncerPromptReason);
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800226 final CharSequence customMessage = mCallback.consumeCustomMessage();
227 if (customMessage != null) {
228 mKeyguardView.showErrorMessage(customMessage);
229 }
Selim Cinekcb3d45a2017-09-08 18:00:18 -0700230 // We might still be collapsed and the view didn't have time to layout yet or still
231 // be small, let's wait on the predraw to do the animation in that case.
232 if (mKeyguardView.getHeight() != 0 && mKeyguardView.getHeight() != mStatusBarHeight) {
Adrian Roosedfa96f2016-01-29 12:46:35 -0800233 mKeyguardView.startAppearAnimation();
234 } else {
235 mKeyguardView.getViewTreeObserver().addOnPreDrawListener(
236 new ViewTreeObserver.OnPreDrawListener() {
237 @Override
238 public boolean onPreDraw() {
239 mKeyguardView.getViewTreeObserver().removeOnPreDrawListener(this);
240 mKeyguardView.startAppearAnimation();
241 return true;
242 }
243 });
244 mKeyguardView.requestLayout();
245 }
Jorim Jaggi416493b2014-09-13 03:57:32 +0200246 mShowingSoon = false;
Lucas Dupin70659002018-04-30 15:56:52 -0700247 if (mExpansion == EXPANSION_VISIBLE) {
248 mKeyguardView.onResume();
Wang, ArvinXa2d94c52018-09-12 11:31:32 +0800249 mKeyguardView.resetSecurityContainer();
Lucas Dupin70659002018-04-30 15:56:52 -0700250 }
Muhammad Qureshi9bced7d2020-01-16 15:22:12 -0800251 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
252 SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN);
Jorim Jaggi0bed7f22014-04-03 16:12:54 +0200253 }
Jorim Jaggi416493b2014-09-13 03:57:32 +0200254 };
255
Selim Cinek3122fa82015-06-18 01:38:59 -0700256 /**
257 * Show a string explaining why the security view needs to be solved.
258 *
259 * @param reason a flag indicating which string should be shown, see
260 * {@link KeyguardSecurityView#PROMPT_REASON_NONE}
261 * and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
262 */
263 public void showPromptReason(int reason) {
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700264 if (mKeyguardView != null) {
265 mKeyguardView.showPromptReason(reason);
266 } else {
267 Log.w(TAG, "Trying to show prompt reason on empty bouncer");
268 }
Selim Cinek3122fa82015-06-18 01:38:59 -0700269 }
270
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800271 public void showMessage(String message, ColorStateList colorState) {
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700272 if (mKeyguardView != null) {
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800273 mKeyguardView.showMessage(message, colorState);
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700274 } else {
275 Log.w(TAG, "Trying to show message on empty bouncer");
276 }
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700277 }
278
Jorim Jaggi416493b2014-09-13 03:57:32 +0200279 private void cancelShowRunnable() {
Jorim Jaggi86b273f2015-07-14 18:08:43 -0700280 DejankUtils.removeCallbacks(mShowRunnable);
Lucas Dupin787f9a02019-04-24 14:56:52 -0700281 mHandler.removeCallbacks(mShowRunnable);
Jorim Jaggi416493b2014-09-13 03:57:32 +0200282 mShowingSoon = false;
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200283 }
284
Jorim Jaggid9449862015-05-29 14:49:08 -0700285 public void showWithDismissAction(OnDismissAction r, Runnable cancelAction) {
Adrian Roos7d7090d2014-05-21 13:10:23 +0200286 ensureView();
Jorim Jaggid9449862015-05-29 14:49:08 -0700287 mKeyguardView.setOnDismissAction(r, cancelAction);
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100288 show(false /* resetSecuritySelection */);
Adrian Roos7d7090d2014-05-21 13:10:23 +0200289 }
290
Jorim Jaggia0be6d52014-05-26 03:01:13 +0200291 public void hide(boolean destroyView) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700292 if (isShowing()) {
Muhammad Qureshi9bced7d2020-01-16 15:22:12 -0800293 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
294 SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
Jorim Jaggi241ae102016-11-02 21:57:33 -0700295 mDismissCallbackRegistry.notifyDismissCancelled();
296 }
Lucas Dupin93f714d2019-03-26 16:49:24 -0700297 mIsScrimmed = false;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700298 mFalsingManager.onBouncerHidden();
Matthew Ng66f0b702017-12-08 12:58:42 -0800299 mCallback.onBouncerVisiblityChanged(false /* shown */);
Jorim Jaggi416493b2014-09-13 03:57:32 +0200300 cancelShowRunnable();
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800301 if (mKeyguardView != null) {
Jorim Jaggid9449862015-05-29 14:49:08 -0700302 mKeyguardView.cancelDismissAction();
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200303 mKeyguardView.cleanUp();
304 }
Lucas Dupin28dc9d72018-03-21 15:59:15 -0700305 mIsAnimatingAway = false;
Jorim Jaggifabc7432017-05-15 02:40:05 +0200306 if (mRoot != null) {
Jorim Jaggia0be6d52014-05-26 03:01:13 +0200307 mRoot.setVisibility(View.INVISIBLE);
Jorim Jaggifabc7432017-05-15 02:40:05 +0200308 if (destroyView) {
309
310 // We have a ViewFlipper that unregisters a broadcast when being detached, which may
311 // be slow because of AM lock contention during unlocking. We can delay it a bit.
312 mHandler.postDelayed(mRemoveViewRunnable, 50);
313 }
Jorim Jaggia0be6d52014-05-26 03:01:13 +0200314 }
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200315 }
316
Jorim Jaggi76a16232014-08-08 17:00:47 +0200317 /**
318 * See {@link StatusBarKeyguardViewManager#startPreHideAnimation}.
319 */
320 public void startPreHideAnimation(Runnable runnable) {
Lucas Dupin28dc9d72018-03-21 15:59:15 -0700321 mIsAnimatingAway = true;
Jorim Jaggi76a16232014-08-08 17:00:47 +0200322 if (mKeyguardView != null) {
323 mKeyguardView.startDisappearAnimation(runnable);
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200324 } else if (runnable != null) {
Jorim Jaggi76a16232014-08-08 17:00:47 +0200325 runnable.run();
Jorim Jaggie29b2db2014-05-30 23:17:03 +0200326 }
327 }
328
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200329 /**
330 * Reset the state of the view.
331 */
332 public void reset() {
Jorim Jaggi416493b2014-09-13 03:57:32 +0200333 cancelShowRunnable();
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200334 inflateView();
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700335 mFalsingManager.onBouncerHidden();
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200336 }
337
338 public void onScreenTurnedOff() {
Dan Sandler9ee256d2014-04-21 12:05:00 -0400339 if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200340 mKeyguardView.onPause();
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200341 }
342 }
343
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200344 public boolean isShowing() {
Lucas Dupin3d565fa2018-03-20 15:40:14 -0700345 return (mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE))
Lucas Dupin70659002018-04-30 15:56:52 -0700346 && mExpansion == EXPANSION_VISIBLE && !isAnimatingAway();
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200347 }
348
Lucas Dupin28dc9d72018-03-21 15:59:15 -0700349 /**
Lucas Dupinb7d32742019-07-12 17:46:11 +0900350 * {@link #show(boolean)} was called but we're not showing yet, or being dragged.
Lucas Dupinfa817a02019-07-02 15:22:54 -0700351 */
Lucas Dupinb7d32742019-07-12 17:46:11 +0900352 public boolean inTransit() {
Lucas Dupin273832d2019-07-23 13:44:12 -0700353 return mShowingSoon || mExpansion != EXPANSION_HIDDEN && mExpansion != EXPANSION_VISIBLE;
Lucas Dupinfa817a02019-07-02 15:22:54 -0700354 }
355
356 /**
Lucas Dupin28dc9d72018-03-21 15:59:15 -0700357 * @return {@code true} when bouncer's pre-hide animation already started but isn't completely
358 * hidden yet, {@code false} otherwise.
359 */
360 public boolean isAnimatingAway() {
361 return mIsAnimatingAway;
362 }
363
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200364 public void prepare() {
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100365 boolean wasInitialized = mRoot != null;
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200366 ensureView();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100367 if (wasInitialized) {
Lucas Dupin27321c42019-03-20 16:22:24 -0700368 showPrimarySecurityScreen();
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100369 }
Jorim Jaggi86b273f2015-07-14 18:08:43 -0700370 mBouncerPromptReason = mCallback.getBouncerPromptReason();
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200371 }
372
Lucas Dupin27321c42019-03-20 16:22:24 -0700373 private void showPrimarySecurityScreen() {
374 mKeyguardView.showPrimarySecurityScreen();
Lucas Dupin27321c42019-03-20 16:22:24 -0700375 }
376
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800377 /**
378 * Current notification panel expansion
379 * @param fraction 0 when notification panel is collapsed and 1 when expanded.
380 * @see StatusBarKeyguardViewManager#onPanelExpansionChanged
381 */
382 public void setExpansion(float fraction) {
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800383 float oldExpansion = mExpansion;
Lucas Dupin3d565fa2018-03-20 15:40:14 -0700384 mExpansion = fraction;
Lucas Dupin28dc9d72018-03-21 15:59:15 -0700385 if (mKeyguardView != null && !mIsAnimatingAway) {
Lucas Dupin0df9b7a2018-03-15 17:53:17 -0700386 float alpha = MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
387 mKeyguardView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800388 mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
389 }
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800390
Lucas Dupin70659002018-04-30 15:56:52 -0700391 if (fraction == EXPANSION_VISIBLE && oldExpansion != EXPANSION_VISIBLE) {
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800392 onFullyShown();
393 mExpansionCallback.onFullyShown();
Lucas Dupin70659002018-04-30 15:56:52 -0700394 } else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800395 onFullyHidden();
396 mExpansionCallback.onFullyHidden();
Lucas Dupin84993542018-10-11 19:23:45 -0700397 } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
398 mExpansionCallback.onStartingToHide();
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800399 }
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800400 }
401
Lucas Dupin6f0d71f2018-03-23 17:26:06 -0700402 public boolean willDismissWithAction() {
403 return mKeyguardView != null && mKeyguardView.hasDismissActions();
404 }
405
Lucas Dupin4c2aa392018-03-28 18:00:45 -0700406 public int getTop() {
407 if (mKeyguardView == null) {
408 return 0;
409 }
410
411 int top = mKeyguardView.getTop();
412 // The password view has an extra top padding that should be ignored.
413 if (mKeyguardView.getCurrentSecurityMode() == SecurityMode.Password) {
414 View messageArea = mKeyguardView.findViewById(R.id.keyguard_message_area);
415 top += messageArea.getTop();
416 }
417 return top;
418 }
419
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800420 protected void ensureView() {
Lucas Dupinf190a852017-07-31 17:11:26 -0700421 // Removal of the view might be deferred to reduce unlock latency,
422 // in this case we need to force the removal, otherwise we'll
423 // end up in an unpredictable state.
424 boolean forceRemoval = mHandler.hasCallbacks(mRemoveViewRunnable);
425 if (mRoot == null || forceRemoval) {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200426 inflateView();
427 }
428 }
429
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800430 protected void inflateView() {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200431 removeView();
Jorim Jaggifabc7432017-05-15 02:40:05 +0200432 mHandler.removeCallbacks(mRemoveViewRunnable);
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200433 mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
Lucas Dupin6865b712017-09-11 12:28:03 -0700434 mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view);
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200435 mKeyguardView.setLockPatternUtils(mLockPatternUtils);
436 mKeyguardView.setViewMediatorCallback(mCallback);
437 mContainer.addView(mRoot, mContainer.getChildCount());
Selim Cinekcb3d45a2017-09-08 18:00:18 -0700438 mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset(
439 com.android.systemui.R.dimen.status_bar_height);
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200440 mRoot.setVisibility(View.INVISIBLE);
Phil Weaver7d847b02018-02-13 16:02:35 -0800441 mRoot.setAccessibilityPaneTitle(mKeyguardView.getAccessibilityTitleForCurrentMode());
Lucas Dupin6865b712017-09-11 12:28:03 -0700442
443 final WindowInsets rootInsets = mRoot.getRootWindowInsets();
444 if (rootInsets != null) {
445 mRoot.dispatchApplyWindowInsets(rootInsets);
446 }
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200447 }
448
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800449 protected void removeView() {
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200450 if (mRoot != null && mRoot.getParent() == mContainer) {
451 mContainer.removeView(mRoot);
452 mRoot = null;
453 }
454 }
Jorim Jaggie5c7a892014-04-10 20:37:32 +0200455
456 public boolean onBackPressed() {
457 return mKeyguardView != null && mKeyguardView.handleBackKey();
458 }
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200459
460 /**
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100461 * @return True if and only if the security method should be shown before showing the
462 * notifications on Keyguard, like SIM PIN/PUK.
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200463 */
464 public boolean needsFullscreenBouncer() {
Dave Mankofff44b13a2019-10-03 17:29:58 -0400465 SecurityMode mode = Dependency.get(KeyguardSecurityModel.class).getSecurityMode(
466 KeyguardUpdateMonitor.getCurrentUser());
467 return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100468 }
469
470 /**
471 * Like {@link #needsFullscreenBouncer}, but uses the currently visible security method, which
472 * makes this method much faster.
473 */
474 public boolean isFullscreenBouncer() {
475 if (mKeyguardView != null) {
476 SecurityMode mode = mKeyguardView.getCurrentSecurityMode();
477 return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
Jorim Jaggia005f1b2014-04-16 19:06:10 +0200478 }
479 return false;
480 }
Jorim Jaggi8c8bcc12014-04-16 21:36:51 +0200481
Christoph Studer2231c6e2014-12-19 12:40:13 +0100482 /**
483 * WARNING: This method might cause Binder calls.
484 */
Jorim Jaggi15682502014-04-23 12:01:36 +0200485 public boolean isSecure() {
486 return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None;
487 }
488
Selim Cinek28540192016-02-19 17:25:08 -0800489 public boolean shouldDismissOnMenuPressed() {
490 return mKeyguardView.shouldEnableMenuKey();
Jorim Jaggi8c8bcc12014-04-16 21:36:51 +0200491 }
Jorim Jaggidf993512014-05-13 23:06:35 +0200492
493 public boolean interceptMediaKey(KeyEvent event) {
494 ensureView();
495 return mKeyguardView.interceptMediaKey(event);
496 }
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700497
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700498 public void notifyKeyguardAuthenticated(boolean strongAuth) {
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700499 ensureView();
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700500 mKeyguardView.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser());
Jorim Jaggi5cc86592015-06-08 14:48:28 -0700501 }
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800502
503 public void dump(PrintWriter pw) {
504 pw.println("KeyguardBouncer");
505 pw.println(" isShowing(): " + isShowing());
506 pw.println(" mStatusBarHeight: " + mStatusBarHeight);
507 pw.println(" mExpansion: " + mExpansion);
508 pw.println(" mKeyguardView; " + mKeyguardView);
509 pw.println(" mShowingSoon: " + mKeyguardView);
510 pw.println(" mBouncerPromptReason: " + mBouncerPromptReason);
511 pw.println(" mIsAnimatingAway: " + mIsAnimatingAway);
512 }
513
514 public interface BouncerExpansionCallback {
515 void onFullyShown();
Lucas Dupin84993542018-10-11 19:23:45 -0700516 void onStartingToHide();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700517 void onStartingToShow();
Lucas Dupin15a6b6c2018-04-16 14:50:20 +0800518 void onFullyHidden();
519 }
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200520}