blob: 72592325c511f68e9915299c66264caa982d9a80 [file] [log] [blame]
Jim Miller5a8daad2014-01-14 18:57:03 -08001/*
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 */
Jim Miller5ecd8112013-01-09 18:50:26 -080016package com.android.keyguard;
Jim Miller838906b2012-10-19 18:41:25 -070017
Jim Miller7751ff62014-01-14 18:57:03 -080018import android.app.Activity;
19import android.app.AlertDialog;
Amith Yamasani3a3d2122014-10-29 11:41:31 -070020import android.app.admin.DevicePolicyManager;
Jim Miller838906b2012-10-19 18:41:25 -070021import android.content.Context;
Jason Chang1e4a4bd2018-05-22 17:30:19 +080022import android.content.res.ColorStateList;
Lucas Dupin3ac28ac2019-05-13 16:33:32 -070023import android.graphics.Rect;
Steven Wu6ef24b22019-03-11 17:14:11 -040024import android.metrics.LogMaker;
Amith Yamasani3a3d2122014-10-29 11:41:31 -070025import android.os.UserHandle;
Jim Miller838906b2012-10-19 18:41:25 -070026import android.util.AttributeSet;
Jim Miller7751ff62014-01-14 18:57:03 -080027import android.util.Log;
28import android.util.Slog;
Tej Singhdd7bd352018-02-09 19:33:15 -080029import android.util.StatsLog;
Lucas Dupin7156bc72019-05-03 19:37:39 -070030import android.util.TypedValue;
Jim Miller7751ff62014-01-14 18:57:03 -080031import android.view.LayoutInflater;
Lucas Dupin7156bc72019-05-03 19:37:39 -070032import android.view.MotionEvent;
33import android.view.VelocityTracker;
Chris Wren052999f2012-11-02 14:36:56 -040034import android.view.View;
Lucas Dupin7156bc72019-05-03 19:37:39 -070035import android.view.ViewConfiguration;
Jim Miller7751ff62014-01-14 18:57:03 -080036import android.view.WindowManager;
Jim Miller838906b2012-10-19 18:41:25 -070037import android.widget.FrameLayout;
38
Gus Prevasab336792018-11-14 13:52:20 -050039import androidx.annotation.VisibleForTesting;
Lucas Dupin7156bc72019-05-03 19:37:39 -070040import androidx.dynamicanimation.animation.DynamicAnimation;
41import androidx.dynamicanimation.animation.SpringAnimation;
Gus Prevasab336792018-11-14 13:52:20 -050042
Steven Wu6ef24b22019-03-11 17:14:11 -040043import com.android.internal.logging.MetricsLogger;
44import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jim Miller7751ff62014-01-14 18:57:03 -080045import com.android.internal.widget.LockPatternUtils;
46import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
Steven Wu6ef24b22019-03-11 17:14:11 -040047import com.android.systemui.Dependency;
Priyank Singh051353e2019-04-25 10:14:57 -070048import com.android.systemui.SystemUIFactory;
49import com.android.systemui.util.InjectionInflationController;
Jim Miller7751ff62014-01-14 18:57:03 -080050
51public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
Jorim Jaggi5cf17872014-03-26 18:31:48 +010052 private static final boolean DEBUG = KeyguardConstants.DEBUG;
Jim Miller7751ff62014-01-14 18:57:03 -080053 private static final String TAG = "KeyguardSecurityView";
Amith Yamasani3a3d2122014-10-29 11:41:31 -070054
55 private static final int USER_TYPE_PRIMARY = 1;
56 private static final int USER_TYPE_WORK_PROFILE = 2;
57 private static final int USER_TYPE_SECONDARY_USER = 3;
58
Steven Wucfe398d2019-03-21 11:32:15 -040059 // Bouncer is dismissed due to no security.
60 private static final int BOUNCER_DISMISS_NONE_SECURITY = 0;
61 // Bouncer is dismissed due to pin, password or pattern entered.
62 private static final int BOUNCER_DISMISS_PASSWORD = 1;
63 // Bouncer is dismissed due to biometric (face, fingerprint or iris) authenticated.
64 private static final int BOUNCER_DISMISS_BIOMETRIC = 2;
65 // Bouncer is dismissed due to extended access granted.
66 private static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3;
67 // Bouncer is dismissed due to sim card unlock code entered.
68 private static final int BOUNCER_DISMISS_SIM = 4;
69
Lucas Dupin7156bc72019-05-03 19:37:39 -070070 // Make the view move slower than the finger, as if the spring were applying force.
71 private static final float TOUCH_Y_MULTIPLIER = 0.25f;
72 // How much you need to drag the bouncer to trigger an auth retry (in dps.)
73 private static final float MIN_DRAG_SIZE = 10;
74
Jim Miller7751ff62014-01-14 18:57:03 -080075 private KeyguardSecurityModel mSecurityModel;
Jim Miller7751ff62014-01-14 18:57:03 -080076 private LockPatternUtils mLockPatternUtils;
77
78 private KeyguardSecurityViewFlipper mSecurityViewFlipper;
79 private boolean mIsVerifyUnlockOnly;
80 private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
Lucas Dupin27321c42019-03-20 16:22:24 -070081 private KeyguardSecurityView mCurrentSecurityView;
Jim Miller7751ff62014-01-14 18:57:03 -080082 private SecurityCallback mSecurityCallback;
Lucas Dupin7f729822017-12-13 15:27:10 -080083 private AlertDialog mAlertDialog;
Priyank Singh051353e2019-04-25 10:14:57 -070084 private InjectionInflationController mInjectionInflationController;
Lucas Dupin7156bc72019-05-03 19:37:39 -070085 private boolean mSwipeUpToRetry;
Jim Miller7751ff62014-01-14 18:57:03 -080086
Lucas Dupin7156bc72019-05-03 19:37:39 -070087 private final ViewConfiguration mViewConfiguration;
88 private final SpringAnimation mSpringAnimation;
89 private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
Adrian Roos336be7f2014-05-19 17:11:18 +020090 private final KeyguardUpdateMonitor mUpdateMonitor;
91
Steven Wu6ef24b22019-03-11 17:14:11 -040092 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
Lucas Dupin7156bc72019-05-03 19:37:39 -070093 private float mLastTouchY = -1;
94 private int mActivePointerId = -1;
95 private boolean mIsDragging;
96 private float mStartTouchY = -1;
Steven Wu6ef24b22019-03-11 17:14:11 -040097
Jim Miller7751ff62014-01-14 18:57:03 -080098 // Used to notify the container when something interesting happens.
99 public interface SecurityCallback {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700100 public boolean dismiss(boolean authenticated, int targetUserId);
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200101 public void userActivity();
Jim Millerba7d94b2014-02-05 17:30:50 -0800102 public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700103
104 /**
105 * @param strongAuth wheher the user has authenticated with strong authentication like
106 * pattern, password or PIN but not by trust agents or fingerprint
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700107 * @param targetUserId a user that needs to be the foreground user at the finish completion.
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700108 */
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700109 public void finish(boolean strongAuth, int targetUserId);
Andrew Lee72b46d42015-01-30 13:23:21 -0800110 public void reset();
Aarthi Balachander0a427ef2018-07-13 15:00:58 -0700111 public void onCancelClicked();
Jim Miller7751ff62014-01-14 18:57:03 -0800112 }
113
Jim Miller838906b2012-10-19 18:41:25 -0700114 public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
115 this(context, attrs, 0);
116 }
117
118 public KeyguardSecurityContainer(Context context) {
Esteban Talaverafe0f24c2014-08-06 16:20:56 +0100119 this(context, null, 0);
Jim Miller838906b2012-10-19 18:41:25 -0700120 }
121
122 public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
Lucas Dupin987f1932017-05-13 21:02:52 -0700123 super(context, attrs, defStyle);
Jim Miller7751ff62014-01-14 18:57:03 -0800124 mSecurityModel = new KeyguardSecurityModel(context);
125 mLockPatternUtils = new LockPatternUtils(context);
Adrian Roos336be7f2014-05-19 17:11:18 +0200126 mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Lucas Dupin7156bc72019-05-03 19:37:39 -0700127 mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
Priyank Singh051353e2019-04-25 10:14:57 -0700128 mInjectionInflationController = new InjectionInflationController(
129 SystemUIFactory.getInstance().getRootComponent());
Lucas Dupin7156bc72019-05-03 19:37:39 -0700130 mViewConfiguration = ViewConfiguration.get(context);
Chris Wrenc3451462012-10-30 11:22:58 -0400131 }
132
Jim Miller7751ff62014-01-14 18:57:03 -0800133 public void setSecurityCallback(SecurityCallback callback) {
134 mSecurityCallback = callback;
135 }
136
137 @Override
138 public void onResume(int reason) {
Jorim Jaggif4797922014-08-04 22:49:41 +0200139 if (mCurrentSecuritySelection != SecurityMode.None) {
140 getSecurityView(mCurrentSecuritySelection).onResume(reason);
141 }
Lucas Dupin7156bc72019-05-03 19:37:39 -0700142 updateBiometricRetry();
Jim Miller7751ff62014-01-14 18:57:03 -0800143 }
144
145 @Override
146 public void onPause() {
Lucas Dupin7f729822017-12-13 15:27:10 -0800147 if (mAlertDialog != null) {
148 mAlertDialog.dismiss();
149 mAlertDialog = null;
150 }
Jorim Jaggif4797922014-08-04 22:49:41 +0200151 if (mCurrentSecuritySelection != SecurityMode.None) {
152 getSecurityView(mCurrentSecuritySelection).onPause();
153 }
Jim Miller7751ff62014-01-14 18:57:03 -0800154 }
155
Lucas Dupin7156bc72019-05-03 19:37:39 -0700156 @Override
157 public boolean shouldDelayChildPressedState() {
158 return true;
159 }
160
161 @Override
162 public boolean onInterceptTouchEvent(MotionEvent event) {
163 switch (event.getActionMasked()) {
164 case MotionEvent.ACTION_DOWN:
165 int pointerIndex = event.getActionIndex();
166 mStartTouchY = event.getY(pointerIndex);
167 mActivePointerId = event.getPointerId(pointerIndex);
168 mVelocityTracker.clear();
169 break;
170 case MotionEvent.ACTION_MOVE:
171 if (mIsDragging) {
172 return true;
173 }
174 if (!mSwipeUpToRetry) {
175 return false;
176 }
177 // Avoid dragging the pattern view
178 if (mCurrentSecurityView.disallowInterceptTouch(event)) {
179 return false;
180 }
181 int index = event.findPointerIndex(mActivePointerId);
182 int touchSlop = mViewConfiguration.getScaledTouchSlop();
Lucas Dupinc26ab7512019-05-13 13:49:17 -0700183 if (mCurrentSecurityView != null && index != -1
Lucas Dupin7156bc72019-05-03 19:37:39 -0700184 && mStartTouchY - event.getY(index) > touchSlop) {
185 mIsDragging = true;
186 return true;
187 }
188 break;
189 case MotionEvent.ACTION_CANCEL:
190 case MotionEvent.ACTION_UP:
191 mIsDragging = false;
192 break;
193 }
194 return false;
195 }
196
197 @Override
198 public boolean onTouchEvent(MotionEvent event) {
199 final int action = event.getActionMasked();
200 switch (action) {
201 case MotionEvent.ACTION_MOVE:
202 mVelocityTracker.addMovement(event);
203 int pointerIndex = event.findPointerIndex(mActivePointerId);
204 float y = event.getY(pointerIndex);
205 if (mLastTouchY != -1) {
206 float dy = y - mLastTouchY;
207 setTranslationY(getTranslationY() + dy * TOUCH_Y_MULTIPLIER);
208 }
209 mLastTouchY = y;
210 break;
211 case MotionEvent.ACTION_UP:
212 case MotionEvent.ACTION_CANCEL:
213 mActivePointerId = -1;
214 mLastTouchY = -1;
215 mIsDragging = false;
216 startSpringAnimation(mVelocityTracker.getYVelocity());
217 break;
218 case MotionEvent.ACTION_POINTER_UP:
219 int index = event.getActionIndex();
220 int pointerId = event.getPointerId(index);
221 if (pointerId == mActivePointerId) {
222 // This was our active pointer going up. Choose a new
223 // active pointer and adjust accordingly.
224 final int newPointerIndex = index == 0 ? 1 : 0;
225 mLastTouchY = event.getY(newPointerIndex);
226 mActivePointerId = event.getPointerId(newPointerIndex);
227 }
228 break;
229 }
230 if (action == MotionEvent.ACTION_UP) {
231 if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
Lucas Dupin51996bb2019-05-16 17:56:43 -0700232 MIN_DRAG_SIZE, getResources().getDisplayMetrics())
233 && !mUpdateMonitor.isFaceDetectionRunning()) {
Lucas Dupin7156bc72019-05-03 19:37:39 -0700234 mUpdateMonitor.requestFaceAuth();
Lucas Dupin51996bb2019-05-16 17:56:43 -0700235 showMessage(null, null);
Lucas Dupin7156bc72019-05-03 19:37:39 -0700236 }
237 }
238 return true;
239 }
240
241 private void startSpringAnimation(float startVelocity) {
242 mSpringAnimation
243 .setStartVelocity(startVelocity)
244 .animateToFinalPosition(0);
245 }
246
Jorim Jaggic14f8292014-05-27 02:25:45 +0200247 public void startAppearAnimation() {
Jorim Jaggif4797922014-08-04 22:49:41 +0200248 if (mCurrentSecuritySelection != SecurityMode.None) {
249 getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
250 }
Jorim Jaggic14f8292014-05-27 02:25:45 +0200251 }
252
Jorim Jaggi76a16232014-08-08 17:00:47 +0200253 public boolean startDisappearAnimation(Runnable onFinishRunnable) {
254 if (mCurrentSecuritySelection != SecurityMode.None) {
255 return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation(
256 onFinishRunnable);
257 }
258 return false;
259 }
260
Lucas Dupin7156bc72019-05-03 19:37:39 -0700261 /**
262 * Enables/disables swipe up to retry on the bouncer.
263 */
264 private void updateBiometricRetry() {
265 SecurityMode securityMode = getSecurityMode();
266 int userId = KeyguardUpdateMonitor.getCurrentUser();
267 mSwipeUpToRetry = mUpdateMonitor.isUnlockWithFacePossible(userId)
268 && securityMode != SecurityMode.SimPin
269 && securityMode != SecurityMode.SimPuk
270 && securityMode != SecurityMode.None;
271 }
272
Phil Weaver7d847b02018-02-13 16:02:35 -0800273 public CharSequence getTitle() {
274 return mSecurityViewFlipper.getTitle();
Jorim Jaggic1dff8c2015-02-02 14:45:39 +0100275 }
276
Jim Miller7751ff62014-01-14 18:57:03 -0800277 private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
278 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
279 KeyguardSecurityView view = null;
280 final int children = mSecurityViewFlipper.getChildCount();
281 for (int child = 0; child < children; child++) {
282 if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
283 view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
284 break;
285 }
286 }
287 int layoutId = getLayoutIdFor(securityMode);
288 if (view == null && layoutId != 0) {
289 final LayoutInflater inflater = LayoutInflater.from(mContext);
290 if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
Priyank Singh051353e2019-04-25 10:14:57 -0700291 View v = mInjectionInflationController.injectable(inflater)
292 .inflate(layoutId, mSecurityViewFlipper, false);
Jim Miller7751ff62014-01-14 18:57:03 -0800293 mSecurityViewFlipper.addView(v);
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100294 updateSecurityView(v);
Jim Miller7751ff62014-01-14 18:57:03 -0800295 view = (KeyguardSecurityView)v;
Lucas Dupinf7fd03d2018-06-26 15:58:51 -0700296 view.reset();
Jim Miller7751ff62014-01-14 18:57:03 -0800297 }
298
Jim Miller7751ff62014-01-14 18:57:03 -0800299 return view;
300 }
301
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100302 private void updateSecurityView(View view) {
Jim Miller7751ff62014-01-14 18:57:03 -0800303 if (view instanceof KeyguardSecurityView) {
304 KeyguardSecurityView ksv = (KeyguardSecurityView) view;
305 ksv.setKeyguardCallback(mCallback);
306 ksv.setLockPatternUtils(mLockPatternUtils);
Jim Miller7751ff62014-01-14 18:57:03 -0800307 } else {
308 Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
309 }
310 }
311
312 protected void onFinishInflate() {
Alan Viverette51efddb2017-04-05 10:00:01 -0400313 mSecurityViewFlipper = findViewById(R.id.view_flipper);
Jim Miller7751ff62014-01-14 18:57:03 -0800314 mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
315 }
316
317 public void setLockPatternUtils(LockPatternUtils utils) {
318 mLockPatternUtils = utils;
319 mSecurityModel.setLockPatternUtils(utils);
320 mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
321 }
322
Lucas Dupin7156bc72019-05-03 19:37:39 -0700323 @Override
Lucas Dupin3ac28ac2019-05-13 16:33:32 -0700324 protected boolean fitSystemWindows(Rect insets) {
325 // Consume bottom insets because we're setting the padding locally (for IME and navbar.)
326 setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), insets.bottom);
327 insets.bottom = 0;
328 return false;
Lucas Dupin7156bc72019-05-03 19:37:39 -0700329 }
330
Jim Miller7751ff62014-01-14 18:57:03 -0800331 private void showDialog(String title, String message) {
Lucas Dupin7f729822017-12-13 15:27:10 -0800332 if (mAlertDialog != null) {
333 mAlertDialog.dismiss();
334 }
335
336 mAlertDialog = new AlertDialog.Builder(mContext)
Jim Miller7751ff62014-01-14 18:57:03 -0800337 .setTitle(title)
338 .setMessage(message)
Edward Savage-Jonesb08a1462016-10-05 10:29:02 +0200339 .setCancelable(false)
Jim Miller7751ff62014-01-14 18:57:03 -0800340 .setNeutralButton(R.string.ok, null)
341 .create();
342 if (!(mContext instanceof Activity)) {
Lucas Dupin7f729822017-12-13 15:27:10 -0800343 mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
Jim Miller7751ff62014-01-14 18:57:03 -0800344 }
Lucas Dupin7f729822017-12-13 15:27:10 -0800345 mAlertDialog.show();
Jim Miller7751ff62014-01-14 18:57:03 -0800346 }
347
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700348 private void showTimeoutDialog(int userId, int timeoutMs) {
Andres Morales23974272015-05-14 22:42:26 -0700349 int timeoutInSeconds = (int) timeoutMs / 1000;
Jim Miller7751ff62014-01-14 18:57:03 -0800350 int messageId = 0;
351
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700352 switch (mSecurityModel.getSecurityMode(userId)) {
Jim Miller7751ff62014-01-14 18:57:03 -0800353 case Pattern:
354 messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
355 break;
356 case PIN:
357 messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message;
358 break;
359 case Password:
360 messageId = R.string.kg_too_many_failed_password_attempts_dialog_message;
361 break;
362 // These don't have timeout dialogs.
Jim Miller7751ff62014-01-14 18:57:03 -0800363 case Invalid:
364 case None:
365 case SimPin:
366 case SimPuk:
367 break;
368 }
369
370 if (messageId != 0) {
371 final String message = mContext.getString(messageId,
Pavel Grafovb90dc432018-08-15 20:02:58 +0100372 mLockPatternUtils.getCurrentFailedPasswordAttempts(userId),
Jim Miller7751ff62014-01-14 18:57:03 -0800373 timeoutInSeconds);
374 showDialog(null, message);
375 }
376 }
377
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700378 private void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
379 String message = null;
380 switch (userType) {
381 case USER_TYPE_PRIMARY:
382 message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe,
383 attempts, remaining);
384 break;
385 case USER_TYPE_SECONDARY_USER:
386 message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_user,
387 attempts, remaining);
388 break;
389 case USER_TYPE_WORK_PROFILE:
390 message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_profile,
391 attempts, remaining);
392 break;
393 }
Jim Miller7751ff62014-01-14 18:57:03 -0800394 showDialog(null, message);
395 }
396
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700397 private void showWipeDialog(int attempts, int userType) {
398 String message = null;
399 switch (userType) {
400 case USER_TYPE_PRIMARY:
401 message = mContext.getString(R.string.kg_failed_attempts_now_wiping,
402 attempts);
403 break;
404 case USER_TYPE_SECONDARY_USER:
405 message = mContext.getString(R.string.kg_failed_attempts_now_erasing_user,
406 attempts);
407 break;
408 case USER_TYPE_WORK_PROFILE:
409 message = mContext.getString(R.string.kg_failed_attempts_now_erasing_profile,
410 attempts);
411 break;
412 }
Jim Miller7751ff62014-01-14 18:57:03 -0800413 showDialog(null, message);
414 }
415
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800416 private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
Pavel Grafovb90dc432018-08-15 20:02:58 +0100417 // +1 for this time
418 final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
Jim Miller7751ff62014-01-14 18:57:03 -0800419
420 if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
421
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700422 final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
423 final int failedAttemptsBeforeWipe =
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800424 dpm.getMaximumFailedPasswordsForWipe(null, userId);
Jim Miller7751ff62014-01-14 18:57:03 -0800425
Jim Miller7751ff62014-01-14 18:57:03 -0800426 final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
427 (failedAttemptsBeforeWipe - failedAttempts)
428 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
Jim Miller7751ff62014-01-14 18:57:03 -0800429 if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
Esteban Talaverafe0f24c2014-08-06 16:20:56 +0100430 // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
431 // N attempts. Once we get below the grace period, we post this dialog every time as a
432 // clear warning until the deletion fires.
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700433 // Check which profile has the strictest policy for failed password attempts
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800434 final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700435 int userType = USER_TYPE_PRIMARY;
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800436 if (expiringUser == userId) {
Xiaohui Chencc791bc2015-08-26 14:54:34 -0700437 // TODO: http://b/23522538
438 if (expiringUser != UserHandle.USER_SYSTEM) {
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700439 userType = USER_TYPE_SECONDARY_USER;
440 }
441 } else if (expiringUser != UserHandle.USER_NULL) {
442 userType = USER_TYPE_WORK_PROFILE;
443 } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
Jim Miller7751ff62014-01-14 18:57:03 -0800444 if (remainingBeforeWipe > 0) {
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700445 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
Jim Miller7751ff62014-01-14 18:57:03 -0800446 } else {
447 // Too many attempts. The device will be wiped shortly.
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700448 Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
449 showWipeDialog(failedAttempts, userType);
Jim Miller7751ff62014-01-14 18:57:03 -0800450 }
Jim Miller7751ff62014-01-14 18:57:03 -0800451 }
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800452 mLockPatternUtils.reportFailedPasswordAttempt(userId);
Andres Morales23974272015-05-14 22:42:26 -0700453 if (timeoutMs > 0) {
Zachary Iqbal327323d2017-01-12 14:41:13 -0800454 mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700455 showTimeoutDialog(userId, timeoutMs);
Jim Miller7751ff62014-01-14 18:57:03 -0800456 }
457 }
458
459 /**
460 * Shows the primary security screen for the user. This will be either the multi-selector
461 * or the user's security method.
462 * @param turningOff true if the device is being turned off
463 */
464 void showPrimarySecurityScreen(boolean turningOff) {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700465 SecurityMode securityMode = mSecurityModel.getSecurityMode(
466 KeyguardUpdateMonitor.getCurrentUser());
Jim Miller7751ff62014-01-14 18:57:03 -0800467 if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
Jim Miller7751ff62014-01-14 18:57:03 -0800468 showSecurityScreen(securityMode);
469 }
470
471 /**
Jim Millerba7d94b2014-02-05 17:30:50 -0800472 * Shows the next security screen if there is one.
473 * @param authenticated true if the user entered the correct authentication
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700474 * @param targetUserId a user that needs to be the foreground user at the finish (if called)
475 * completion.
Jim Millerba7d94b2014-02-05 17:30:50 -0800476 * @return true if keyguard is done
477 */
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700478 boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId) {
Jim Miller7751ff62014-01-14 18:57:03 -0800479 if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
480 boolean finish = false;
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700481 boolean strongAuth = false;
Steven Wucfe398d2019-03-21 11:32:15 -0400482 int eventSubtype = -1;
483 if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
Adrian Roos336be7f2014-05-19 17:11:18 +0200484 finish = true;
Steven Wucfe398d2019-03-21 11:32:15 -0400485 eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
486 } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
487 finish = true;
488 eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
Adrian Roos336be7f2014-05-19 17:11:18 +0200489 } else if (SecurityMode.None == mCurrentSecuritySelection) {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700490 SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
Jim Miller7751ff62014-01-14 18:57:03 -0800491 if (SecurityMode.None == securityMode) {
492 finish = true; // no security required
Steven Wucfe398d2019-03-21 11:32:15 -0400493 eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
Jim Miller7751ff62014-01-14 18:57:03 -0800494 } else {
495 showSecurityScreen(securityMode); // switch to the alternate security view
496 }
497 } else if (authenticated) {
498 switch (mCurrentSecuritySelection) {
499 case Pattern:
500 case Password:
501 case PIN:
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700502 strongAuth = true;
Jim Miller7751ff62014-01-14 18:57:03 -0800503 finish = true;
Steven Wucfe398d2019-03-21 11:32:15 -0400504 eventSubtype = BOUNCER_DISMISS_PASSWORD;
Jim Miller7751ff62014-01-14 18:57:03 -0800505 break;
506
507 case SimPin:
508 case SimPuk:
509 // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700510 SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
Jordan Liub4299d92018-09-26 12:49:11 -0700511 if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
Selim Cinek245273e2015-06-24 13:17:56 -0400512 KeyguardUpdateMonitor.getCurrentUser())) {
Jim Miller7751ff62014-01-14 18:57:03 -0800513 finish = true;
Steven Wucfe398d2019-03-21 11:32:15 -0400514 eventSubtype = BOUNCER_DISMISS_SIM;
Jordan Liub4299d92018-09-26 12:49:11 -0700515 } else {
516 showSecurityScreen(securityMode);
Jim Miller7751ff62014-01-14 18:57:03 -0800517 }
518 break;
519
520 default:
521 Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
522 showPrimarySecurityScreen(false);
523 break;
524 }
Jim Miller7751ff62014-01-14 18:57:03 -0800525 }
Steven Wucfe398d2019-03-21 11:32:15 -0400526 if (eventSubtype != -1) {
527 mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
528 .setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
529 }
Jim Miller7751ff62014-01-14 18:57:03 -0800530 if (finish) {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700531 mSecurityCallback.finish(strongAuth, targetUserId);
Jim Miller7751ff62014-01-14 18:57:03 -0800532 }
533 return finish;
534 }
535
536 /**
537 * Switches to the given security view unless it's already being shown, in which case
538 * this is a no-op.
539 *
540 * @param securityMode
541 */
542 private void showSecurityScreen(SecurityMode securityMode) {
543 if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
544
545 if (securityMode == mCurrentSecuritySelection) return;
546
547 KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
548 KeyguardSecurityView newView = getSecurityView(securityMode);
549
550 // Emulate Activity life cycle
551 if (oldView != null) {
552 oldView.onPause();
553 oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
554 }
Jorim Jaggif4797922014-08-04 22:49:41 +0200555 if (securityMode != SecurityMode.None) {
556 newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
557 newView.setKeyguardCallback(mCallback);
558 }
Jim Miller7751ff62014-01-14 18:57:03 -0800559
560 // Find and show this child.
561 final int childCount = mSecurityViewFlipper.getChildCount();
562
563 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
564 for (int i = 0; i < childCount; i++) {
565 if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
566 mSecurityViewFlipper.setDisplayedChild(i);
567 break;
568 }
569 }
570
571 mCurrentSecuritySelection = securityMode;
Lucas Dupin27321c42019-03-20 16:22:24 -0700572 mCurrentSecurityView = newView;
Jorim Jaggif4797922014-08-04 22:49:41 +0200573 mSecurityCallback.onSecurityModeChanged(securityMode,
574 securityMode != SecurityMode.None && newView.needsInput());
Jim Miller7751ff62014-01-14 18:57:03 -0800575 }
576
577 private KeyguardSecurityViewFlipper getFlipper() {
Chris Wren052999f2012-11-02 14:36:56 -0400578 for (int i = 0; i < getChildCount(); i++) {
579 View child = getChildAt(i);
580 if (child instanceof KeyguardSecurityViewFlipper) {
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500581 return (KeyguardSecurityViewFlipper) child;
Chris Wren052999f2012-11-02 14:36:56 -0400582 }
583 }
584 return null;
585 }
586
Jim Miller7751ff62014-01-14 18:57:03 -0800587 private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200588 public void userActivity() {
Jim Miller7751ff62014-01-14 18:57:03 -0800589 if (mSecurityCallback != null) {
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200590 mSecurityCallback.userActivity();
Jim Miller7751ff62014-01-14 18:57:03 -0800591 }
592 }
593
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700594 public void dismiss(boolean authenticated, int targetId) {
595 mSecurityCallback.dismiss(authenticated, targetId);
Jim Miller7751ff62014-01-14 18:57:03 -0800596 }
597
598 public boolean isVerifyUnlockOnly() {
599 return mIsVerifyUnlockOnly;
600 }
601
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800602 public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
Jim Miller7751ff62014-01-14 18:57:03 -0800603 if (success) {
Tej Singhdd7bd352018-02-09 19:33:15 -0800604 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
605 StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800606 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
Jim Miller7751ff62014-01-14 18:57:03 -0800607 } else {
Tej Singhdd7bd352018-02-09 19:33:15 -0800608 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
609 StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800610 KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs);
Jim Miller7751ff62014-01-14 18:57:03 -0800611 }
Steven Wu6ef24b22019-03-11 17:14:11 -0400612 mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
613 .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
Jim Miller7751ff62014-01-14 18:57:03 -0800614 }
615
Andrew Lee72b46d42015-01-30 13:23:21 -0800616 public void reset() {
617 mSecurityCallback.reset();
618 }
Aarthi Balachander0a427ef2018-07-13 15:00:58 -0700619
620 public void onCancelClicked() {
621 mSecurityCallback.onCancelClicked();
622 }
Jim Miller7751ff62014-01-14 18:57:03 -0800623 };
624
625 // The following is used to ignore callbacks from SecurityViews that are no longer current
626 // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
627 // state for the current security method.
628 private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
629 @Override
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200630 public void userActivity() { }
Jim Miller7751ff62014-01-14 18:57:03 -0800631 @Override
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800632 public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
Jim Miller7751ff62014-01-14 18:57:03 -0800633 @Override
634 public boolean isVerifyUnlockOnly() { return false; }
635 @Override
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700636 public void dismiss(boolean securityVerified, int targetUserId) { }
Andrew Lee72b46d42015-01-30 13:23:21 -0800637 @Override
638 public void reset() {}
Jim Miller7751ff62014-01-14 18:57:03 -0800639 };
640
641 private int getSecurityViewIdForMode(SecurityMode securityMode) {
642 switch (securityMode) {
Jim Miller7751ff62014-01-14 18:57:03 -0800643 case Pattern: return R.id.keyguard_pattern_view;
644 case PIN: return R.id.keyguard_pin_view;
645 case Password: return R.id.keyguard_password_view;
Jim Miller7751ff62014-01-14 18:57:03 -0800646 case SimPin: return R.id.keyguard_sim_pin_view;
647 case SimPuk: return R.id.keyguard_sim_puk_view;
648 }
649 return 0;
650 }
651
Lucas Dupine17ce522017-07-17 15:45:06 -0700652 @VisibleForTesting
653 public int getLayoutIdFor(SecurityMode securityMode) {
Jim Miller7751ff62014-01-14 18:57:03 -0800654 switch (securityMode) {
Jim Miller7751ff62014-01-14 18:57:03 -0800655 case Pattern: return R.layout.keyguard_pattern_view;
656 case PIN: return R.layout.keyguard_pin_view;
657 case Password: return R.layout.keyguard_password_view;
Jim Miller7751ff62014-01-14 18:57:03 -0800658 case SimPin: return R.layout.keyguard_sim_pin_view;
659 case SimPuk: return R.layout.keyguard_sim_puk_view;
660 default:
661 return 0;
662 }
663 }
664
665 public SecurityMode getSecurityMode() {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700666 return mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser());
Jim Miller7751ff62014-01-14 18:57:03 -0800667 }
668
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100669 public SecurityMode getCurrentSecurityMode() {
670 return mCurrentSecuritySelection;
671 }
672
Lucas Dupin27321c42019-03-20 16:22:24 -0700673 public KeyguardSecurityView getCurrentSecurityView() {
674 return mCurrentSecurityView;
675 }
676
Jim Miller7751ff62014-01-14 18:57:03 -0800677 public void verifyUnlock() {
678 mIsVerifyUnlockOnly = true;
679 showSecurityScreen(getSecurityMode());
680 }
681
682 public SecurityMode getCurrentSecuritySelection() {
683 return mCurrentSecuritySelection;
684 }
685
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700686 public void dismiss(boolean authenticated, int targetUserId) {
687 mCallback.dismiss(authenticated, targetUserId);
Jim Miller7751ff62014-01-14 18:57:03 -0800688 }
689
690 public boolean needsInput() {
691 return mSecurityViewFlipper.needsInput();
692 }
693
694 @Override
695 public void setKeyguardCallback(KeyguardSecurityCallback callback) {
696 mSecurityViewFlipper.setKeyguardCallback(callback);
697 }
698
699 @Override
700 public void reset() {
701 mSecurityViewFlipper.reset();
702 }
703
704 @Override
705 public KeyguardSecurityCallback getCallback() {
706 return mSecurityViewFlipper.getCallback();
707 }
708
709 @Override
Selim Cinek3122fa82015-06-18 01:38:59 -0700710 public void showPromptReason(int reason) {
711 if (mCurrentSecuritySelection != SecurityMode.None) {
Adrian Roos569edb82016-03-03 15:39:03 -0800712 if (reason != PROMPT_REASON_NONE) {
713 Log.i(TAG, "Strong auth required, reason: " + reason);
714 }
Selim Cinek3122fa82015-06-18 01:38:59 -0700715 getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
716 }
717 }
718
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800719 public void showMessage(CharSequence message, ColorStateList colorState) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700720 if (mCurrentSecuritySelection != SecurityMode.None) {
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800721 getSecurityView(mCurrentSecuritySelection).showMessage(message, colorState);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700722 }
723 }
724
Selim Cinek3122fa82015-06-18 01:38:59 -0700725 @Override
Jim Miller7751ff62014-01-14 18:57:03 -0800726 public void showUsabilityHint() {
727 mSecurityViewFlipper.showUsabilityHint();
728 }
729
Jim Miller838906b2012-10-19 18:41:25 -0700730}
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500731