1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.keyguard;
18 
19 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
20 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS;
21 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY;
22 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_PASSWORD;
23 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_SIM;
24 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_PRIMARY;
25 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER;
26 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
27 import static com.android.systemui.DejankUtils.whitelistIpcs;
28 
29 import android.app.admin.DevicePolicyManager;
30 import android.content.Intent;
31 import android.content.res.ColorStateList;
32 import android.content.res.Configuration;
33 import android.metrics.LogMaker;
34 import android.os.UserHandle;
35 import android.provider.Settings;
36 import android.util.Log;
37 import android.util.Slog;
38 import android.view.MotionEvent;
39 
40 import com.android.internal.annotations.VisibleForTesting;
41 import com.android.internal.logging.MetricsLogger;
42 import com.android.internal.logging.UiEventLogger;
43 import com.android.internal.logging.nano.MetricsProto;
44 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
45 import com.android.internal.widget.LockPatternUtils;
46 import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent;
47 import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
48 import com.android.keyguard.KeyguardSecurityContainer.SwipeListener;
49 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
50 import com.android.keyguard.dagger.KeyguardBouncerScope;
51 import com.android.settingslib.utils.ThreadUtils;
52 import com.android.systemui.Gefingerpoken;
53 import com.android.systemui.R;
54 import com.android.systemui.classifier.FalsingCollector;
55 import com.android.systemui.shared.system.SysUiStatsLog;
56 import com.android.systemui.statusbar.policy.ConfigurationController;
57 import com.android.systemui.statusbar.policy.KeyguardStateController;
58 import com.android.systemui.util.ViewController;
59 
60 import javax.inject.Inject;
61 
62 /** Controller for {@link KeyguardSecurityContainer} */
63 @KeyguardBouncerScope
64 public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer>
65         implements KeyguardSecurityView {
66 
67     private static final boolean DEBUG = KeyguardConstants.DEBUG;
68     private static final String TAG = "KeyguardSecurityView";
69 
70     private final AdminSecondaryLockScreenController mAdminSecondaryLockScreenController;
71     private final LockPatternUtils mLockPatternUtils;
72     private final KeyguardUpdateMonitor mUpdateMonitor;
73     private final KeyguardSecurityModel mSecurityModel;
74     private final MetricsLogger mMetricsLogger;
75     private final UiEventLogger mUiEventLogger;
76     private final KeyguardStateController mKeyguardStateController;
77     private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
78     private final SecurityCallback mSecurityCallback;
79     private final ConfigurationController mConfigurationController;
80     private final FalsingCollector mFalsingCollector;
81 
82     private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
83 
84     private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
85 
86     @VisibleForTesting
87     final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
88         private MotionEvent mTouchDown;
89         @Override
90         public boolean onInterceptTouchEvent(MotionEvent ev) {
91             return false;
92         }
93 
94         @Override
95         public boolean onTouchEvent(MotionEvent ev) {
96             // Do just a bit of our own falsing. People should only be tapping on the input, not
97             // swiping.
98             if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
99                 // If we're in one handed mode, the user can tap on the opposite side of the screen
100                 // to move the bouncer across. In that case, inhibit the falsing (otherwise the taps
101                 // to move the bouncer to each screen side can end up closing it instead).
102                 if (mView.isOneHandedMode()) {
103                     if ((mView.isOneHandedModeLeftAligned() && ev.getX() > mView.getWidth() / 2f)
104                             || (!mView.isOneHandedModeLeftAligned()
105                             && ev.getX() <= mView.getWidth() / 2f)) {
106                         mFalsingCollector.avoidGesture();
107                     }
108                 }
109 
110                 if (mTouchDown != null) {
111                     mTouchDown.recycle();
112                     mTouchDown = null;
113                 }
114                 mTouchDown = MotionEvent.obtain(ev);
115             } else if (mTouchDown != null) {
116                 if (ev.getActionMasked() == MotionEvent.ACTION_UP
117                         || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
118                     mTouchDown.recycle();
119                     mTouchDown = null;
120                 }
121             }
122             return false;
123         }
124     };
125 
126     private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
127         public void userActivity() {
128             if (mSecurityCallback != null) {
129                 mSecurityCallback.userActivity();
130             }
131         }
132 
133         @Override
134         public void onUserInput() {
135             mUpdateMonitor.cancelFaceAuth();
136         }
137 
138         @Override
139         public void dismiss(boolean authenticated, int targetId) {
140             dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
141         }
142 
143         @Override
144         public void dismiss(boolean authenticated, int targetId,
145                 boolean bypassSecondaryLockScreen) {
146             mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
147         }
148 
149         public boolean isVerifyUnlockOnly() {
150             return false;
151         }
152 
153         public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
154             int bouncerSide = SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__DEFAULT;
155             if (canUseOneHandedBouncer()) {
156                 bouncerSide = isOneHandedKeyguardLeftAligned()
157                         ? SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__LEFT
158                         : SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__RIGHT;
159             }
160 
161             if (success) {
162                 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
163                         SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS,
164                         bouncerSide);
165                 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
166                 // Force a garbage collection in an attempt to erase any lockscreen password left in
167                 // memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard
168                 // dismiss animation janky.
169                 ThreadUtils.postOnBackgroundThread(() -> {
170                     try {
171                         Thread.sleep(5000);
172                     } catch (InterruptedException ignored) { }
173                     System.gc();
174                     System.runFinalization();
175                     System.gc();
176                 });
177             } else {
178                 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
179                         SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE,
180                         bouncerSide);
181                 reportFailedUnlockAttempt(userId, timeoutMs);
182             }
183             mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
184                     .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
185             mUiEventLogger.log(success ? BouncerUiEvent.BOUNCER_PASSWORD_SUCCESS
186                     : BouncerUiEvent.BOUNCER_PASSWORD_FAILURE);
187         }
188 
189         public void reset() {
190             mSecurityCallback.reset();
191         }
192 
193         public void onCancelClicked() {
194             mSecurityCallback.onCancelClicked();
195         }
196     };
197 
198 
199     private SwipeListener mSwipeListener = new SwipeListener() {
200         @Override
201         public void onSwipeUp() {
202             if (!mUpdateMonitor.isFaceDetectionRunning()) {
203                 mUpdateMonitor.requestFaceAuth(true);
204                 mKeyguardSecurityCallback.userActivity();
205                 showMessage(null, null);
206             }
207         }
208     };
209     private ConfigurationController.ConfigurationListener mConfigurationListener =
210             new ConfigurationController.ConfigurationListener() {
211                 @Override
212                 public void onThemeChanged() {
213                     mSecurityViewFlipperController.reloadColors();
214                 }
215 
216                 @Override
217                 public void onUiModeChanged() {
218                     mSecurityViewFlipperController.reloadColors();
219                 }
220             };
221 
KeyguardSecurityContainerController(KeyguardSecurityContainer view, AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory, LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardSecurityModel keyguardSecurityModel, MetricsLogger metricsLogger, UiEventLogger uiEventLogger, KeyguardStateController keyguardStateController, SecurityCallback securityCallback, KeyguardSecurityViewFlipperController securityViewFlipperController, ConfigurationController configurationController, FalsingCollector falsingCollector)222     private KeyguardSecurityContainerController(KeyguardSecurityContainer view,
223             AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
224             LockPatternUtils lockPatternUtils,
225             KeyguardUpdateMonitor keyguardUpdateMonitor,
226             KeyguardSecurityModel keyguardSecurityModel,
227             MetricsLogger metricsLogger,
228             UiEventLogger uiEventLogger,
229             KeyguardStateController keyguardStateController,
230             SecurityCallback securityCallback,
231             KeyguardSecurityViewFlipperController securityViewFlipperController,
232             ConfigurationController configurationController,
233             FalsingCollector falsingCollector) {
234         super(view);
235         mLockPatternUtils = lockPatternUtils;
236         mUpdateMonitor = keyguardUpdateMonitor;
237         mSecurityModel = keyguardSecurityModel;
238         mMetricsLogger = metricsLogger;
239         mUiEventLogger = uiEventLogger;
240         mKeyguardStateController = keyguardStateController;
241         mSecurityCallback = securityCallback;
242         mSecurityViewFlipperController = securityViewFlipperController;
243         mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
244                 mKeyguardSecurityCallback);
245         mConfigurationController = configurationController;
246         mLastOrientation = getResources().getConfiguration().orientation;
247         mFalsingCollector = falsingCollector;
248     }
249 
250     @Override
onInit()251     public void onInit() {
252         mSecurityViewFlipperController.init();
253     }
254 
255     @Override
onViewAttached()256     protected void onViewAttached() {
257         mView.setSwipeListener(mSwipeListener);
258         mView.addMotionEventListener(mGlobalTouchListener);
259         mConfigurationController.addCallback(mConfigurationListener);
260     }
261 
262     @Override
onViewDetached()263     protected void onViewDetached() {
264         mConfigurationController.removeCallback(mConfigurationListener);
265         mView.removeMotionEventListener(mGlobalTouchListener);
266     }
267 
268     /** */
onPause()269     public void onPause() {
270         mAdminSecondaryLockScreenController.hide();
271         if (mCurrentSecurityMode != SecurityMode.None) {
272             getCurrentSecurityController().onPause();
273         }
274         mView.onPause();
275     }
276 
277 
278     /**
279      * Shows the primary security screen for the user. This will be either the multi-selector
280      * or the user's security method.
281      * @param turningOff true if the device is being turned off
282      */
showPrimarySecurityScreen(boolean turningOff)283     public void showPrimarySecurityScreen(boolean turningOff) {
284         SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
285                 KeyguardUpdateMonitor.getCurrentUser()));
286         if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
287         showSecurityScreen(securityMode);
288     }
289 
290     @Override
showPromptReason(int reason)291     public void showPromptReason(int reason) {
292         if (mCurrentSecurityMode != SecurityMode.None) {
293             if (reason != PROMPT_REASON_NONE) {
294                 Log.i(TAG, "Strong auth required, reason: " + reason);
295             }
296             getCurrentSecurityController().showPromptReason(reason);
297         }
298     }
299 
showMessage(CharSequence message, ColorStateList colorState)300     public void showMessage(CharSequence message, ColorStateList colorState) {
301         if (mCurrentSecurityMode != SecurityMode.None) {
302             getCurrentSecurityController().showMessage(message, colorState);
303         }
304     }
305 
getCurrentSecurityMode()306     public SecurityMode getCurrentSecurityMode() {
307         return mCurrentSecurityMode;
308     }
309 
dismiss(boolean authenticated, int targetUserId)310     public void dismiss(boolean authenticated, int targetUserId) {
311         mKeyguardSecurityCallback.dismiss(authenticated, targetUserId);
312     }
313 
reset()314     public void reset() {
315         mView.reset();
316         mSecurityViewFlipperController.reset();
317     }
318 
getTitle()319     public CharSequence getTitle() {
320         return mView.getTitle();
321     }
322 
323     @Override
onResume(int reason)324     public void onResume(int reason) {
325         if (mCurrentSecurityMode != SecurityMode.None) {
326             int state = SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN;
327             if (canUseOneHandedBouncer()) {
328                 state = mView.isOneHandedModeLeftAligned()
329                         ? SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN_LEFT
330                         : SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN_RIGHT;
331             }
332             SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, state);
333 
334             getCurrentSecurityController().onResume(reason);
335         }
336         mView.onResume(
337                 mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()),
338                 mKeyguardStateController.isFaceAuthEnabled());
339     }
340 
startAppearAnimation()341     public void startAppearAnimation() {
342         if (mCurrentSecurityMode != SecurityMode.None) {
343             getCurrentSecurityController().startAppearAnimation();
344         }
345     }
346 
startDisappearAnimation(Runnable onFinishRunnable)347     public boolean startDisappearAnimation(Runnable onFinishRunnable) {
348         mView.startDisappearAnimation(getCurrentSecurityMode());
349 
350         if (mCurrentSecurityMode != SecurityMode.None) {
351             return getCurrentSecurityController().startDisappearAnimation(onFinishRunnable);
352         }
353 
354         return false;
355     }
356 
onStartingToHide()357     public void onStartingToHide() {
358         if (mCurrentSecurityMode != SecurityMode.None) {
359             getCurrentSecurityController().onStartingToHide();
360         }
361     }
362 
363     /**
364      * Shows the next security screen if there is one.
365      * @param authenticated true if the user entered the correct authentication
366      * @param targetUserId a user that needs to be the foreground user at the finish (if called)
367      *     completion.
368      * @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
369      *     secondary lock screen requirement, if any.
370      * @return true if keyguard is done
371      */
showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen)372     public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
373             boolean bypassSecondaryLockScreen) {
374 
375         if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
376         boolean finish = false;
377         boolean strongAuth = false;
378         int eventSubtype = -1;
379         BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
380         if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
381             finish = true;
382             eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
383             uiEvent = BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS;
384         } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
385             finish = true;
386             eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
387             uiEvent = BouncerUiEvent.BOUNCER_DISMISS_BIOMETRIC;
388         } else if (SecurityMode.None == getCurrentSecurityMode()) {
389             SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
390             if (SecurityMode.None == securityMode) {
391                 finish = true; // no security required
392                 eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
393                 uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY;
394             } else {
395                 showSecurityScreen(securityMode); // switch to the alternate security view
396             }
397         } else if (authenticated) {
398             switch (getCurrentSecurityMode()) {
399                 case Pattern:
400                 case Password:
401                 case PIN:
402                     strongAuth = true;
403                     finish = true;
404                     eventSubtype = BOUNCER_DISMISS_PASSWORD;
405                     uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
406                     break;
407 
408                 case SimPin:
409                 case SimPuk:
410                     // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
411                     SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
412                     if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
413                             KeyguardUpdateMonitor.getCurrentUser())) {
414                         finish = true;
415                         eventSubtype = BOUNCER_DISMISS_SIM;
416                         uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
417                     } else {
418                         showSecurityScreen(securityMode);
419                     }
420                     break;
421 
422                 default:
423                     Log.v(TAG, "Bad security screen " + getCurrentSecurityMode()
424                             + ", fail safe");
425                     showPrimarySecurityScreen(false);
426                     break;
427             }
428         }
429         // Check for device admin specified additional security measures.
430         if (finish && !bypassSecondaryLockScreen) {
431             Intent secondaryLockscreenIntent =
432                     mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
433             if (secondaryLockscreenIntent != null) {
434                 mAdminSecondaryLockScreenController.show(secondaryLockscreenIntent);
435                 return false;
436             }
437         }
438         if (eventSubtype != -1) {
439             mMetricsLogger.write(new LogMaker(MetricsProto.MetricsEvent.BOUNCER)
440                     .setType(MetricsProto.MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
441         }
442         if (uiEvent != BouncerUiEvent.UNKNOWN) {
443             mUiEventLogger.log(uiEvent);
444         }
445         if (finish) {
446             mSecurityCallback.finish(strongAuth, targetUserId);
447         }
448         return finish;
449     }
450 
needsInput()451     public boolean needsInput() {
452         return getCurrentSecurityController().needsInput();
453     }
454 
455     /**
456      * Switches to the given security view unless it's already being shown, in which case
457      * this is a no-op.
458      *
459      * @param securityMode
460      */
461     @VisibleForTesting
showSecurityScreen(SecurityMode securityMode)462     void showSecurityScreen(SecurityMode securityMode) {
463         if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
464 
465         if (securityMode == SecurityMode.Invalid || securityMode == mCurrentSecurityMode) {
466             return;
467         }
468 
469         KeyguardInputViewController<KeyguardInputView> oldView = getCurrentSecurityController();
470 
471         // Emulate Activity life cycle
472         if (oldView != null) {
473             oldView.onPause();
474         }
475 
476         KeyguardInputViewController<KeyguardInputView> newView = changeSecurityMode(securityMode);
477         if (newView != null) {
478             newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
479             mSecurityViewFlipperController.show(newView);
480             configureOneHandedMode();
481         }
482 
483         mSecurityCallback.onSecurityModeChanged(
484                 securityMode, newView != null && newView.needsInput());
485     }
486 
487     /** Read whether the one-handed keyguard should be on the left/right from settings. */
isOneHandedKeyguardLeftAligned()488     private boolean isOneHandedKeyguardLeftAligned() {
489         try {
490             return Settings.Global.getInt(mView.getContext().getContentResolver(),
491                     Settings.Global.ONE_HANDED_KEYGUARD_SIDE)
492                     == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
493         } catch (Settings.SettingNotFoundException ex) {
494             return true;
495         }
496     }
497 
canUseOneHandedBouncer()498     private boolean canUseOneHandedBouncer() {
499         // Is it enabled?
500         if (!getResources().getBoolean(
501                 com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) {
502             return false;
503         }
504 
505         if (!KeyguardSecurityModel.isSecurityViewOneHanded(mCurrentSecurityMode)) {
506             return false;
507         }
508 
509         return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
510     }
511 
configureOneHandedMode()512     private void configureOneHandedMode() {
513         boolean oneHandedMode = canUseOneHandedBouncer();
514 
515         mView.setOneHandedMode(oneHandedMode);
516 
517         if (oneHandedMode) {
518             mView.setOneHandedModeLeftAligned(
519                     isOneHandedKeyguardLeftAligned(), /* animate= */false);
520         }
521     }
522 
reportFailedUnlockAttempt(int userId, int timeoutMs)523     public void reportFailedUnlockAttempt(int userId, int timeoutMs) {
524         // +1 for this time
525         final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
526 
527         if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
528 
529         final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
530         final int failedAttemptsBeforeWipe =
531                 dpm.getMaximumFailedPasswordsForWipe(null, userId);
532 
533         final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0
534                 ? (failedAttemptsBeforeWipe - failedAttempts)
535                 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
536         if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
537             // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
538             // N attempts. Once we get below the grace period, we post this dialog every time as a
539             // clear warning until the deletion fires.
540             // Check which profile has the strictest policy for failed password attempts
541             final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
542             int userType = USER_TYPE_PRIMARY;
543             if (expiringUser == userId) {
544                 // TODO: http://b/23522538
545                 if (expiringUser != UserHandle.USER_SYSTEM) {
546                     userType = USER_TYPE_SECONDARY_USER;
547                 }
548             } else if (expiringUser != UserHandle.USER_NULL) {
549                 userType = USER_TYPE_WORK_PROFILE;
550             } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
551             if (remainingBeforeWipe > 0) {
552                 mView.showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
553             } else {
554                 // Too many attempts. The device will be wiped shortly.
555                 Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
556                 mView.showWipeDialog(failedAttempts, userType);
557             }
558         }
559         mLockPatternUtils.reportFailedPasswordAttempt(userId);
560         if (timeoutMs > 0) {
561             mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
562             mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils,
563                     mSecurityModel.getSecurityMode(userId));
564         }
565     }
566 
getCurrentSecurityController()567     private KeyguardInputViewController<KeyguardInputView> getCurrentSecurityController() {
568         return mSecurityViewFlipperController
569                 .getSecurityView(mCurrentSecurityMode, mKeyguardSecurityCallback);
570     }
571 
changeSecurityMode( SecurityMode securityMode)572     private KeyguardInputViewController<KeyguardInputView> changeSecurityMode(
573             SecurityMode securityMode) {
574         mCurrentSecurityMode = securityMode;
575         return getCurrentSecurityController();
576     }
577 
578     /**
579      * Apply keyguard configuration from the currently active resources. This can be called when the
580      * device configuration changes, to re-apply some resources that are qualified on the device
581      * configuration.
582      */
updateResources()583     public void updateResources() {
584         int newOrientation = getResources().getConfiguration().orientation;
585         if (newOrientation != mLastOrientation) {
586             mLastOrientation = newOrientation;
587             configureOneHandedMode();
588         }
589     }
590 
591     /** Update keyguard position based on a tapped X coordinate. */
updateKeyguardPosition(float x)592     public void updateKeyguardPosition(float x) {
593         if (mView.isOneHandedMode()) {
594             mView.setOneHandedModeLeftAligned(x <= mView.getWidth() / 2f, false);
595         }
596     }
597 
598     static class Factory {
599 
600         private final KeyguardSecurityContainer mView;
601         private final AdminSecondaryLockScreenController.Factory
602                 mAdminSecondaryLockScreenControllerFactory;
603         private final LockPatternUtils mLockPatternUtils;
604         private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
605         private final KeyguardSecurityModel mKeyguardSecurityModel;
606         private final MetricsLogger mMetricsLogger;
607         private final UiEventLogger mUiEventLogger;
608         private final KeyguardStateController mKeyguardStateController;
609         private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
610         private final ConfigurationController mConfigurationController;
611         private final FalsingCollector mFalsingCollector;
612 
613         @Inject
Factory(KeyguardSecurityContainer view, AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory, LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardSecurityModel keyguardSecurityModel, MetricsLogger metricsLogger, UiEventLogger uiEventLogger, KeyguardStateController keyguardStateController, KeyguardSecurityViewFlipperController securityViewFlipperController, ConfigurationController configurationController, FalsingCollector falsingCollector)614         Factory(KeyguardSecurityContainer view,
615                 AdminSecondaryLockScreenController.Factory
616                         adminSecondaryLockScreenControllerFactory,
617                 LockPatternUtils lockPatternUtils,
618                 KeyguardUpdateMonitor keyguardUpdateMonitor,
619                 KeyguardSecurityModel keyguardSecurityModel,
620                 MetricsLogger metricsLogger,
621                 UiEventLogger uiEventLogger,
622                 KeyguardStateController keyguardStateController,
623                 KeyguardSecurityViewFlipperController securityViewFlipperController,
624                 ConfigurationController configurationController,
625                 FalsingCollector falsingCollector) {
626             mView = view;
627             mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
628             mLockPatternUtils = lockPatternUtils;
629             mKeyguardUpdateMonitor = keyguardUpdateMonitor;
630             mKeyguardSecurityModel = keyguardSecurityModel;
631             mMetricsLogger = metricsLogger;
632             mUiEventLogger = uiEventLogger;
633             mKeyguardStateController = keyguardStateController;
634             mSecurityViewFlipperController = securityViewFlipperController;
635             mConfigurationController = configurationController;
636             mFalsingCollector = falsingCollector;
637         }
638 
create( SecurityCallback securityCallback)639         public KeyguardSecurityContainerController create(
640                 SecurityCallback securityCallback) {
641             return new KeyguardSecurityContainerController(mView,
642                     mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
643                     mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
644                     mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
645                     mConfigurationController, mFalsingCollector);
646         }
647 
648     }
649 }
650