blob: 8059dcf33df734866043e9be8b2321dce3b9bacb [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;
Lucas Dupin206fe562019-05-31 14:36:42 -070049import com.android.systemui.statusbar.phone.UnlockMethodCache;
Priyank Singh051353e2019-04-25 10:14:57 -070050import com.android.systemui.util.InjectionInflationController;
Jim Miller7751ff62014-01-14 18:57:03 -080051
52public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
Jorim Jaggi5cf17872014-03-26 18:31:48 +010053 private static final boolean DEBUG = KeyguardConstants.DEBUG;
Jim Miller7751ff62014-01-14 18:57:03 -080054 private static final String TAG = "KeyguardSecurityView";
Amith Yamasani3a3d2122014-10-29 11:41:31 -070055
56 private static final int USER_TYPE_PRIMARY = 1;
57 private static final int USER_TYPE_WORK_PROFILE = 2;
58 private static final int USER_TYPE_SECONDARY_USER = 3;
59
Steven Wucfe398d2019-03-21 11:32:15 -040060 // Bouncer is dismissed due to no security.
61 private static final int BOUNCER_DISMISS_NONE_SECURITY = 0;
62 // Bouncer is dismissed due to pin, password or pattern entered.
63 private static final int BOUNCER_DISMISS_PASSWORD = 1;
64 // Bouncer is dismissed due to biometric (face, fingerprint or iris) authenticated.
65 private static final int BOUNCER_DISMISS_BIOMETRIC = 2;
66 // Bouncer is dismissed due to extended access granted.
67 private static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3;
68 // Bouncer is dismissed due to sim card unlock code entered.
69 private static final int BOUNCER_DISMISS_SIM = 4;
70
Lucas Dupin7156bc72019-05-03 19:37:39 -070071 // Make the view move slower than the finger, as if the spring were applying force.
72 private static final float TOUCH_Y_MULTIPLIER = 0.25f;
73 // How much you need to drag the bouncer to trigger an auth retry (in dps.)
74 private static final float MIN_DRAG_SIZE = 10;
Lucas Dupinabb18f42019-05-20 19:10:22 -070075 // How much to scale the default slop by, to avoid accidental drags.
76 private static final float SLOP_SCALE = 2f;
Lucas Dupin7156bc72019-05-03 19:37:39 -070077
Jim Miller7751ff62014-01-14 18:57:03 -080078 private KeyguardSecurityModel mSecurityModel;
Jim Miller7751ff62014-01-14 18:57:03 -080079 private LockPatternUtils mLockPatternUtils;
80
81 private KeyguardSecurityViewFlipper mSecurityViewFlipper;
82 private boolean mIsVerifyUnlockOnly;
83 private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
Lucas Dupin27321c42019-03-20 16:22:24 -070084 private KeyguardSecurityView mCurrentSecurityView;
Jim Miller7751ff62014-01-14 18:57:03 -080085 private SecurityCallback mSecurityCallback;
Lucas Dupin7f729822017-12-13 15:27:10 -080086 private AlertDialog mAlertDialog;
Priyank Singh051353e2019-04-25 10:14:57 -070087 private InjectionInflationController mInjectionInflationController;
Lucas Dupin7156bc72019-05-03 19:37:39 -070088 private boolean mSwipeUpToRetry;
Jim Miller7751ff62014-01-14 18:57:03 -080089
Lucas Dupin7156bc72019-05-03 19:37:39 -070090 private final ViewConfiguration mViewConfiguration;
91 private final SpringAnimation mSpringAnimation;
92 private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
Adrian Roos336be7f2014-05-19 17:11:18 +020093 private final KeyguardUpdateMonitor mUpdateMonitor;
Lucas Dupin206fe562019-05-31 14:36:42 -070094 private final UnlockMethodCache mUnlockMethodCache;
Adrian Roos336be7f2014-05-19 17:11:18 +020095
Steven Wu6ef24b22019-03-11 17:14:11 -040096 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
Lucas Dupin7156bc72019-05-03 19:37:39 -070097 private float mLastTouchY = -1;
98 private int mActivePointerId = -1;
99 private boolean mIsDragging;
100 private float mStartTouchY = -1;
Steven Wu6ef24b22019-03-11 17:14:11 -0400101
Jim Miller7751ff62014-01-14 18:57:03 -0800102 // Used to notify the container when something interesting happens.
103 public interface SecurityCallback {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700104 public boolean dismiss(boolean authenticated, int targetUserId);
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200105 public void userActivity();
Jim Millerba7d94b2014-02-05 17:30:50 -0800106 public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700107
108 /**
109 * @param strongAuth wheher the user has authenticated with strong authentication like
110 * pattern, password or PIN but not by trust agents or fingerprint
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700111 * @param targetUserId a user that needs to be the foreground user at the finish completion.
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700112 */
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700113 public void finish(boolean strongAuth, int targetUserId);
Andrew Lee72b46d42015-01-30 13:23:21 -0800114 public void reset();
Aarthi Balachander0a427ef2018-07-13 15:00:58 -0700115 public void onCancelClicked();
Jim Miller7751ff62014-01-14 18:57:03 -0800116 }
117
Jim Miller838906b2012-10-19 18:41:25 -0700118 public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
119 this(context, attrs, 0);
120 }
121
122 public KeyguardSecurityContainer(Context context) {
Esteban Talaverafe0f24c2014-08-06 16:20:56 +0100123 this(context, null, 0);
Jim Miller838906b2012-10-19 18:41:25 -0700124 }
125
126 public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
Lucas Dupin987f1932017-05-13 21:02:52 -0700127 super(context, attrs, defStyle);
Jim Miller7751ff62014-01-14 18:57:03 -0800128 mSecurityModel = new KeyguardSecurityModel(context);
129 mLockPatternUtils = new LockPatternUtils(context);
Adrian Roos336be7f2014-05-19 17:11:18 +0200130 mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Lucas Dupin7156bc72019-05-03 19:37:39 -0700131 mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
Priyank Singh051353e2019-04-25 10:14:57 -0700132 mInjectionInflationController = new InjectionInflationController(
133 SystemUIFactory.getInstance().getRootComponent());
Lucas Dupin206fe562019-05-31 14:36:42 -0700134 mUnlockMethodCache = UnlockMethodCache.getInstance(context);
Lucas Dupin7156bc72019-05-03 19:37:39 -0700135 mViewConfiguration = ViewConfiguration.get(context);
Chris Wrenc3451462012-10-30 11:22:58 -0400136 }
137
Jim Miller7751ff62014-01-14 18:57:03 -0800138 public void setSecurityCallback(SecurityCallback callback) {
139 mSecurityCallback = callback;
140 }
141
142 @Override
143 public void onResume(int reason) {
Jorim Jaggif4797922014-08-04 22:49:41 +0200144 if (mCurrentSecuritySelection != SecurityMode.None) {
145 getSecurityView(mCurrentSecuritySelection).onResume(reason);
146 }
Lucas Dupin7156bc72019-05-03 19:37:39 -0700147 updateBiometricRetry();
Jim Miller7751ff62014-01-14 18:57:03 -0800148 }
149
150 @Override
151 public void onPause() {
Lucas Dupin7f729822017-12-13 15:27:10 -0800152 if (mAlertDialog != null) {
153 mAlertDialog.dismiss();
154 mAlertDialog = null;
155 }
Jorim Jaggif4797922014-08-04 22:49:41 +0200156 if (mCurrentSecuritySelection != SecurityMode.None) {
157 getSecurityView(mCurrentSecuritySelection).onPause();
158 }
Jim Miller7751ff62014-01-14 18:57:03 -0800159 }
160
Lucas Dupin7156bc72019-05-03 19:37:39 -0700161 @Override
162 public boolean shouldDelayChildPressedState() {
163 return true;
164 }
165
166 @Override
167 public boolean onInterceptTouchEvent(MotionEvent event) {
168 switch (event.getActionMasked()) {
169 case MotionEvent.ACTION_DOWN:
170 int pointerIndex = event.getActionIndex();
171 mStartTouchY = event.getY(pointerIndex);
172 mActivePointerId = event.getPointerId(pointerIndex);
173 mVelocityTracker.clear();
174 break;
175 case MotionEvent.ACTION_MOVE:
176 if (mIsDragging) {
177 return true;
178 }
179 if (!mSwipeUpToRetry) {
180 return false;
181 }
182 // Avoid dragging the pattern view
183 if (mCurrentSecurityView.disallowInterceptTouch(event)) {
184 return false;
185 }
186 int index = event.findPointerIndex(mActivePointerId);
Lucas Dupinabb18f42019-05-20 19:10:22 -0700187 float touchSlop = mViewConfiguration.getScaledTouchSlop() * SLOP_SCALE;
Lucas Dupinc26ab7512019-05-13 13:49:17 -0700188 if (mCurrentSecurityView != null && index != -1
Lucas Dupin7156bc72019-05-03 19:37:39 -0700189 && mStartTouchY - event.getY(index) > touchSlop) {
190 mIsDragging = true;
191 return true;
192 }
193 break;
194 case MotionEvent.ACTION_CANCEL:
195 case MotionEvent.ACTION_UP:
196 mIsDragging = false;
197 break;
198 }
199 return false;
200 }
201
202 @Override
203 public boolean onTouchEvent(MotionEvent event) {
204 final int action = event.getActionMasked();
205 switch (action) {
206 case MotionEvent.ACTION_MOVE:
207 mVelocityTracker.addMovement(event);
208 int pointerIndex = event.findPointerIndex(mActivePointerId);
209 float y = event.getY(pointerIndex);
210 if (mLastTouchY != -1) {
211 float dy = y - mLastTouchY;
212 setTranslationY(getTranslationY() + dy * TOUCH_Y_MULTIPLIER);
213 }
214 mLastTouchY = y;
215 break;
216 case MotionEvent.ACTION_UP:
217 case MotionEvent.ACTION_CANCEL:
218 mActivePointerId = -1;
219 mLastTouchY = -1;
220 mIsDragging = false;
221 startSpringAnimation(mVelocityTracker.getYVelocity());
222 break;
223 case MotionEvent.ACTION_POINTER_UP:
224 int index = event.getActionIndex();
225 int pointerId = event.getPointerId(index);
226 if (pointerId == mActivePointerId) {
227 // This was our active pointer going up. Choose a new
228 // active pointer and adjust accordingly.
229 final int newPointerIndex = index == 0 ? 1 : 0;
230 mLastTouchY = event.getY(newPointerIndex);
231 mActivePointerId = event.getPointerId(newPointerIndex);
232 }
233 break;
234 }
235 if (action == MotionEvent.ACTION_UP) {
236 if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
Lucas Dupin51996bb2019-05-16 17:56:43 -0700237 MIN_DRAG_SIZE, getResources().getDisplayMetrics())
238 && !mUpdateMonitor.isFaceDetectionRunning()) {
Lucas Dupin7156bc72019-05-03 19:37:39 -0700239 mUpdateMonitor.requestFaceAuth();
Lucas Dupinaad98832019-07-14 13:23:24 +0900240 mCallback.userActivity();
Lucas Dupin51996bb2019-05-16 17:56:43 -0700241 showMessage(null, null);
Lucas Dupin7156bc72019-05-03 19:37:39 -0700242 }
243 }
244 return true;
245 }
246
247 private void startSpringAnimation(float startVelocity) {
248 mSpringAnimation
249 .setStartVelocity(startVelocity)
250 .animateToFinalPosition(0);
251 }
252
Jorim Jaggic14f8292014-05-27 02:25:45 +0200253 public void startAppearAnimation() {
Jorim Jaggif4797922014-08-04 22:49:41 +0200254 if (mCurrentSecuritySelection != SecurityMode.None) {
255 getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
256 }
Jorim Jaggic14f8292014-05-27 02:25:45 +0200257 }
258
Jorim Jaggi76a16232014-08-08 17:00:47 +0200259 public boolean startDisappearAnimation(Runnable onFinishRunnable) {
260 if (mCurrentSecuritySelection != SecurityMode.None) {
261 return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation(
262 onFinishRunnable);
263 }
264 return false;
265 }
266
Lucas Dupin7156bc72019-05-03 19:37:39 -0700267 /**
268 * Enables/disables swipe up to retry on the bouncer.
269 */
270 private void updateBiometricRetry() {
271 SecurityMode securityMode = getSecurityMode();
Lucas Dupin4c507042019-07-22 16:47:34 -0700272 mSwipeUpToRetry = mUnlockMethodCache.isFaceAuthEnabled()
Lucas Dupin7156bc72019-05-03 19:37:39 -0700273 && securityMode != SecurityMode.SimPin
274 && securityMode != SecurityMode.SimPuk
Lucas Dupinfc8de932019-06-13 14:20:52 -0700275 && securityMode != SecurityMode.None;
Lucas Dupin7156bc72019-05-03 19:37:39 -0700276 }
277
Phil Weaver7d847b02018-02-13 16:02:35 -0800278 public CharSequence getTitle() {
279 return mSecurityViewFlipper.getTitle();
Jorim Jaggic1dff8c2015-02-02 14:45:39 +0100280 }
281
Jim Miller7751ff62014-01-14 18:57:03 -0800282 private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
283 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
284 KeyguardSecurityView view = null;
285 final int children = mSecurityViewFlipper.getChildCount();
286 for (int child = 0; child < children; child++) {
287 if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
288 view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
289 break;
290 }
291 }
292 int layoutId = getLayoutIdFor(securityMode);
293 if (view == null && layoutId != 0) {
294 final LayoutInflater inflater = LayoutInflater.from(mContext);
295 if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
Priyank Singh051353e2019-04-25 10:14:57 -0700296 View v = mInjectionInflationController.injectable(inflater)
297 .inflate(layoutId, mSecurityViewFlipper, false);
Jim Miller7751ff62014-01-14 18:57:03 -0800298 mSecurityViewFlipper.addView(v);
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100299 updateSecurityView(v);
Jim Miller7751ff62014-01-14 18:57:03 -0800300 view = (KeyguardSecurityView)v;
Lucas Dupinf7fd03d2018-06-26 15:58:51 -0700301 view.reset();
Jim Miller7751ff62014-01-14 18:57:03 -0800302 }
303
Jim Miller7751ff62014-01-14 18:57:03 -0800304 return view;
305 }
306
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100307 private void updateSecurityView(View view) {
Jim Miller7751ff62014-01-14 18:57:03 -0800308 if (view instanceof KeyguardSecurityView) {
309 KeyguardSecurityView ksv = (KeyguardSecurityView) view;
310 ksv.setKeyguardCallback(mCallback);
311 ksv.setLockPatternUtils(mLockPatternUtils);
Jim Miller7751ff62014-01-14 18:57:03 -0800312 } else {
313 Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
314 }
315 }
316
317 protected void onFinishInflate() {
Alan Viverette51efddb2017-04-05 10:00:01 -0400318 mSecurityViewFlipper = findViewById(R.id.view_flipper);
Jim Miller7751ff62014-01-14 18:57:03 -0800319 mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
320 }
321
322 public void setLockPatternUtils(LockPatternUtils utils) {
323 mLockPatternUtils = utils;
324 mSecurityModel.setLockPatternUtils(utils);
325 mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
326 }
327
Lucas Dupin7156bc72019-05-03 19:37:39 -0700328 @Override
Lucas Dupin3ac28ac2019-05-13 16:33:32 -0700329 protected boolean fitSystemWindows(Rect insets) {
330 // Consume bottom insets because we're setting the padding locally (for IME and navbar.)
331 setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), insets.bottom);
332 insets.bottom = 0;
333 return false;
Lucas Dupin7156bc72019-05-03 19:37:39 -0700334 }
335
Jim Miller7751ff62014-01-14 18:57:03 -0800336 private void showDialog(String title, String message) {
Lucas Dupin7f729822017-12-13 15:27:10 -0800337 if (mAlertDialog != null) {
338 mAlertDialog.dismiss();
339 }
340
341 mAlertDialog = new AlertDialog.Builder(mContext)
Jim Miller7751ff62014-01-14 18:57:03 -0800342 .setTitle(title)
343 .setMessage(message)
Edward Savage-Jonesb08a1462016-10-05 10:29:02 +0200344 .setCancelable(false)
Jim Miller7751ff62014-01-14 18:57:03 -0800345 .setNeutralButton(R.string.ok, null)
346 .create();
347 if (!(mContext instanceof Activity)) {
Lucas Dupin7f729822017-12-13 15:27:10 -0800348 mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
Jim Miller7751ff62014-01-14 18:57:03 -0800349 }
Lucas Dupin7f729822017-12-13 15:27:10 -0800350 mAlertDialog.show();
Jim Miller7751ff62014-01-14 18:57:03 -0800351 }
352
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700353 private void showTimeoutDialog(int userId, int timeoutMs) {
Andres Morales23974272015-05-14 22:42:26 -0700354 int timeoutInSeconds = (int) timeoutMs / 1000;
Jim Miller7751ff62014-01-14 18:57:03 -0800355 int messageId = 0;
356
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700357 switch (mSecurityModel.getSecurityMode(userId)) {
Jim Miller7751ff62014-01-14 18:57:03 -0800358 case Pattern:
359 messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
360 break;
361 case PIN:
362 messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message;
363 break;
364 case Password:
365 messageId = R.string.kg_too_many_failed_password_attempts_dialog_message;
366 break;
367 // These don't have timeout dialogs.
Jim Miller7751ff62014-01-14 18:57:03 -0800368 case Invalid:
369 case None:
370 case SimPin:
371 case SimPuk:
372 break;
373 }
374
375 if (messageId != 0) {
376 final String message = mContext.getString(messageId,
Pavel Grafovb90dc432018-08-15 20:02:58 +0100377 mLockPatternUtils.getCurrentFailedPasswordAttempts(userId),
Jim Miller7751ff62014-01-14 18:57:03 -0800378 timeoutInSeconds);
379 showDialog(null, message);
380 }
381 }
382
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700383 private void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
384 String message = null;
385 switch (userType) {
386 case USER_TYPE_PRIMARY:
387 message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe,
388 attempts, remaining);
389 break;
390 case USER_TYPE_SECONDARY_USER:
391 message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_user,
392 attempts, remaining);
393 break;
394 case USER_TYPE_WORK_PROFILE:
395 message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_profile,
396 attempts, remaining);
397 break;
398 }
Jim Miller7751ff62014-01-14 18:57:03 -0800399 showDialog(null, message);
400 }
401
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700402 private void showWipeDialog(int attempts, int userType) {
403 String message = null;
404 switch (userType) {
405 case USER_TYPE_PRIMARY:
406 message = mContext.getString(R.string.kg_failed_attempts_now_wiping,
407 attempts);
408 break;
409 case USER_TYPE_SECONDARY_USER:
410 message = mContext.getString(R.string.kg_failed_attempts_now_erasing_user,
411 attempts);
412 break;
413 case USER_TYPE_WORK_PROFILE:
414 message = mContext.getString(R.string.kg_failed_attempts_now_erasing_profile,
415 attempts);
416 break;
417 }
Jim Miller7751ff62014-01-14 18:57:03 -0800418 showDialog(null, message);
419 }
420
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800421 private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
Pavel Grafovb90dc432018-08-15 20:02:58 +0100422 // +1 for this time
423 final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
Jim Miller7751ff62014-01-14 18:57:03 -0800424
425 if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
426
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700427 final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
428 final int failedAttemptsBeforeWipe =
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800429 dpm.getMaximumFailedPasswordsForWipe(null, userId);
Jim Miller7751ff62014-01-14 18:57:03 -0800430
Jim Miller7751ff62014-01-14 18:57:03 -0800431 final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
432 (failedAttemptsBeforeWipe - failedAttempts)
433 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
Jim Miller7751ff62014-01-14 18:57:03 -0800434 if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
Esteban Talaverafe0f24c2014-08-06 16:20:56 +0100435 // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
436 // N attempts. Once we get below the grace period, we post this dialog every time as a
437 // clear warning until the deletion fires.
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700438 // Check which profile has the strictest policy for failed password attempts
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800439 final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700440 int userType = USER_TYPE_PRIMARY;
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800441 if (expiringUser == userId) {
Xiaohui Chencc791bc2015-08-26 14:54:34 -0700442 // TODO: http://b/23522538
443 if (expiringUser != UserHandle.USER_SYSTEM) {
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700444 userType = USER_TYPE_SECONDARY_USER;
445 }
446 } else if (expiringUser != UserHandle.USER_NULL) {
447 userType = USER_TYPE_WORK_PROFILE;
448 } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
Jim Miller7751ff62014-01-14 18:57:03 -0800449 if (remainingBeforeWipe > 0) {
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700450 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
Jim Miller7751ff62014-01-14 18:57:03 -0800451 } else {
452 // Too many attempts. The device will be wiped shortly.
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700453 Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
454 showWipeDialog(failedAttempts, userType);
Jim Miller7751ff62014-01-14 18:57:03 -0800455 }
Jim Miller7751ff62014-01-14 18:57:03 -0800456 }
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800457 mLockPatternUtils.reportFailedPasswordAttempt(userId);
Andres Morales23974272015-05-14 22:42:26 -0700458 if (timeoutMs > 0) {
Zachary Iqbal327323d2017-01-12 14:41:13 -0800459 mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700460 showTimeoutDialog(userId, timeoutMs);
Jim Miller7751ff62014-01-14 18:57:03 -0800461 }
462 }
463
464 /**
465 * Shows the primary security screen for the user. This will be either the multi-selector
466 * or the user's security method.
467 * @param turningOff true if the device is being turned off
468 */
469 void showPrimarySecurityScreen(boolean turningOff) {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700470 SecurityMode securityMode = mSecurityModel.getSecurityMode(
471 KeyguardUpdateMonitor.getCurrentUser());
Jim Miller7751ff62014-01-14 18:57:03 -0800472 if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
Jim Miller7751ff62014-01-14 18:57:03 -0800473 showSecurityScreen(securityMode);
474 }
475
476 /**
Jim Millerba7d94b2014-02-05 17:30:50 -0800477 * Shows the next security screen if there is one.
478 * @param authenticated true if the user entered the correct authentication
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700479 * @param targetUserId a user that needs to be the foreground user at the finish (if called)
480 * completion.
Jim Millerba7d94b2014-02-05 17:30:50 -0800481 * @return true if keyguard is done
482 */
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700483 boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId) {
Jim Miller7751ff62014-01-14 18:57:03 -0800484 if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
485 boolean finish = false;
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700486 boolean strongAuth = false;
Steven Wucfe398d2019-03-21 11:32:15 -0400487 int eventSubtype = -1;
488 if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
Adrian Roos336be7f2014-05-19 17:11:18 +0200489 finish = true;
Steven Wucfe398d2019-03-21 11:32:15 -0400490 eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
491 } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
492 finish = true;
493 eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
Adrian Roos336be7f2014-05-19 17:11:18 +0200494 } else if (SecurityMode.None == mCurrentSecuritySelection) {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700495 SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
Jim Miller7751ff62014-01-14 18:57:03 -0800496 if (SecurityMode.None == securityMode) {
497 finish = true; // no security required
Steven Wucfe398d2019-03-21 11:32:15 -0400498 eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
Jim Miller7751ff62014-01-14 18:57:03 -0800499 } else {
500 showSecurityScreen(securityMode); // switch to the alternate security view
501 }
502 } else if (authenticated) {
503 switch (mCurrentSecuritySelection) {
504 case Pattern:
505 case Password:
506 case PIN:
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700507 strongAuth = true;
Jim Miller7751ff62014-01-14 18:57:03 -0800508 finish = true;
Steven Wucfe398d2019-03-21 11:32:15 -0400509 eventSubtype = BOUNCER_DISMISS_PASSWORD;
Jim Miller7751ff62014-01-14 18:57:03 -0800510 break;
511
512 case SimPin:
513 case SimPuk:
514 // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700515 SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
Jordan Liu15be64a2019-07-15 17:05:20 -0700516 if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
Selim Cinek245273e2015-06-24 13:17:56 -0400517 KeyguardUpdateMonitor.getCurrentUser())) {
Jim Miller7751ff62014-01-14 18:57:03 -0800518 finish = true;
Steven Wucfe398d2019-03-21 11:32:15 -0400519 eventSubtype = BOUNCER_DISMISS_SIM;
Jordan Liub4299d92018-09-26 12:49:11 -0700520 } else {
521 showSecurityScreen(securityMode);
Jim Miller7751ff62014-01-14 18:57:03 -0800522 }
523 break;
524
525 default:
526 Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
527 showPrimarySecurityScreen(false);
528 break;
529 }
Jim Miller7751ff62014-01-14 18:57:03 -0800530 }
Steven Wucfe398d2019-03-21 11:32:15 -0400531 if (eventSubtype != -1) {
532 mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
533 .setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
534 }
Jim Miller7751ff62014-01-14 18:57:03 -0800535 if (finish) {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700536 mSecurityCallback.finish(strongAuth, targetUserId);
Jim Miller7751ff62014-01-14 18:57:03 -0800537 }
538 return finish;
539 }
540
541 /**
542 * Switches to the given security view unless it's already being shown, in which case
543 * this is a no-op.
544 *
545 * @param securityMode
546 */
547 private void showSecurityScreen(SecurityMode securityMode) {
548 if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
549
550 if (securityMode == mCurrentSecuritySelection) return;
551
552 KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
553 KeyguardSecurityView newView = getSecurityView(securityMode);
554
555 // Emulate Activity life cycle
556 if (oldView != null) {
557 oldView.onPause();
558 oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
559 }
Jorim Jaggif4797922014-08-04 22:49:41 +0200560 if (securityMode != SecurityMode.None) {
561 newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
562 newView.setKeyguardCallback(mCallback);
563 }
Jim Miller7751ff62014-01-14 18:57:03 -0800564
565 // Find and show this child.
566 final int childCount = mSecurityViewFlipper.getChildCount();
567
568 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
569 for (int i = 0; i < childCount; i++) {
570 if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
571 mSecurityViewFlipper.setDisplayedChild(i);
572 break;
573 }
574 }
575
576 mCurrentSecuritySelection = securityMode;
Lucas Dupin27321c42019-03-20 16:22:24 -0700577 mCurrentSecurityView = newView;
Jorim Jaggif4797922014-08-04 22:49:41 +0200578 mSecurityCallback.onSecurityModeChanged(securityMode,
579 securityMode != SecurityMode.None && newView.needsInput());
Jim Miller7751ff62014-01-14 18:57:03 -0800580 }
581
582 private KeyguardSecurityViewFlipper getFlipper() {
Chris Wren052999f2012-11-02 14:36:56 -0400583 for (int i = 0; i < getChildCount(); i++) {
584 View child = getChildAt(i);
585 if (child instanceof KeyguardSecurityViewFlipper) {
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500586 return (KeyguardSecurityViewFlipper) child;
Chris Wren052999f2012-11-02 14:36:56 -0400587 }
588 }
589 return null;
590 }
591
Jim Miller7751ff62014-01-14 18:57:03 -0800592 private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200593 public void userActivity() {
Jim Miller7751ff62014-01-14 18:57:03 -0800594 if (mSecurityCallback != null) {
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200595 mSecurityCallback.userActivity();
Jim Miller7751ff62014-01-14 18:57:03 -0800596 }
597 }
598
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700599 public void dismiss(boolean authenticated, int targetId) {
600 mSecurityCallback.dismiss(authenticated, targetId);
Jim Miller7751ff62014-01-14 18:57:03 -0800601 }
602
603 public boolean isVerifyUnlockOnly() {
604 return mIsVerifyUnlockOnly;
605 }
606
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800607 public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
Jim Miller7751ff62014-01-14 18:57:03 -0800608 if (success) {
Tej Singhdd7bd352018-02-09 19:33:15 -0800609 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
610 StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800611 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
Jim Miller7751ff62014-01-14 18:57:03 -0800612 } else {
Tej Singhdd7bd352018-02-09 19:33:15 -0800613 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
614 StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800615 KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs);
Jim Miller7751ff62014-01-14 18:57:03 -0800616 }
Steven Wu6ef24b22019-03-11 17:14:11 -0400617 mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
618 .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
Jim Miller7751ff62014-01-14 18:57:03 -0800619 }
620
Andrew Lee72b46d42015-01-30 13:23:21 -0800621 public void reset() {
622 mSecurityCallback.reset();
623 }
Aarthi Balachander0a427ef2018-07-13 15:00:58 -0700624
625 public void onCancelClicked() {
626 mSecurityCallback.onCancelClicked();
627 }
Jim Miller7751ff62014-01-14 18:57:03 -0800628 };
629
630 // The following is used to ignore callbacks from SecurityViews that are no longer current
631 // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
632 // state for the current security method.
633 private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
634 @Override
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200635 public void userActivity() { }
Jim Miller7751ff62014-01-14 18:57:03 -0800636 @Override
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800637 public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
Jim Miller7751ff62014-01-14 18:57:03 -0800638 @Override
639 public boolean isVerifyUnlockOnly() { return false; }
640 @Override
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700641 public void dismiss(boolean securityVerified, int targetUserId) { }
Andrew Lee72b46d42015-01-30 13:23:21 -0800642 @Override
643 public void reset() {}
Jim Miller7751ff62014-01-14 18:57:03 -0800644 };
645
646 private int getSecurityViewIdForMode(SecurityMode securityMode) {
647 switch (securityMode) {
Jim Miller7751ff62014-01-14 18:57:03 -0800648 case Pattern: return R.id.keyguard_pattern_view;
649 case PIN: return R.id.keyguard_pin_view;
650 case Password: return R.id.keyguard_password_view;
Jim Miller7751ff62014-01-14 18:57:03 -0800651 case SimPin: return R.id.keyguard_sim_pin_view;
652 case SimPuk: return R.id.keyguard_sim_puk_view;
653 }
654 return 0;
655 }
656
Lucas Dupine17ce522017-07-17 15:45:06 -0700657 @VisibleForTesting
658 public int getLayoutIdFor(SecurityMode securityMode) {
Jim Miller7751ff62014-01-14 18:57:03 -0800659 switch (securityMode) {
Jim Miller7751ff62014-01-14 18:57:03 -0800660 case Pattern: return R.layout.keyguard_pattern_view;
661 case PIN: return R.layout.keyguard_pin_view;
662 case Password: return R.layout.keyguard_password_view;
Jim Miller7751ff62014-01-14 18:57:03 -0800663 case SimPin: return R.layout.keyguard_sim_pin_view;
664 case SimPuk: return R.layout.keyguard_sim_puk_view;
665 default:
666 return 0;
667 }
668 }
669
670 public SecurityMode getSecurityMode() {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700671 return mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser());
Jim Miller7751ff62014-01-14 18:57:03 -0800672 }
673
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100674 public SecurityMode getCurrentSecurityMode() {
675 return mCurrentSecuritySelection;
676 }
677
Lucas Dupin27321c42019-03-20 16:22:24 -0700678 public KeyguardSecurityView getCurrentSecurityView() {
679 return mCurrentSecurityView;
680 }
681
Jim Miller7751ff62014-01-14 18:57:03 -0800682 public void verifyUnlock() {
683 mIsVerifyUnlockOnly = true;
684 showSecurityScreen(getSecurityMode());
685 }
686
687 public SecurityMode getCurrentSecuritySelection() {
688 return mCurrentSecuritySelection;
689 }
690
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700691 public void dismiss(boolean authenticated, int targetUserId) {
692 mCallback.dismiss(authenticated, targetUserId);
Jim Miller7751ff62014-01-14 18:57:03 -0800693 }
694
695 public boolean needsInput() {
696 return mSecurityViewFlipper.needsInput();
697 }
698
699 @Override
700 public void setKeyguardCallback(KeyguardSecurityCallback callback) {
701 mSecurityViewFlipper.setKeyguardCallback(callback);
702 }
703
704 @Override
705 public void reset() {
706 mSecurityViewFlipper.reset();
707 }
708
709 @Override
710 public KeyguardSecurityCallback getCallback() {
711 return mSecurityViewFlipper.getCallback();
712 }
713
714 @Override
Selim Cinek3122fa82015-06-18 01:38:59 -0700715 public void showPromptReason(int reason) {
716 if (mCurrentSecuritySelection != SecurityMode.None) {
Adrian Roos569edb82016-03-03 15:39:03 -0800717 if (reason != PROMPT_REASON_NONE) {
718 Log.i(TAG, "Strong auth required, reason: " + reason);
719 }
Selim Cinek3122fa82015-06-18 01:38:59 -0700720 getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
721 }
722 }
723
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800724 public void showMessage(CharSequence message, ColorStateList colorState) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700725 if (mCurrentSecuritySelection != SecurityMode.None) {
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800726 getSecurityView(mCurrentSecuritySelection).showMessage(message, colorState);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700727 }
728 }
729
Selim Cinek3122fa82015-06-18 01:38:59 -0700730 @Override
Jim Miller7751ff62014-01-14 18:57:03 -0800731 public void showUsabilityHint() {
732 mSecurityViewFlipper.showUsabilityHint();
733 }
734
Jim Miller838906b2012-10-19 18:41:25 -0700735}
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500736