blob: 454f44674c6661a05103cd9bd51b192668b90419 [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
Lucas Dupin8968f6a2019-08-09 17:41:15 -070018import static com.android.systemui.DejankUtils.whitelistIpcs;
19
Jim Miller7751ff62014-01-14 18:57:03 -080020import android.app.Activity;
21import android.app.AlertDialog;
Amith Yamasani3a3d2122014-10-29 11:41:31 -070022import android.app.admin.DevicePolicyManager;
Jim Miller838906b2012-10-19 18:41:25 -070023import android.content.Context;
Jason Chang1e4a4bd2018-05-22 17:30:19 +080024import android.content.res.ColorStateList;
Lucas Dupin3ac28ac2019-05-13 16:33:32 -070025import android.graphics.Rect;
Steven Wu6ef24b22019-03-11 17:14:11 -040026import android.metrics.LogMaker;
Amith Yamasani3a3d2122014-10-29 11:41:31 -070027import android.os.UserHandle;
Jim Miller838906b2012-10-19 18:41:25 -070028import android.util.AttributeSet;
Jim Miller7751ff62014-01-14 18:57:03 -080029import android.util.Log;
30import android.util.Slog;
Tej Singhdd7bd352018-02-09 19:33:15 -080031import android.util.StatsLog;
Lucas Dupin7156bc72019-05-03 19:37:39 -070032import android.util.TypedValue;
Jim Miller7751ff62014-01-14 18:57:03 -080033import android.view.LayoutInflater;
Lucas Dupin7156bc72019-05-03 19:37:39 -070034import android.view.MotionEvent;
35import android.view.VelocityTracker;
Chris Wren052999f2012-11-02 14:36:56 -040036import android.view.View;
Lucas Dupin7156bc72019-05-03 19:37:39 -070037import android.view.ViewConfiguration;
Jim Miller7751ff62014-01-14 18:57:03 -080038import android.view.WindowManager;
Jim Miller838906b2012-10-19 18:41:25 -070039import android.widget.FrameLayout;
40
Gus Prevasab336792018-11-14 13:52:20 -050041import androidx.annotation.VisibleForTesting;
Lucas Dupin7156bc72019-05-03 19:37:39 -070042import androidx.dynamicanimation.animation.DynamicAnimation;
43import androidx.dynamicanimation.animation.SpringAnimation;
Gus Prevasab336792018-11-14 13:52:20 -050044
Steven Wu6ef24b22019-03-11 17:14:11 -040045import com.android.internal.logging.MetricsLogger;
46import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jim Miller7751ff62014-01-14 18:57:03 -080047import com.android.internal.widget.LockPatternUtils;
48import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
Steven Wu6ef24b22019-03-11 17:14:11 -040049import com.android.systemui.Dependency;
Priyank Singh051353e2019-04-25 10:14:57 -070050import com.android.systemui.SystemUIFactory;
Lucas Dupin206fe562019-05-31 14:36:42 -070051import com.android.systemui.statusbar.phone.UnlockMethodCache;
Priyank Singh051353e2019-04-25 10:14:57 -070052import com.android.systemui.util.InjectionInflationController;
Jim Miller7751ff62014-01-14 18:57:03 -080053
54public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
Jorim Jaggi5cf17872014-03-26 18:31:48 +010055 private static final boolean DEBUG = KeyguardConstants.DEBUG;
Jim Miller7751ff62014-01-14 18:57:03 -080056 private static final String TAG = "KeyguardSecurityView";
Amith Yamasani3a3d2122014-10-29 11:41:31 -070057
58 private static final int USER_TYPE_PRIMARY = 1;
59 private static final int USER_TYPE_WORK_PROFILE = 2;
60 private static final int USER_TYPE_SECONDARY_USER = 3;
61
Steven Wucfe398d2019-03-21 11:32:15 -040062 // Bouncer is dismissed due to no security.
63 private static final int BOUNCER_DISMISS_NONE_SECURITY = 0;
64 // Bouncer is dismissed due to pin, password or pattern entered.
65 private static final int BOUNCER_DISMISS_PASSWORD = 1;
66 // Bouncer is dismissed due to biometric (face, fingerprint or iris) authenticated.
67 private static final int BOUNCER_DISMISS_BIOMETRIC = 2;
68 // Bouncer is dismissed due to extended access granted.
69 private static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3;
70 // Bouncer is dismissed due to sim card unlock code entered.
71 private static final int BOUNCER_DISMISS_SIM = 4;
72
Lucas Dupin7156bc72019-05-03 19:37:39 -070073 // Make the view move slower than the finger, as if the spring were applying force.
74 private static final float TOUCH_Y_MULTIPLIER = 0.25f;
75 // How much you need to drag the bouncer to trigger an auth retry (in dps.)
76 private static final float MIN_DRAG_SIZE = 10;
Lucas Dupinabb18f42019-05-20 19:10:22 -070077 // How much to scale the default slop by, to avoid accidental drags.
78 private static final float SLOP_SCALE = 2f;
Lucas Dupin7156bc72019-05-03 19:37:39 -070079
Jim Miller7751ff62014-01-14 18:57:03 -080080 private KeyguardSecurityModel mSecurityModel;
Jim Miller7751ff62014-01-14 18:57:03 -080081 private LockPatternUtils mLockPatternUtils;
82
83 private KeyguardSecurityViewFlipper mSecurityViewFlipper;
84 private boolean mIsVerifyUnlockOnly;
85 private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
Lucas Dupin27321c42019-03-20 16:22:24 -070086 private KeyguardSecurityView mCurrentSecurityView;
Jim Miller7751ff62014-01-14 18:57:03 -080087 private SecurityCallback mSecurityCallback;
Lucas Dupin7f729822017-12-13 15:27:10 -080088 private AlertDialog mAlertDialog;
Priyank Singh051353e2019-04-25 10:14:57 -070089 private InjectionInflationController mInjectionInflationController;
Lucas Dupin7156bc72019-05-03 19:37:39 -070090 private boolean mSwipeUpToRetry;
Jim Miller7751ff62014-01-14 18:57:03 -080091
Lucas Dupin7156bc72019-05-03 19:37:39 -070092 private final ViewConfiguration mViewConfiguration;
93 private final SpringAnimation mSpringAnimation;
94 private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
Adrian Roos336be7f2014-05-19 17:11:18 +020095 private final KeyguardUpdateMonitor mUpdateMonitor;
Lucas Dupin206fe562019-05-31 14:36:42 -070096 private final UnlockMethodCache mUnlockMethodCache;
Adrian Roos336be7f2014-05-19 17:11:18 +020097
Steven Wu6ef24b22019-03-11 17:14:11 -040098 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
Lucas Dupin7156bc72019-05-03 19:37:39 -070099 private float mLastTouchY = -1;
100 private int mActivePointerId = -1;
101 private boolean mIsDragging;
102 private float mStartTouchY = -1;
Steven Wu6ef24b22019-03-11 17:14:11 -0400103
Jim Miller7751ff62014-01-14 18:57:03 -0800104 // Used to notify the container when something interesting happens.
105 public interface SecurityCallback {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700106 public boolean dismiss(boolean authenticated, int targetUserId);
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200107 public void userActivity();
Jim Millerba7d94b2014-02-05 17:30:50 -0800108 public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700109
110 /**
111 * @param strongAuth wheher the user has authenticated with strong authentication like
112 * pattern, password or PIN but not by trust agents or fingerprint
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700113 * @param targetUserId a user that needs to be the foreground user at the finish completion.
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700114 */
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700115 public void finish(boolean strongAuth, int targetUserId);
Andrew Lee72b46d42015-01-30 13:23:21 -0800116 public void reset();
Aarthi Balachander0a427ef2018-07-13 15:00:58 -0700117 public void onCancelClicked();
Jim Miller7751ff62014-01-14 18:57:03 -0800118 }
119
Jim Miller838906b2012-10-19 18:41:25 -0700120 public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
121 this(context, attrs, 0);
122 }
123
124 public KeyguardSecurityContainer(Context context) {
Esteban Talaverafe0f24c2014-08-06 16:20:56 +0100125 this(context, null, 0);
Jim Miller838906b2012-10-19 18:41:25 -0700126 }
127
128 public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
Lucas Dupin987f1932017-05-13 21:02:52 -0700129 super(context, attrs, defStyle);
Jim Miller7751ff62014-01-14 18:57:03 -0800130 mSecurityModel = new KeyguardSecurityModel(context);
131 mLockPatternUtils = new LockPatternUtils(context);
Adrian Roos336be7f2014-05-19 17:11:18 +0200132 mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Lucas Dupin7156bc72019-05-03 19:37:39 -0700133 mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
Priyank Singh051353e2019-04-25 10:14:57 -0700134 mInjectionInflationController = new InjectionInflationController(
135 SystemUIFactory.getInstance().getRootComponent());
Lucas Dupin206fe562019-05-31 14:36:42 -0700136 mUnlockMethodCache = UnlockMethodCache.getInstance(context);
Lucas Dupin7156bc72019-05-03 19:37:39 -0700137 mViewConfiguration = ViewConfiguration.get(context);
Chris Wrenc3451462012-10-30 11:22:58 -0400138 }
139
Jim Miller7751ff62014-01-14 18:57:03 -0800140 public void setSecurityCallback(SecurityCallback callback) {
141 mSecurityCallback = callback;
142 }
143
144 @Override
145 public void onResume(int reason) {
Jorim Jaggif4797922014-08-04 22:49:41 +0200146 if (mCurrentSecuritySelection != SecurityMode.None) {
147 getSecurityView(mCurrentSecuritySelection).onResume(reason);
148 }
Lucas Dupin7156bc72019-05-03 19:37:39 -0700149 updateBiometricRetry();
Jim Miller7751ff62014-01-14 18:57:03 -0800150 }
151
152 @Override
153 public void onPause() {
Lucas Dupin7f729822017-12-13 15:27:10 -0800154 if (mAlertDialog != null) {
155 mAlertDialog.dismiss();
156 mAlertDialog = null;
157 }
Jorim Jaggif4797922014-08-04 22:49:41 +0200158 if (mCurrentSecuritySelection != SecurityMode.None) {
159 getSecurityView(mCurrentSecuritySelection).onPause();
160 }
Jim Miller7751ff62014-01-14 18:57:03 -0800161 }
162
Lucas Dupin7156bc72019-05-03 19:37:39 -0700163 @Override
164 public boolean shouldDelayChildPressedState() {
165 return true;
166 }
167
168 @Override
169 public boolean onInterceptTouchEvent(MotionEvent event) {
170 switch (event.getActionMasked()) {
171 case MotionEvent.ACTION_DOWN:
172 int pointerIndex = event.getActionIndex();
173 mStartTouchY = event.getY(pointerIndex);
174 mActivePointerId = event.getPointerId(pointerIndex);
175 mVelocityTracker.clear();
176 break;
177 case MotionEvent.ACTION_MOVE:
178 if (mIsDragging) {
179 return true;
180 }
181 if (!mSwipeUpToRetry) {
182 return false;
183 }
184 // Avoid dragging the pattern view
185 if (mCurrentSecurityView.disallowInterceptTouch(event)) {
186 return false;
187 }
188 int index = event.findPointerIndex(mActivePointerId);
Lucas Dupinabb18f42019-05-20 19:10:22 -0700189 float touchSlop = mViewConfiguration.getScaledTouchSlop() * SLOP_SCALE;
Lucas Dupinc26ab7512019-05-13 13:49:17 -0700190 if (mCurrentSecurityView != null && index != -1
Lucas Dupin7156bc72019-05-03 19:37:39 -0700191 && mStartTouchY - event.getY(index) > touchSlop) {
192 mIsDragging = true;
193 return true;
194 }
195 break;
196 case MotionEvent.ACTION_CANCEL:
197 case MotionEvent.ACTION_UP:
198 mIsDragging = false;
199 break;
200 }
201 return false;
202 }
203
204 @Override
205 public boolean onTouchEvent(MotionEvent event) {
206 final int action = event.getActionMasked();
207 switch (action) {
208 case MotionEvent.ACTION_MOVE:
209 mVelocityTracker.addMovement(event);
210 int pointerIndex = event.findPointerIndex(mActivePointerId);
211 float y = event.getY(pointerIndex);
212 if (mLastTouchY != -1) {
213 float dy = y - mLastTouchY;
214 setTranslationY(getTranslationY() + dy * TOUCH_Y_MULTIPLIER);
215 }
216 mLastTouchY = y;
217 break;
218 case MotionEvent.ACTION_UP:
219 case MotionEvent.ACTION_CANCEL:
220 mActivePointerId = -1;
221 mLastTouchY = -1;
222 mIsDragging = false;
223 startSpringAnimation(mVelocityTracker.getYVelocity());
224 break;
225 case MotionEvent.ACTION_POINTER_UP:
226 int index = event.getActionIndex();
227 int pointerId = event.getPointerId(index);
228 if (pointerId == mActivePointerId) {
229 // This was our active pointer going up. Choose a new
230 // active pointer and adjust accordingly.
231 final int newPointerIndex = index == 0 ? 1 : 0;
232 mLastTouchY = event.getY(newPointerIndex);
233 mActivePointerId = event.getPointerId(newPointerIndex);
234 }
235 break;
236 }
237 if (action == MotionEvent.ACTION_UP) {
238 if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
Lucas Dupin51996bb2019-05-16 17:56:43 -0700239 MIN_DRAG_SIZE, getResources().getDisplayMetrics())
240 && !mUpdateMonitor.isFaceDetectionRunning()) {
Lucas Dupin7156bc72019-05-03 19:37:39 -0700241 mUpdateMonitor.requestFaceAuth();
Lucas Dupinaad98832019-07-14 13:23:24 +0900242 mCallback.userActivity();
Lucas Dupin51996bb2019-05-16 17:56:43 -0700243 showMessage(null, null);
Lucas Dupin7156bc72019-05-03 19:37:39 -0700244 }
245 }
246 return true;
247 }
248
249 private void startSpringAnimation(float startVelocity) {
250 mSpringAnimation
251 .setStartVelocity(startVelocity)
252 .animateToFinalPosition(0);
253 }
254
Jorim Jaggic14f8292014-05-27 02:25:45 +0200255 public void startAppearAnimation() {
Jorim Jaggif4797922014-08-04 22:49:41 +0200256 if (mCurrentSecuritySelection != SecurityMode.None) {
257 getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
258 }
Jorim Jaggic14f8292014-05-27 02:25:45 +0200259 }
260
Jorim Jaggi76a16232014-08-08 17:00:47 +0200261 public boolean startDisappearAnimation(Runnable onFinishRunnable) {
262 if (mCurrentSecuritySelection != SecurityMode.None) {
263 return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation(
264 onFinishRunnable);
265 }
266 return false;
267 }
268
Lucas Dupin7156bc72019-05-03 19:37:39 -0700269 /**
270 * Enables/disables swipe up to retry on the bouncer.
271 */
272 private void updateBiometricRetry() {
273 SecurityMode securityMode = getSecurityMode();
Lucas Dupin4c507042019-07-22 16:47:34 -0700274 mSwipeUpToRetry = mUnlockMethodCache.isFaceAuthEnabled()
Lucas Dupin7156bc72019-05-03 19:37:39 -0700275 && securityMode != SecurityMode.SimPin
276 && securityMode != SecurityMode.SimPuk
Lucas Dupinfc8de932019-06-13 14:20:52 -0700277 && securityMode != SecurityMode.None;
Lucas Dupin7156bc72019-05-03 19:37:39 -0700278 }
279
Phil Weaver7d847b02018-02-13 16:02:35 -0800280 public CharSequence getTitle() {
281 return mSecurityViewFlipper.getTitle();
Jorim Jaggic1dff8c2015-02-02 14:45:39 +0100282 }
283
Jim Miller7751ff62014-01-14 18:57:03 -0800284 private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
285 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
286 KeyguardSecurityView view = null;
287 final int children = mSecurityViewFlipper.getChildCount();
288 for (int child = 0; child < children; child++) {
289 if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
290 view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
291 break;
292 }
293 }
294 int layoutId = getLayoutIdFor(securityMode);
295 if (view == null && layoutId != 0) {
296 final LayoutInflater inflater = LayoutInflater.from(mContext);
297 if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
Priyank Singh051353e2019-04-25 10:14:57 -0700298 View v = mInjectionInflationController.injectable(inflater)
299 .inflate(layoutId, mSecurityViewFlipper, false);
Jim Miller7751ff62014-01-14 18:57:03 -0800300 mSecurityViewFlipper.addView(v);
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100301 updateSecurityView(v);
Jim Miller7751ff62014-01-14 18:57:03 -0800302 view = (KeyguardSecurityView)v;
Lucas Dupinf7fd03d2018-06-26 15:58:51 -0700303 view.reset();
Jim Miller7751ff62014-01-14 18:57:03 -0800304 }
305
Jim Miller7751ff62014-01-14 18:57:03 -0800306 return view;
307 }
308
Jorim Jaggi6b88cdf2014-12-22 20:56:50 +0100309 private void updateSecurityView(View view) {
Jim Miller7751ff62014-01-14 18:57:03 -0800310 if (view instanceof KeyguardSecurityView) {
311 KeyguardSecurityView ksv = (KeyguardSecurityView) view;
312 ksv.setKeyguardCallback(mCallback);
313 ksv.setLockPatternUtils(mLockPatternUtils);
Jim Miller7751ff62014-01-14 18:57:03 -0800314 } else {
315 Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
316 }
317 }
318
319 protected void onFinishInflate() {
Alan Viverette51efddb2017-04-05 10:00:01 -0400320 mSecurityViewFlipper = findViewById(R.id.view_flipper);
Jim Miller7751ff62014-01-14 18:57:03 -0800321 mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
322 }
323
324 public void setLockPatternUtils(LockPatternUtils utils) {
325 mLockPatternUtils = utils;
326 mSecurityModel.setLockPatternUtils(utils);
327 mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
328 }
329
Lucas Dupin7156bc72019-05-03 19:37:39 -0700330 @Override
Lucas Dupin3ac28ac2019-05-13 16:33:32 -0700331 protected boolean fitSystemWindows(Rect insets) {
332 // Consume bottom insets because we're setting the padding locally (for IME and navbar.)
333 setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), insets.bottom);
334 insets.bottom = 0;
335 return false;
Lucas Dupin7156bc72019-05-03 19:37:39 -0700336 }
337
Jim Miller7751ff62014-01-14 18:57:03 -0800338 private void showDialog(String title, String message) {
Lucas Dupin7f729822017-12-13 15:27:10 -0800339 if (mAlertDialog != null) {
340 mAlertDialog.dismiss();
341 }
342
343 mAlertDialog = new AlertDialog.Builder(mContext)
Jim Miller7751ff62014-01-14 18:57:03 -0800344 .setTitle(title)
345 .setMessage(message)
Edward Savage-Jonesb08a1462016-10-05 10:29:02 +0200346 .setCancelable(false)
Jim Miller7751ff62014-01-14 18:57:03 -0800347 .setNeutralButton(R.string.ok, null)
348 .create();
349 if (!(mContext instanceof Activity)) {
Lucas Dupin7f729822017-12-13 15:27:10 -0800350 mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
Jim Miller7751ff62014-01-14 18:57:03 -0800351 }
Lucas Dupin7f729822017-12-13 15:27:10 -0800352 mAlertDialog.show();
Jim Miller7751ff62014-01-14 18:57:03 -0800353 }
354
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700355 private void showTimeoutDialog(int userId, int timeoutMs) {
Andres Morales23974272015-05-14 22:42:26 -0700356 int timeoutInSeconds = (int) timeoutMs / 1000;
Jim Miller7751ff62014-01-14 18:57:03 -0800357 int messageId = 0;
358
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700359 switch (mSecurityModel.getSecurityMode(userId)) {
Jim Miller7751ff62014-01-14 18:57:03 -0800360 case Pattern:
361 messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
362 break;
363 case PIN:
364 messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message;
365 break;
366 case Password:
367 messageId = R.string.kg_too_many_failed_password_attempts_dialog_message;
368 break;
369 // These don't have timeout dialogs.
Jim Miller7751ff62014-01-14 18:57:03 -0800370 case Invalid:
371 case None:
372 case SimPin:
373 case SimPuk:
374 break;
375 }
376
377 if (messageId != 0) {
378 final String message = mContext.getString(messageId,
Pavel Grafovb90dc432018-08-15 20:02:58 +0100379 mLockPatternUtils.getCurrentFailedPasswordAttempts(userId),
Jim Miller7751ff62014-01-14 18:57:03 -0800380 timeoutInSeconds);
381 showDialog(null, message);
382 }
383 }
384
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700385 private void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
386 String message = null;
387 switch (userType) {
388 case USER_TYPE_PRIMARY:
389 message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe,
390 attempts, remaining);
391 break;
392 case USER_TYPE_SECONDARY_USER:
393 message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_user,
394 attempts, remaining);
395 break;
396 case USER_TYPE_WORK_PROFILE:
397 message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_profile,
398 attempts, remaining);
399 break;
400 }
Jim Miller7751ff62014-01-14 18:57:03 -0800401 showDialog(null, message);
402 }
403
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700404 private void showWipeDialog(int attempts, int userType) {
405 String message = null;
406 switch (userType) {
407 case USER_TYPE_PRIMARY:
408 message = mContext.getString(R.string.kg_failed_attempts_now_wiping,
409 attempts);
410 break;
411 case USER_TYPE_SECONDARY_USER:
412 message = mContext.getString(R.string.kg_failed_attempts_now_erasing_user,
413 attempts);
414 break;
415 case USER_TYPE_WORK_PROFILE:
416 message = mContext.getString(R.string.kg_failed_attempts_now_erasing_profile,
417 attempts);
418 break;
419 }
Jim Miller7751ff62014-01-14 18:57:03 -0800420 showDialog(null, message);
421 }
422
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800423 private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
Pavel Grafovb90dc432018-08-15 20:02:58 +0100424 // +1 for this time
425 final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
Jim Miller7751ff62014-01-14 18:57:03 -0800426
427 if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
428
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700429 final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
430 final int failedAttemptsBeforeWipe =
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800431 dpm.getMaximumFailedPasswordsForWipe(null, userId);
Jim Miller7751ff62014-01-14 18:57:03 -0800432
Jim Miller7751ff62014-01-14 18:57:03 -0800433 final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
434 (failedAttemptsBeforeWipe - failedAttempts)
435 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
Jim Miller7751ff62014-01-14 18:57:03 -0800436 if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
Esteban Talaverafe0f24c2014-08-06 16:20:56 +0100437 // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
438 // N attempts. Once we get below the grace period, we post this dialog every time as a
439 // clear warning until the deletion fires.
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700440 // Check which profile has the strictest policy for failed password attempts
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800441 final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700442 int userType = USER_TYPE_PRIMARY;
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800443 if (expiringUser == userId) {
Xiaohui Chencc791bc2015-08-26 14:54:34 -0700444 // TODO: http://b/23522538
445 if (expiringUser != UserHandle.USER_SYSTEM) {
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700446 userType = USER_TYPE_SECONDARY_USER;
447 }
448 } else if (expiringUser != UserHandle.USER_NULL) {
449 userType = USER_TYPE_WORK_PROFILE;
450 } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
Jim Miller7751ff62014-01-14 18:57:03 -0800451 if (remainingBeforeWipe > 0) {
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700452 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
Jim Miller7751ff62014-01-14 18:57:03 -0800453 } else {
454 // Too many attempts. The device will be wiped shortly.
Amith Yamasani3a3d2122014-10-29 11:41:31 -0700455 Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
456 showWipeDialog(failedAttempts, userType);
Jim Miller7751ff62014-01-14 18:57:03 -0800457 }
Jim Miller7751ff62014-01-14 18:57:03 -0800458 }
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800459 mLockPatternUtils.reportFailedPasswordAttempt(userId);
Andres Morales23974272015-05-14 22:42:26 -0700460 if (timeoutMs > 0) {
Zachary Iqbal327323d2017-01-12 14:41:13 -0800461 mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700462 showTimeoutDialog(userId, timeoutMs);
Jim Miller7751ff62014-01-14 18:57:03 -0800463 }
464 }
465
466 /**
467 * Shows the primary security screen for the user. This will be either the multi-selector
468 * or the user's security method.
469 * @param turningOff true if the device is being turned off
470 */
471 void showPrimarySecurityScreen(boolean turningOff) {
Lucas Dupin8968f6a2019-08-09 17:41:15 -0700472 SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
473 KeyguardUpdateMonitor.getCurrentUser()));
Jim Miller7751ff62014-01-14 18:57:03 -0800474 if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
Jim Miller7751ff62014-01-14 18:57:03 -0800475 showSecurityScreen(securityMode);
476 }
477
478 /**
Jim Millerba7d94b2014-02-05 17:30:50 -0800479 * Shows the next security screen if there is one.
480 * @param authenticated true if the user entered the correct authentication
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700481 * @param targetUserId a user that needs to be the foreground user at the finish (if called)
482 * completion.
Jim Millerba7d94b2014-02-05 17:30:50 -0800483 * @return true if keyguard is done
484 */
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700485 boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId) {
Jim Miller7751ff62014-01-14 18:57:03 -0800486 if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
487 boolean finish = false;
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700488 boolean strongAuth = false;
Steven Wucfe398d2019-03-21 11:32:15 -0400489 int eventSubtype = -1;
490 if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
Adrian Roos336be7f2014-05-19 17:11:18 +0200491 finish = true;
Steven Wucfe398d2019-03-21 11:32:15 -0400492 eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
493 } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
494 finish = true;
495 eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
Adrian Roos336be7f2014-05-19 17:11:18 +0200496 } else if (SecurityMode.None == mCurrentSecuritySelection) {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700497 SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
Jim Miller7751ff62014-01-14 18:57:03 -0800498 if (SecurityMode.None == securityMode) {
499 finish = true; // no security required
Steven Wucfe398d2019-03-21 11:32:15 -0400500 eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
Jim Miller7751ff62014-01-14 18:57:03 -0800501 } else {
502 showSecurityScreen(securityMode); // switch to the alternate security view
503 }
504 } else if (authenticated) {
505 switch (mCurrentSecuritySelection) {
506 case Pattern:
507 case Password:
508 case PIN:
Jorim Jaggi25b4d4b2015-08-11 15:54:06 -0700509 strongAuth = true;
Jim Miller7751ff62014-01-14 18:57:03 -0800510 finish = true;
Steven Wucfe398d2019-03-21 11:32:15 -0400511 eventSubtype = BOUNCER_DISMISS_PASSWORD;
Jim Miller7751ff62014-01-14 18:57:03 -0800512 break;
513
514 case SimPin:
515 case SimPuk:
516 // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700517 SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
Jordan Liu15be64a2019-07-15 17:05:20 -0700518 if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
Selim Cinek245273e2015-06-24 13:17:56 -0400519 KeyguardUpdateMonitor.getCurrentUser())) {
Jim Miller7751ff62014-01-14 18:57:03 -0800520 finish = true;
Steven Wucfe398d2019-03-21 11:32:15 -0400521 eventSubtype = BOUNCER_DISMISS_SIM;
Jordan Liub4299d92018-09-26 12:49:11 -0700522 } else {
523 showSecurityScreen(securityMode);
Jim Miller7751ff62014-01-14 18:57:03 -0800524 }
525 break;
526
527 default:
528 Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
529 showPrimarySecurityScreen(false);
530 break;
531 }
Jim Miller7751ff62014-01-14 18:57:03 -0800532 }
Steven Wucfe398d2019-03-21 11:32:15 -0400533 if (eventSubtype != -1) {
534 mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
535 .setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
536 }
Jim Miller7751ff62014-01-14 18:57:03 -0800537 if (finish) {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700538 mSecurityCallback.finish(strongAuth, targetUserId);
Jim Miller7751ff62014-01-14 18:57:03 -0800539 }
540 return finish;
541 }
542
543 /**
544 * Switches to the given security view unless it's already being shown, in which case
545 * this is a no-op.
546 *
547 * @param securityMode
548 */
549 private void showSecurityScreen(SecurityMode securityMode) {
550 if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
551
552 if (securityMode == mCurrentSecuritySelection) return;
553
554 KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
555 KeyguardSecurityView newView = getSecurityView(securityMode);
556
557 // Emulate Activity life cycle
558 if (oldView != null) {
559 oldView.onPause();
560 oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
561 }
Jorim Jaggif4797922014-08-04 22:49:41 +0200562 if (securityMode != SecurityMode.None) {
563 newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
564 newView.setKeyguardCallback(mCallback);
565 }
Jim Miller7751ff62014-01-14 18:57:03 -0800566
567 // Find and show this child.
568 final int childCount = mSecurityViewFlipper.getChildCount();
569
570 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
571 for (int i = 0; i < childCount; i++) {
572 if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
573 mSecurityViewFlipper.setDisplayedChild(i);
574 break;
575 }
576 }
577
578 mCurrentSecuritySelection = securityMode;
Lucas Dupin27321c42019-03-20 16:22:24 -0700579 mCurrentSecurityView = newView;
Jorim Jaggif4797922014-08-04 22:49:41 +0200580 mSecurityCallback.onSecurityModeChanged(securityMode,
581 securityMode != SecurityMode.None && newView.needsInput());
Jim Miller7751ff62014-01-14 18:57:03 -0800582 }
583
584 private KeyguardSecurityViewFlipper getFlipper() {
Chris Wren052999f2012-11-02 14:36:56 -0400585 for (int i = 0; i < getChildCount(); i++) {
586 View child = getChildAt(i);
587 if (child instanceof KeyguardSecurityViewFlipper) {
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500588 return (KeyguardSecurityViewFlipper) child;
Chris Wren052999f2012-11-02 14:36:56 -0400589 }
590 }
591 return null;
592 }
593
Jim Miller7751ff62014-01-14 18:57:03 -0800594 private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200595 public void userActivity() {
Jim Miller7751ff62014-01-14 18:57:03 -0800596 if (mSecurityCallback != null) {
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200597 mSecurityCallback.userActivity();
Jim Miller7751ff62014-01-14 18:57:03 -0800598 }
599 }
600
Lucas Dupinccf67212019-08-07 12:53:02 -0700601 @Override
602 public void onUserInput() {
603 mUpdateMonitor.cancelFaceAuth();
604 }
605
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700606 public void dismiss(boolean authenticated, int targetId) {
607 mSecurityCallback.dismiss(authenticated, targetId);
Jim Miller7751ff62014-01-14 18:57:03 -0800608 }
609
610 public boolean isVerifyUnlockOnly() {
611 return mIsVerifyUnlockOnly;
612 }
613
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800614 public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
Jim Miller7751ff62014-01-14 18:57:03 -0800615 if (success) {
Tej Singhdd7bd352018-02-09 19:33:15 -0800616 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
617 StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800618 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
Jim Miller7751ff62014-01-14 18:57:03 -0800619 } else {
Tej Singhdd7bd352018-02-09 19:33:15 -0800620 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
621 StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800622 KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs);
Jim Miller7751ff62014-01-14 18:57:03 -0800623 }
Steven Wu6ef24b22019-03-11 17:14:11 -0400624 mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
625 .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
Jim Miller7751ff62014-01-14 18:57:03 -0800626 }
627
Andrew Lee72b46d42015-01-30 13:23:21 -0800628 public void reset() {
629 mSecurityCallback.reset();
630 }
Aarthi Balachander0a427ef2018-07-13 15:00:58 -0700631
632 public void onCancelClicked() {
633 mSecurityCallback.onCancelClicked();
634 }
Jim Miller7751ff62014-01-14 18:57:03 -0800635 };
636
637 // The following is used to ignore callbacks from SecurityViews that are no longer current
638 // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
639 // state for the current security method.
640 private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
641 @Override
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200642 public void userActivity() { }
Jim Miller7751ff62014-01-14 18:57:03 -0800643 @Override
Xiyuan Xiace64cea2016-01-06 08:51:16 -0800644 public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
Jim Miller7751ff62014-01-14 18:57:03 -0800645 @Override
646 public boolean isVerifyUnlockOnly() { return false; }
647 @Override
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700648 public void dismiss(boolean securityVerified, int targetUserId) { }
Andrew Lee72b46d42015-01-30 13:23:21 -0800649 @Override
Lucas Dupinccf67212019-08-07 12:53:02 -0700650 public void onUserInput() { }
651 @Override
Andrew Lee72b46d42015-01-30 13:23:21 -0800652 public void reset() {}
Jim Miller7751ff62014-01-14 18:57:03 -0800653 };
654
655 private int getSecurityViewIdForMode(SecurityMode securityMode) {
656 switch (securityMode) {
Jim Miller7751ff62014-01-14 18:57:03 -0800657 case Pattern: return R.id.keyguard_pattern_view;
658 case PIN: return R.id.keyguard_pin_view;
659 case Password: return R.id.keyguard_password_view;
Jim Miller7751ff62014-01-14 18:57:03 -0800660 case SimPin: return R.id.keyguard_sim_pin_view;
661 case SimPuk: return R.id.keyguard_sim_puk_view;
662 }
663 return 0;
664 }
665
Lucas Dupine17ce522017-07-17 15:45:06 -0700666 @VisibleForTesting
667 public int getLayoutIdFor(SecurityMode securityMode) {
Jim Miller7751ff62014-01-14 18:57:03 -0800668 switch (securityMode) {
Jim Miller7751ff62014-01-14 18:57:03 -0800669 case Pattern: return R.layout.keyguard_pattern_view;
670 case PIN: return R.layout.keyguard_pin_view;
671 case Password: return R.layout.keyguard_password_view;
Jim Miller7751ff62014-01-14 18:57:03 -0800672 case SimPin: return R.layout.keyguard_sim_pin_view;
673 case SimPuk: return R.layout.keyguard_sim_puk_view;
674 default:
675 return 0;
676 }
677 }
678
679 public SecurityMode getSecurityMode() {
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700680 return mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser());
Jim Miller7751ff62014-01-14 18:57:03 -0800681 }
682
Jorim Jaggi95e89ca2014-11-24 20:12:50 +0100683 public SecurityMode getCurrentSecurityMode() {
684 return mCurrentSecuritySelection;
685 }
686
Lucas Dupin27321c42019-03-20 16:22:24 -0700687 public KeyguardSecurityView getCurrentSecurityView() {
688 return mCurrentSecurityView;
689 }
690
Jim Miller7751ff62014-01-14 18:57:03 -0800691 public void verifyUnlock() {
692 mIsVerifyUnlockOnly = true;
693 showSecurityScreen(getSecurityMode());
694 }
695
696 public SecurityMode getCurrentSecuritySelection() {
697 return mCurrentSecuritySelection;
698 }
699
Vadim Tryshev8702ca72016-04-22 08:14:12 -0700700 public void dismiss(boolean authenticated, int targetUserId) {
701 mCallback.dismiss(authenticated, targetUserId);
Jim Miller7751ff62014-01-14 18:57:03 -0800702 }
703
704 public boolean needsInput() {
705 return mSecurityViewFlipper.needsInput();
706 }
707
708 @Override
709 public void setKeyguardCallback(KeyguardSecurityCallback callback) {
710 mSecurityViewFlipper.setKeyguardCallback(callback);
711 }
712
713 @Override
714 public void reset() {
715 mSecurityViewFlipper.reset();
716 }
717
718 @Override
719 public KeyguardSecurityCallback getCallback() {
720 return mSecurityViewFlipper.getCallback();
721 }
722
723 @Override
Selim Cinek3122fa82015-06-18 01:38:59 -0700724 public void showPromptReason(int reason) {
725 if (mCurrentSecuritySelection != SecurityMode.None) {
Adrian Roos569edb82016-03-03 15:39:03 -0800726 if (reason != PROMPT_REASON_NONE) {
727 Log.i(TAG, "Strong auth required, reason: " + reason);
728 }
Selim Cinek3122fa82015-06-18 01:38:59 -0700729 getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
730 }
731 }
732
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800733 public void showMessage(CharSequence message, ColorStateList colorState) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700734 if (mCurrentSecuritySelection != SecurityMode.None) {
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800735 getSecurityView(mCurrentSecuritySelection).showMessage(message, colorState);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700736 }
737 }
738
Selim Cinek3122fa82015-06-18 01:38:59 -0700739 @Override
Jim Miller7751ff62014-01-14 18:57:03 -0800740 public void showUsabilityHint() {
741 mSecurityViewFlipper.showUsabilityHint();
742 }
743
Jim Miller838906b2012-10-19 18:41:25 -0700744}
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500745