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 android.app.StatusBarManager.SESSION_KEYGUARD;
20 
21 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
22 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS;
23 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY;
24 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_PASSWORD;
25 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_SIM;
26 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_PRIMARY;
27 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER;
28 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
29 import static com.android.systemui.DejankUtils.whitelistIpcs;
30 import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
31 import static com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES;
32 
33 import android.app.ActivityManager;
34 import android.app.admin.DevicePolicyManager;
35 import android.content.Intent;
36 import android.content.res.ColorStateList;
37 import android.content.res.Resources;
38 import android.hardware.biometrics.BiometricOverlayConstants;
39 import android.media.AudioManager;
40 import android.metrics.LogMaker;
41 import android.os.SystemClock;
42 import android.os.UserHandle;
43 import android.telephony.TelephonyManager;
44 import android.text.TextUtils;
45 import android.util.Log;
46 import android.util.MathUtils;
47 import android.util.Slog;
48 import android.view.KeyEvent;
49 import android.view.MotionEvent;
50 import android.view.View;
51 import android.view.ViewTreeObserver;
52 import android.widget.FrameLayout;
53 import android.window.OnBackAnimationCallback;
54 
55 import androidx.annotation.NonNull;
56 import androidx.annotation.Nullable;
57 
58 import com.android.internal.annotations.VisibleForTesting;
59 import com.android.internal.logging.InstanceId;
60 import com.android.internal.logging.MetricsLogger;
61 import com.android.internal.logging.UiEventLogger;
62 import com.android.internal.logging.nano.MetricsProto;
63 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
64 import com.android.internal.widget.LockPatternUtils;
65 import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent;
66 import com.android.keyguard.KeyguardSecurityContainer.SwipeListener;
67 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
68 import com.android.keyguard.dagger.KeyguardBouncerScope;
69 import com.android.settingslib.utils.ThreadUtils;
70 import com.android.systemui.Gefingerpoken;
71 import com.android.systemui.R;
72 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor;
73 import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate;
74 import com.android.systemui.biometrics.SideFpsController;
75 import com.android.systemui.biometrics.SideFpsUiRequestSource;
76 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
77 import com.android.systemui.classifier.FalsingA11yDelegate;
78 import com.android.systemui.classifier.FalsingCollector;
79 import com.android.systemui.flags.FeatureFlags;
80 import com.android.systemui.flags.Flags;
81 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
82 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
83 import com.android.systemui.log.SessionTracker;
84 import com.android.systemui.plugins.ActivityStarter;
85 import com.android.systemui.plugins.FalsingManager;
86 import com.android.systemui.shared.system.SysUiStatsLog;
87 import com.android.systemui.statusbar.policy.ConfigurationController;
88 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
89 import com.android.systemui.statusbar.policy.KeyguardStateController;
90 import com.android.systemui.statusbar.policy.UserSwitcherController;
91 import com.android.systemui.user.domain.interactor.UserInteractor;
92 import com.android.systemui.util.ViewController;
93 import com.android.systemui.util.kotlin.JavaAdapter;
94 import com.android.systemui.util.settings.GlobalSettings;
95 
96 import java.io.File;
97 import java.util.Optional;
98 
99 import javax.inject.Inject;
100 import javax.inject.Provider;
101 
102 import kotlinx.coroutines.Job;
103 
104 /** Controller for {@link KeyguardSecurityContainer} */
105 @KeyguardBouncerScope
106 public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer>
107         implements KeyguardSecurityView {
108 
109     private static final boolean DEBUG = KeyguardConstants.DEBUG;
110     private static final String TAG = "KeyguardSecurityView";
111 
112     private final AdminSecondaryLockScreenController mAdminSecondaryLockScreenController;
113     private final LockPatternUtils mLockPatternUtils;
114     private final KeyguardUpdateMonitor mUpdateMonitor;
115     private final KeyguardSecurityModel mSecurityModel;
116     private final MetricsLogger mMetricsLogger;
117     private final UiEventLogger mUiEventLogger;
118     private final KeyguardStateController mKeyguardStateController;
119     private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
120     private final ConfigurationController mConfigurationController;
121     private final FalsingCollector mFalsingCollector;
122     private final FalsingManager mFalsingManager;
123     private final UserSwitcherController mUserSwitcherController;
124     private final GlobalSettings mGlobalSettings;
125     private final FeatureFlags mFeatureFlags;
126     private final SessionTracker mSessionTracker;
127     private final Optional<SideFpsController> mSideFpsController;
128     private final FalsingA11yDelegate mFalsingA11yDelegate;
129     private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
130     private final BouncerMessageInteractor mBouncerMessageInteractor;
131     private int mTranslationY;
132     private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
133     // Whether the volume keys should be handled by keyguard. If true, then
134     // they will be handled here for specific media types such as music, otherwise
135     // the audio service will bring up the volume dialog.
136     private static final boolean KEYGUARD_MANAGES_VOLUME = false;
137 
138     private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
139 
140     private final TelephonyManager mTelephonyManager;
141     private final ViewMediatorCallback mViewMediatorCallback;
142     private final AudioManager mAudioManager;
143     private View.OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
144     private ActivityStarter.OnDismissAction mDismissAction;
145     private Runnable mCancelAction;
146     private boolean mWillRunDismissFromKeyguard;
147 
148     private int mLastOrientation;
149 
150     private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
151     private int mCurrentUser = UserHandle.USER_NULL;
152     private UserSwitcherController.UserSwitchCallback mUserSwitchCallback =
153             new UserSwitcherController.UserSwitchCallback() {
154         @Override
155         public void onUserSwitched() {
156             if (mCurrentUser == KeyguardUpdateMonitor.getCurrentUser()) {
157                 return;
158             }
159             mCurrentUser = KeyguardUpdateMonitor.getCurrentUser();
160             showPrimarySecurityScreen(false);
161             reinflateViewFlipper((l) -> {});
162         }
163     };
164 
165     @VisibleForTesting
166     final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
167         private MotionEvent mTouchDown;
168         @Override
169         public boolean onInterceptTouchEvent(MotionEvent ev) {
170             return false;
171         }
172 
173         @Override
174         public boolean onTouchEvent(MotionEvent ev) {
175             // Do just a bit of our own falsing. People should only be tapping on the input, not
176             // swiping.
177             if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
178                 // If we're in one handed mode, the user can tap on the opposite side of the screen
179                 // to move the bouncer across. In that case, inhibit the falsing (otherwise the taps
180                 // to move the bouncer to each screen side can end up closing it instead).
181                 if (mView.isTouchOnTheOtherSideOfSecurity(ev)) {
182                     mFalsingCollector.avoidGesture();
183                 }
184 
185                 if (mTouchDown != null) {
186                     mTouchDown.recycle();
187                     mTouchDown = null;
188                 }
189                 mTouchDown = MotionEvent.obtain(ev);
190             } else if (mTouchDown != null) {
191                 if (ev.getActionMasked() == MotionEvent.ACTION_UP
192                         || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
193                     mTouchDown.recycle();
194                     mTouchDown = null;
195                 }
196             }
197             return false;
198         }
199     };
200 
201     private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
202 
203         @Override
204         public void onUserInput() {
205             mBouncerMessageInteractor.onPrimaryBouncerUserInput();
206             mKeyguardFaceAuthInteractor.onPrimaryBouncerUserInput();
207             mUpdateMonitor.cancelFaceAuth();
208         }
209 
210         @Override
211         public void dismiss(boolean authenticated, int targetId,
212                 SecurityMode expectedSecurityMode) {
213             dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false,
214                     expectedSecurityMode);
215         }
216 
217         @Override
218         public boolean dismiss(boolean authenticated, int targetId,
219                 boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
220             return showNextSecurityScreenOrFinish(
221                     authenticated, targetId, bypassSecondaryLockScreen, expectedSecurityMode);
222         }
223 
224         @Override
225         public void userActivity() {
226             mViewMediatorCallback.userActivity();
227         }
228 
229         @Override
230         public boolean isVerifyUnlockOnly() {
231             return false;
232         }
233 
234         @Override
235         public void onAttemptLockoutStart(long seconds) {
236             mBouncerMessageInteractor.onPrimaryAuthLockedOut(seconds);
237         }
238 
239         @Override
240         public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
241             if (timeoutMs == 0 && !success) {
242                 mBouncerMessageInteractor.onPrimaryAuthIncorrectAttempt();
243             }
244             int bouncerSide = SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__DEFAULT;
245             if (mView.isSidedSecurityMode()) {
246                 bouncerSide = mView.isSecurityLeftAligned()
247                         ? SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__LEFT
248                         : SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__RIGHT;
249             }
250 
251             if (success) {
252                 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
253                         SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS,
254                         bouncerSide);
255                 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
256                 // Force a garbage collection in an attempt to erase any lockscreen password left in
257                 // memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard
258                 // dismiss animation janky.
259                 ThreadUtils.postOnBackgroundThread(() -> {
260                     try {
261                         Thread.sleep(5000);
262                     } catch (InterruptedException ignored) { }
263                     System.gc();
264                     System.runFinalization();
265                     System.gc();
266                 });
267             } else {
268                 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
269                         SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE,
270                         bouncerSide);
271                 reportFailedUnlockAttempt(userId, timeoutMs);
272             }
273             mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
274                     .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
275             mUiEventLogger.log(success ? BouncerUiEvent.BOUNCER_PASSWORD_SUCCESS
276                             : BouncerUiEvent.BOUNCER_PASSWORD_FAILURE, getSessionId());
277         }
278 
279         @Override
280         public void reset() {
281             mViewMediatorCallback.resetKeyguard();
282         }
283 
284         @Override
285         public void onCancelClicked() {
286             mViewMediatorCallback.onCancelClicked();
287         }
288 
289         /**
290          * Authentication has happened and it's time to dismiss keyguard. This function
291          * should clean up and inform KeyguardViewMediator.
292          *
293          * @param fromPrimaryAuth whether the user has authenticated with primary auth like
294          *                   pattern, password or PIN but not by trust agents or fingerprint
295          * @param targetUserId a user that needs to be the foreground user at the dismissal
296          *                    completion.
297          */
298         @Override
299         public void finish(boolean fromPrimaryAuth, int targetUserId) {
300             // If there's a pending runnable because the user interacted with a widget
301             // and we're leaving keyguard, then run it.
302             boolean deferKeyguardDone = false;
303             mWillRunDismissFromKeyguard = false;
304             if (mDismissAction != null) {
305                 deferKeyguardDone = mDismissAction.onDismiss();
306                 mWillRunDismissFromKeyguard = mDismissAction.willRunAnimationOnKeyguard();
307                 mDismissAction = null;
308                 mCancelAction = null;
309             }
310             if (mViewMediatorCallback != null) {
311                 if (deferKeyguardDone) {
312                     mViewMediatorCallback.keyguardDonePending(fromPrimaryAuth, targetUserId);
313                 } else {
314                     mViewMediatorCallback.keyguardDone(fromPrimaryAuth, targetUserId);
315                 }
316             }
317 
318             if (mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
319                 mKeyguardTransitionInteractor.startDismissKeyguardTransition();
320             }
321         }
322 
323         @Override
324         public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
325             mViewMediatorCallback.setNeedsInput(needsInput);
326         }
327     };
328 
329 
330     private final SwipeListener mSwipeListener = new SwipeListener() {
331         @Override
332         public void onSwipeUp() {
333             if (!mUpdateMonitor.isFaceDetectionRunning()) {
334                 mKeyguardFaceAuthInteractor.onSwipeUpOnBouncer();
335                 boolean didFaceAuthRun = mUpdateMonitor.requestFaceAuth(
336                         FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER);
337                 mKeyguardSecurityCallback.userActivity();
338                 if (didFaceAuthRun) {
339                     showMessage(/* message= */ null, /* colorState= */ null, /* animated= */ true);
340                 }
341             }
342             if (mUpdateMonitor.isFaceEnrolled()) {
343                 mUpdateMonitor.requestActiveUnlock(
344                         ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT,
345                         "swipeUpOnBouncer");
346             }
347         }
348 
349         @Override
350         public void onSwipeDown() {
351             mViewMediatorCallback.onBouncerSwipeDown();
352         }
353     };
354     private final ConfigurationController.ConfigurationListener mConfigurationListener =
355             new ConfigurationController.ConfigurationListener() {
356                 @Override
357                 public void onThemeChanged() {
358                     reloadColors();
359                 }
360 
361                 @Override
362                 public void onUiModeChanged() {
363                     reloadColors();
364                 }
365 
366                 @Override
367                 public void onDensityOrFontScaleChanged() {
368                     KeyguardSecurityContainerController.this
369                             .onDensityOrFontScaleOrOrientationChanged();
370                 }
371 
372                 @Override
373                 public void onOrientationChanged(int orientation) {
374                     if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)) {
375                         // TODO(b/295603468)
376                         // Fix reinflation of views when flag is enabled.
377                         KeyguardSecurityContainerController.this
378                             .onDensityOrFontScaleOrOrientationChanged();
379                     }
380                 }
381             };
382     private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
383             new KeyguardUpdateMonitorCallback() {
384                 @Override
385                 public void onTrustGrantedForCurrentUser(
386                         boolean dismissKeyguard,
387                         boolean newlyUnlocked,
388                         TrustGrantFlags flags,
389                         String message
390                 ) {
391                     if (dismissKeyguard) {
392                         if (!mView.isVisibleToUser()) {
393                             // The trust agent dismissed the keyguard without the user proving
394                             // that they are present (by swiping up to show the bouncer). That's
395                             // fine if the user proved presence via some other way to the trust
396                             // agent.
397                             Log.i(TAG, "TrustAgent dismissed Keyguard.");
398                         }
399                         mKeyguardSecurityCallback.dismiss(
400                                 false /* authenticated */,
401                                 KeyguardUpdateMonitor.getCurrentUser(),
402                                 /* bypassSecondaryLockScreen */ false,
403                                 SecurityMode.Invalid
404                         );
405                     } else {
406                         if (flags.isInitiatedByUser() || flags.dismissKeyguardRequested()) {
407                             mViewMediatorCallback.playTrustedSound();
408                         }
409                     }
410                 }
411 
412                 @Override
413                 public void onDevicePolicyManagerStateChanged() {
414                     showPrimarySecurityScreen(false);
415                 }
416             };
417     private final UserInteractor mUserInteractor;
418     private final Provider<AuthenticationInteractor> mAuthenticationInteractor;
419     private final Provider<JavaAdapter> mJavaAdapter;
420     private final DeviceProvisionedController mDeviceProvisionedController;
421     @Nullable private Job mSceneTransitionCollectionJob;
422 
423     @Inject
KeyguardSecurityContainerController(KeyguardSecurityContainer view, AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory, LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardSecurityModel keyguardSecurityModel, MetricsLogger metricsLogger, UiEventLogger uiEventLogger, KeyguardStateController keyguardStateController, KeyguardSecurityViewFlipperController securityViewFlipperController, ConfigurationController configurationController, FalsingCollector falsingCollector, FalsingManager falsingManager, UserSwitcherController userSwitcherController, FeatureFlags featureFlags, GlobalSettings globalSettings, SessionTracker sessionTracker, Optional<SideFpsController> sideFpsController, FalsingA11yDelegate falsingA11yDelegate, TelephonyManager telephonyManager, ViewMediatorCallback viewMediatorCallback, AudioManager audioManager, KeyguardFaceAuthInteractor keyguardFaceAuthInteractor, BouncerMessageInteractor bouncerMessageInteractor, Provider<JavaAdapter> javaAdapter, UserInteractor userInteractor, DeviceProvisionedController deviceProvisionedController, FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate, KeyguardTransitionInteractor keyguardTransitionInteractor, Provider<AuthenticationInteractor> authenticationInteractor )424     public KeyguardSecurityContainerController(KeyguardSecurityContainer view,
425             AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
426             LockPatternUtils lockPatternUtils,
427             KeyguardUpdateMonitor keyguardUpdateMonitor,
428             KeyguardSecurityModel keyguardSecurityModel,
429             MetricsLogger metricsLogger,
430             UiEventLogger uiEventLogger,
431             KeyguardStateController keyguardStateController,
432             KeyguardSecurityViewFlipperController securityViewFlipperController,
433             ConfigurationController configurationController,
434             FalsingCollector falsingCollector,
435             FalsingManager falsingManager,
436             UserSwitcherController userSwitcherController,
437             FeatureFlags featureFlags,
438             GlobalSettings globalSettings,
439             SessionTracker sessionTracker,
440             Optional<SideFpsController> sideFpsController,
441             FalsingA11yDelegate falsingA11yDelegate,
442             TelephonyManager telephonyManager,
443             ViewMediatorCallback viewMediatorCallback,
444             AudioManager audioManager,
445             KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
446             BouncerMessageInteractor bouncerMessageInteractor,
447             Provider<JavaAdapter> javaAdapter,
448             UserInteractor userInteractor,
449             DeviceProvisionedController deviceProvisionedController,
450             FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate,
451             KeyguardTransitionInteractor keyguardTransitionInteractor,
452             Provider<AuthenticationInteractor> authenticationInteractor
453     ) {
454         super(view);
455         view.setAccessibilityDelegate(faceAuthAccessibilityDelegate);
456         mLockPatternUtils = lockPatternUtils;
457         mUpdateMonitor = keyguardUpdateMonitor;
458         mSecurityModel = keyguardSecurityModel;
459         mMetricsLogger = metricsLogger;
460         mUiEventLogger = uiEventLogger;
461         mKeyguardStateController = keyguardStateController;
462         mSecurityViewFlipperController = securityViewFlipperController;
463         mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
464                 mKeyguardSecurityCallback);
465         mConfigurationController = configurationController;
466         mLastOrientation = getResources().getConfiguration().orientation;
467         mFalsingCollector = falsingCollector;
468         mFalsingManager = falsingManager;
469         mUserSwitcherController = userSwitcherController;
470         mFeatureFlags = featureFlags;
471         mGlobalSettings = globalSettings;
472         mSessionTracker = sessionTracker;
473         mSideFpsController = sideFpsController;
474         mFalsingA11yDelegate = falsingA11yDelegate;
475         mTelephonyManager = telephonyManager;
476         mViewMediatorCallback = viewMediatorCallback;
477         mAudioManager = audioManager;
478         mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
479         mBouncerMessageInteractor = bouncerMessageInteractor;
480         mUserInteractor = userInteractor;
481         mAuthenticationInteractor = authenticationInteractor;
482         mJavaAdapter = javaAdapter;
483         mKeyguardTransitionInteractor = keyguardTransitionInteractor;
484         mDeviceProvisionedController = deviceProvisionedController;
485     }
486 
487     @Override
onInit()488     public void onInit() {
489         mSecurityViewFlipperController.init();
490         updateResources();
491         configureMode();
492     }
493 
494     @Override
onViewAttached()495     protected void onViewAttached() {
496         mUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
497         mView.setSwipeListener(mSwipeListener);
498         mView.addMotionEventListener(mGlobalTouchListener);
499         mConfigurationController.addCallback(mConfigurationListener);
500         mUserSwitcherController.addUserSwitchCallback(mUserSwitchCallback);
501         mView.setViewMediatorCallback(mViewMediatorCallback);
502         // Update ViewMediator with the current input method requirements
503         mViewMediatorCallback.setNeedsInput(needsInput());
504         mView.setOnKeyListener(mOnKeyListener);
505 
506         showPrimarySecurityScreen(false);
507 
508         if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
509             // When the scene framework says that the lockscreen has been dismissed, dismiss the
510             // keyguard here, revealing the underlying app or launcher:
511             mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow(
512                 mAuthenticationInteractor.get().isLockscreenDismissed(),
513                 isLockscreenDismissed -> {
514                     if (isLockscreenDismissed) {
515                         final int selectedUserId = mUserInteractor.getSelectedUserId();
516                         showNextSecurityScreenOrFinish(
517                             /* authenticated= */ true,
518                             selectedUserId,
519                             /* bypassSecondaryLockScreen= */ true,
520                             mSecurityModel.getSecurityMode(selectedUserId));
521                     }
522                 }
523             );
524         }
525     }
526 
527     @Override
onViewDetached()528     protected void onViewDetached() {
529         mUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
530         mConfigurationController.removeCallback(mConfigurationListener);
531         mView.removeMotionEventListener(mGlobalTouchListener);
532         mUserSwitcherController.removeUserSwitchCallback(mUserSwitchCallback);
533 
534         if (mSceneTransitionCollectionJob != null) {
535             mSceneTransitionCollectionJob.cancel(null);
536             mSceneTransitionCollectionJob = null;
537         }
538     }
539 
540     /** */
onPause()541     public void onPause() {
542         if (DEBUG) {
543             Log.d(TAG, String.format("screen off, instance %s at %s",
544                     Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
545         }
546         showPrimarySecurityScreen(true);
547         mAdminSecondaryLockScreenController.hide();
548         if (mCurrentSecurityMode != SecurityMode.None) {
549             getCurrentSecurityController(controller -> controller.onPause());
550         }
551         mView.onPause();
552         mView.clearFocus();
553     }
554 
555     /**
556      * Shows and hides the side finger print sensor animation.
557      *
558      * @param isVisible sets whether we show or hide the side fps animation
559      */
updateSideFpsVisibility(boolean isVisible)560     public void updateSideFpsVisibility(boolean isVisible) {
561         if (!mSideFpsController.isPresent()) {
562             return;
563         }
564 
565         if (isVisible) {
566             mSideFpsController.get().show(
567                     SideFpsUiRequestSource.PRIMARY_BOUNCER,
568                     BiometricOverlayConstants.REASON_AUTH_KEYGUARD
569             );
570         } else {
571             mSideFpsController.get().hide(SideFpsUiRequestSource.PRIMARY_BOUNCER);
572         }
573     }
574 
575     /**
576      * Shows the primary security screen for the user. This will be either the multi-selector
577      * or the user's security method.
578      * @param turningOff true if the device is being turned off
579      */
showPrimarySecurityScreen(boolean turningOff)580     public void showPrimarySecurityScreen(boolean turningOff) {
581         if (DEBUG) Log.d(TAG, "show()");
582         SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
583                 KeyguardUpdateMonitor.getCurrentUser()));
584         if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
585         showSecurityScreen(securityMode);
586     }
587 
588     /**
589      * Show a string explaining why the security view needs to be solved.
590      *
591      * @param reason a flag indicating which string should be shown, see
592      *               {@link KeyguardSecurityView#PROMPT_REASON_NONE},
593      *               {@link KeyguardSecurityView#PROMPT_REASON_RESTART},
594      *               {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and
595      *               {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}.
596      */
597     @Override
showPromptReason(int reason)598     public void showPromptReason(int reason) {
599         if (mCurrentSecurityMode != SecurityMode.None) {
600             if (reason != PROMPT_REASON_NONE) {
601                 Log.i(TAG, "Strong auth required, reason: " + reason);
602             }
603             getCurrentSecurityController(controller -> controller.showPromptReason(reason));
604         }
605     }
606 
607     /** Set message of bouncer title. */
showMessage(CharSequence message, ColorStateList colorState, boolean animated)608     public void showMessage(CharSequence message, ColorStateList colorState, boolean animated) {
609         if (mCurrentSecurityMode != SecurityMode.None) {
610             getCurrentSecurityController(
611                     controller -> controller.showMessage(message, colorState, animated));
612         }
613     }
614 
615     /**
616      * Sets an action to run when keyguard finishes.
617      *
618      * @param action callback to be invoked when keyguard disappear animation completes.
619      */
setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction)620     public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
621         if (mCancelAction != null) {
622             mCancelAction.run();
623         }
624         mDismissAction = action;
625         mCancelAction = cancelAction;
626     }
627 
628     /**
629      * @return whether dismiss action or cancel action has been set.
630      */
hasDismissActions()631     public boolean hasDismissActions() {
632         return mDismissAction != null || mCancelAction != null;
633     }
634 
635     /**
636      * @return will the dismissal run from the keyguard layout (instead of from bouncer)
637      */
willRunDismissFromKeyguard()638     public boolean willRunDismissFromKeyguard() {
639         return mWillRunDismissFromKeyguard;
640     }
641 
642     /**
643      * Remove any dismiss action or cancel action that was set.
644      */
cancelDismissAction()645     public void cancelDismissAction() {
646         setOnDismissAction(null, null);
647     }
648 
649     /**
650      * Potentially dismiss the current security screen, after validating that all device
651      * security has been unlocked. Otherwise show the next screen.
652      */
dismiss(boolean authenticated, int targetUserId, SecurityMode expectedSecurityMode)653     public void dismiss(boolean authenticated, int targetUserId,
654             SecurityMode expectedSecurityMode) {
655         mKeyguardSecurityCallback.dismiss(authenticated, targetUserId, expectedSecurityMode);
656     }
657 
658     /**
659      * Dismisses the keyguard by going to the next screen or making it gone.
660      * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
661      * @return True if the keyguard is done.
662      */
dismiss(int targetUserId)663     public boolean dismiss(int targetUserId) {
664         return mKeyguardSecurityCallback.dismiss(false, targetUserId, false,
665                 getCurrentSecurityMode());
666     }
667 
getCurrentSecurityMode()668     public SecurityMode getCurrentSecurityMode() {
669         return mCurrentSecurityMode;
670     }
671 
672     /**
673      * @return the top of the corresponding view.
674      */
getTop()675     public int getTop() {
676         int top = mView.getTop();
677         // The password view has an extra top padding that should be ignored.
678         if (getCurrentSecurityMode() == SecurityMode.Password) {
679             View messageArea = mView.findViewById(R.id.keyguard_message_area);
680             top += messageArea.getTop();
681         }
682         return top;
683     }
684 
685     /** Set true if the view can be interacted with */
setInteractable(boolean isInteractable)686     public void setInteractable(boolean isInteractable) {
687         mView.setInteractable(isInteractable);
688     }
689 
690     /**
691      * Dismiss keyguard due to a user unlock event.
692      */
finish(boolean primaryAuth, int currentUser)693     public void finish(boolean primaryAuth, int currentUser) {
694         mKeyguardSecurityCallback.finish(primaryAuth, currentUser);
695     }
696 
697     /**
698      * @return the text of the KeyguardMessageArea.
699      */
getTitle()700     public CharSequence getTitle() {
701         return mView.getTitle();
702     }
703 
704     /**
705      *  Resets the state of the views.
706      */
reset()707     public void reset() {
708         mView.reset();
709         mSecurityViewFlipperController.reset();
710     }
711 
712     /** Prepares views in the bouncer before starting appear animation. */
prepareToShow()713     public void prepareToShow() {
714         View bouncerUserSwitcher = mView.findViewById(R.id.keyguard_bouncer_user_switcher);
715         if (bouncerUserSwitcher != null) {
716             bouncerUserSwitcher.setAlpha(0f);
717         }
718     }
719 
720     @Override
onResume(int reason)721     public void onResume(int reason) {
722         if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
723         mView.requestFocus();
724         if (mCurrentSecurityMode != SecurityMode.None) {
725             int state = SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN;
726             if (mView.isSidedSecurityMode()) {
727                 state = mView.isSecurityLeftAligned()
728                         ? SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN_LEFT
729                         : SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN_RIGHT;
730             }
731             SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, state);
732 
733 
734             getCurrentSecurityController(controller -> controller.onResume(reason));
735         }
736         mView.onResume(
737                 mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()),
738                 mKeyguardStateController.isFaceAuthEnabled());
739     }
740 
741     /** Sets an initial message that would override the default message */
setInitialMessage()742     public void setInitialMessage() {
743         CharSequence customMessage = mViewMediatorCallback.consumeCustomMessage();
744         if (!TextUtils.isEmpty(customMessage)) {
745             showMessage(customMessage, /* colorState= */ null, /* animated= */ false);
746             return;
747         }
748         showPromptReason(mViewMediatorCallback.getBouncerPromptReason());
749     }
750 
751     /**
752      * Show the bouncer and start appear animations.
753      *
754      */
appear()755     public void appear() {
756         // We might still be collapsed and the view didn't have time to layout yet or still
757         // be small, let's wait on the predraw to do the animation in that case.
758         mView.getViewTreeObserver().addOnPreDrawListener(
759                 new ViewTreeObserver.OnPreDrawListener() {
760                     @Override
761                     public boolean onPreDraw() {
762                         mView.getViewTreeObserver().removeOnPreDrawListener(this);
763                         startAppearAnimation();
764                         return true;
765                     }
766                 });
767         mView.requestLayout();
768     }
769 
startAppearAnimation()770     public void startAppearAnimation() {
771         if (mCurrentSecurityMode != SecurityMode.None) {
772             mView.startAppearAnimation(mCurrentSecurityMode);
773             getCurrentSecurityController(controller -> controller.startAppearAnimation());
774         }
775     }
776 
777     /** Set the alpha of the security container view */
setAlpha(float alpha)778     public void setAlpha(float alpha) {
779         mView.setAlpha(alpha);
780     }
781 
startDisappearAnimation(Runnable onFinishRunnable)782     public boolean startDisappearAnimation(Runnable onFinishRunnable) {
783         if (mCurrentSecurityMode != SecurityMode.None) {
784             mView.startDisappearAnimation(mCurrentSecurityMode);
785             getCurrentSecurityController(
786                     controller -> {
787                         boolean didRunAnimation = controller.startDisappearAnimation(
788                                 onFinishRunnable);
789                         if (!didRunAnimation && onFinishRunnable != null) {
790                             onFinishRunnable.run();
791                         }
792                     });
793         }
794         return true;
795     }
796 
onStartingToHide()797     public void onStartingToHide() {
798         if (mCurrentSecurityMode != SecurityMode.None) {
799             getCurrentSecurityController(controller -> controller.onStartingToHide());
800         }
801     }
802 
803     /** Called when the bouncer changes visibility. */
onBouncerVisibilityChanged(boolean isVisible)804     public void onBouncerVisibilityChanged(boolean isVisible) {
805         if (!isVisible) {
806             mView.resetScale();
807         }
808     }
809 
810     /**
811      * Shows the next security screen if there is one.
812      * @param authenticated true if the user entered the correct authentication
813      * @param targetUserId a user that needs to be the foreground user at the finish (if called)
814      *     completion.
815      * @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
816      *     secondary lock screen requirement, if any.
817      * @param expectedSecurityMode SecurityMode that is invoking this request. SecurityMode.Invalid
818      *      indicates that no check should be done
819      * @return true if keyguard is done
820      */
showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode)821     public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
822             boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
823 
824         if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
825         if (expectedSecurityMode != SecurityMode.Invalid
826                 && expectedSecurityMode != getCurrentSecurityMode()) {
827             Log.w(TAG, "Attempted to invoke showNextSecurityScreenOrFinish with securityMode "
828                     + expectedSecurityMode + ", but current mode is " + getCurrentSecurityMode());
829             return false;
830         }
831 
832         boolean finish = false;
833         boolean primaryAuth = false;
834         int eventSubtype = -1;
835         BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
836         if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
837             finish = true;
838             eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
839             uiEvent = BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS;
840         } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
841             finish = true;
842             eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
843             uiEvent = BouncerUiEvent.BOUNCER_DISMISS_BIOMETRIC;
844         } else if (SecurityMode.None == getCurrentSecurityMode()) {
845             SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
846             if (SecurityMode.None == securityMode) {
847                 finish = true; // no security required
848                 eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
849                 uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY;
850             } else {
851                 showSecurityScreen(securityMode); // switch to the alternate security view
852             }
853         } else if (authenticated) {
854             switch (getCurrentSecurityMode()) {
855                 case Pattern:
856                 case Password:
857                 case PIN:
858                     primaryAuth = true;
859                     finish = true;
860                     eventSubtype = BOUNCER_DISMISS_PASSWORD;
861                     uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
862                     break;
863 
864                 case SimPin:
865                 case SimPuk:
866                     // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
867                     SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
868                     boolean isLockscreenDisabled = mLockPatternUtils.isLockScreenDisabled(
869                             KeyguardUpdateMonitor.getCurrentUser())
870                             || !mDeviceProvisionedController.isUserSetup(targetUserId);
871 
872                     if (securityMode == SecurityMode.None && isLockscreenDisabled) {
873                         finish = true;
874                         eventSubtype = BOUNCER_DISMISS_SIM;
875                         uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
876                     } else {
877                         showSecurityScreen(securityMode);
878                     }
879                     break;
880 
881                 default:
882                     Log.v(TAG, "Bad security screen " + getCurrentSecurityMode()
883                             + ", fail safe");
884                     showPrimarySecurityScreen(false);
885                     break;
886             }
887         }
888         // Check for device admin specified additional security measures.
889         if (finish && !bypassSecondaryLockScreen) {
890             Intent secondaryLockscreenIntent =
891                     mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
892             if (secondaryLockscreenIntent != null) {
893                 mAdminSecondaryLockScreenController.show(secondaryLockscreenIntent);
894                 return false;
895             }
896         }
897         if (eventSubtype != -1) {
898             mMetricsLogger.write(new LogMaker(MetricsProto.MetricsEvent.BOUNCER)
899                     .setType(MetricsProto.MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
900         }
901         if (uiEvent != BouncerUiEvent.UNKNOWN) {
902             mUiEventLogger.log(uiEvent, getSessionId());
903         }
904         if (finish) {
905             mKeyguardSecurityCallback.finish(primaryAuth, targetUserId);
906         }
907         return finish;
908     }
909 
910     @Override
needsInput()911     public boolean needsInput() {
912         return false;
913     }
914 
915     /**
916      * @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
917      */
918     @NonNull
getBackCallback()919     public OnBackAnimationCallback getBackCallback() {
920         return mView.getBackCallback();
921     }
922 
923     /**
924      * @return whether we should dispatch the back key event before Ime.
925      */
dispatchBackKeyEventPreIme()926     public boolean dispatchBackKeyEventPreIme() {
927         return getCurrentSecurityMode() == SecurityMode.Password;
928     }
929 
930     /**
931      * Allows the media keys to work when the keyguard is showing.
932      * The media keys should be of no interest to the actual keyguard view(s),
933      * so intercepting them here should not be of any harm.
934      * @param event The key event
935      * @return whether the event was consumed as a media key.
936      */
interceptMediaKey(KeyEvent event)937     public boolean interceptMediaKey(KeyEvent event) {
938         int keyCode = event.getKeyCode();
939         if (event.getAction() == KeyEvent.ACTION_DOWN) {
940             switch (keyCode) {
941                 case KeyEvent.KEYCODE_MEDIA_PLAY:
942                 case KeyEvent.KEYCODE_MEDIA_PAUSE:
943                 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
944                     /* Suppress PLAY/PAUSE toggle when phone is ringing or
945                      * in-call to avoid music playback */
946                     if (mTelephonyManager != null
947                             && mTelephonyManager.getCallState()
948                             != TelephonyManager.CALL_STATE_IDLE) {
949                         return true;  // suppress key event
950                     }
951                     return false;
952                 case KeyEvent.KEYCODE_MUTE:
953                 case KeyEvent.KEYCODE_HEADSETHOOK:
954                 case KeyEvent.KEYCODE_MEDIA_STOP:
955                 case KeyEvent.KEYCODE_MEDIA_NEXT:
956                 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
957                 case KeyEvent.KEYCODE_MEDIA_REWIND:
958                 case KeyEvent.KEYCODE_MEDIA_RECORD:
959                 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
960                 case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
961                     handleMediaKeyEvent(event);
962                     return true;
963                 }
964 
965                 case KeyEvent.KEYCODE_VOLUME_UP:
966                 case KeyEvent.KEYCODE_VOLUME_DOWN:
967                 case KeyEvent.KEYCODE_VOLUME_MUTE: {
968                     if (KEYGUARD_MANAGES_VOLUME) {
969                         // Volume buttons should only function for music (local or remote).
970                         // TODO: Actually handle MUTE.
971                         mAudioManager.adjustSuggestedStreamVolume(
972                                 keyCode == KeyEvent.KEYCODE_VOLUME_UP
973                                         ? AudioManager.ADJUST_RAISE
974                                         : AudioManager.ADJUST_LOWER /* direction */,
975                                 AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
976                         // Don't execute default volume behavior
977                         return true;
978                     } else {
979                         return false;
980                     }
981                 }
982             }
983         } else if (event.getAction() == KeyEvent.ACTION_UP) {
984             switch (keyCode) {
985                 case KeyEvent.KEYCODE_MUTE:
986                 case KeyEvent.KEYCODE_HEADSETHOOK:
987                 case KeyEvent.KEYCODE_MEDIA_PLAY:
988                 case KeyEvent.KEYCODE_MEDIA_PAUSE:
989                 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
990                 case KeyEvent.KEYCODE_MEDIA_STOP:
991                 case KeyEvent.KEYCODE_MEDIA_NEXT:
992                 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
993                 case KeyEvent.KEYCODE_MEDIA_REWIND:
994                 case KeyEvent.KEYCODE_MEDIA_RECORD:
995                 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
996                 case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
997                     handleMediaKeyEvent(event);
998                     return true;
999                 }
1000             }
1001         }
1002         return false;
1003     }
1004 
1005 
handleMediaKeyEvent(KeyEvent keyEvent)1006     private void handleMediaKeyEvent(KeyEvent keyEvent) {
1007         mAudioManager.dispatchMediaKeyEvent(keyEvent);
1008     }
1009 
1010     /**
1011      * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
1012      * some cases where we wish to disable it, notably when the menu button placement or technology
1013      * is prone to false positives.
1014      *
1015      * @return true if the menu key should be enabled
1016      */
shouldEnableMenuKey()1017     public boolean shouldEnableMenuKey() {
1018         final Resources res = mView.getResources();
1019         final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
1020         final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
1021         final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
1022         return !configDisabled || isTestHarness || fileOverride;
1023     }
1024 
1025 
1026     /**
1027      * Switches to the given security view unless it's already being shown, in which case
1028      * this is a no-op.
1029      *
1030      * @param securityMode
1031      */
1032     @VisibleForTesting
showSecurityScreen(SecurityMode securityMode)1033     void showSecurityScreen(SecurityMode securityMode) {
1034         if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
1035 
1036         if (securityMode == SecurityMode.Invalid || securityMode == mCurrentSecurityMode) {
1037             return;
1038         }
1039 
1040         getCurrentSecurityController(oldView -> oldView.onPause());
1041 
1042         mCurrentSecurityMode = securityMode;
1043 
1044         getCurrentSecurityController(
1045                 newView -> {
1046                     newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
1047                     mSecurityViewFlipperController.show(newView);
1048                     configureMode();
1049                     mKeyguardSecurityCallback.onSecurityModeChanged(
1050                             securityMode, newView != null && newView.needsInput());
1051 
1052                 });
1053     }
1054 
1055     /**
1056      * Returns whether the given security view should be used in a "one handed" way. This can be
1057      * used to change how the security view is drawn (e.g. take up less of the screen, and align to
1058      * one side).
1059      */
canUseOneHandedBouncer()1060     private boolean canUseOneHandedBouncer() {
1061         if (!(mCurrentSecurityMode == SecurityMode.Pattern
1062                 || mCurrentSecurityMode == SecurityMode.PIN)) {
1063             return false;
1064         }
1065 
1066         return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
1067     }
1068 
canDisplayUserSwitcher()1069     private boolean canDisplayUserSwitcher() {
1070         return mFeatureFlags.isEnabled(Flags.BOUNCER_USER_SWITCHER);
1071     }
1072 
configureMode()1073     private void configureMode() {
1074         boolean useSimSecurity = mCurrentSecurityMode == SecurityMode.SimPin
1075                 || mCurrentSecurityMode == SecurityMode.SimPuk;
1076         int mode = KeyguardSecurityContainer.MODE_DEFAULT;
1077         if (canDisplayUserSwitcher() && !useSimSecurity) {
1078             mode = KeyguardSecurityContainer.MODE_USER_SWITCHER;
1079         } else if (canUseOneHandedBouncer()) {
1080             mode = KeyguardSecurityContainer.MODE_ONE_HANDED;
1081         }
1082 
1083         mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController,
1084                 () -> showMessage(getContext().getString(R.string.keyguard_unlock_to_continue),
1085                         /* colorState= */ null, /* animated= */ true), mFalsingA11yDelegate);
1086     }
1087 
reportFailedUnlockAttempt(int userId, int timeoutMs)1088     public void reportFailedUnlockAttempt(int userId, int timeoutMs) {
1089         // +1 for this time
1090         final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
1091 
1092         if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
1093 
1094         final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
1095         final int failedAttemptsBeforeWipe =
1096                 dpm.getMaximumFailedPasswordsForWipe(null, userId);
1097 
1098         final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0
1099                 ? (failedAttemptsBeforeWipe - failedAttempts)
1100                 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
1101         if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
1102             // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
1103             // N attempts. Once we get below the grace period, we post this dialog every time as a
1104             // clear warning until the deletion fires.
1105             // Check which profile has the strictest policy for failed password attempts
1106             final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
1107             int userType = USER_TYPE_PRIMARY;
1108             if (expiringUser == userId) {
1109                 // TODO: http://b/23522538
1110                 if (expiringUser != UserHandle.USER_SYSTEM) {
1111                     userType = USER_TYPE_SECONDARY_USER;
1112                 }
1113             } else if (expiringUser != UserHandle.USER_NULL) {
1114                 userType = USER_TYPE_WORK_PROFILE;
1115             } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
1116             if (remainingBeforeWipe > 0) {
1117                 mView.showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
1118             } else {
1119                 // Too many attempts. The device will be wiped shortly.
1120                 Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
1121                 mView.showWipeDialog(failedAttempts, userType);
1122             }
1123         }
1124         mLockPatternUtils.reportFailedPasswordAttempt(userId);
1125         if (timeoutMs > 0) {
1126             mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
1127             if (!mFeatureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) {
1128                 mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils,
1129                         mSecurityModel.getSecurityMode(userId));
1130             }
1131         }
1132     }
1133 
getCurrentSecurityController( KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback)1134     private void getCurrentSecurityController(
1135             KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback) {
1136         mSecurityViewFlipperController
1137                 .getSecurityView(mCurrentSecurityMode, mKeyguardSecurityCallback,
1138                         onViewInflatedCallback);
1139     }
1140 
1141     /**
1142      * Apply keyguard configuration from the currently active resources. This can be called when the
1143      * device configuration changes, to re-apply some resources that are qualified on the device
1144      * configuration.
1145      */
updateResources()1146     public void updateResources() {
1147         int gravity;
1148 
1149         Resources resources = mView.getResources();
1150 
1151         if (resources.getBoolean(R.bool.can_use_one_handed_bouncer)) {
1152             gravity = resources.getInteger(
1153                     R.integer.keyguard_host_view_one_handed_gravity);
1154         } else {
1155             gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
1156         }
1157 
1158         mTranslationY = resources
1159                 .getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
1160         // Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
1161         // We're just changing the gravity here though (which can't be applied to RelativeLayout),
1162         // so only attempt the update if mView is inside a FrameLayout.
1163         if (mView.getLayoutParams() instanceof FrameLayout.LayoutParams) {
1164             FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mView.getLayoutParams();
1165             if (lp.gravity != gravity) {
1166                 lp.gravity = gravity;
1167                 mView.setLayoutParams(lp);
1168             }
1169         }
1170 
1171         int newOrientation = getResources().getConfiguration().orientation;
1172         if (newOrientation != mLastOrientation) {
1173             mLastOrientation = newOrientation;
1174             configureMode();
1175         }
1176     }
1177 
getSessionId()1178     private @Nullable InstanceId getSessionId() {
1179         return mSessionTracker.getSessionId(SESSION_KEYGUARD);
1180     }
1181 
1182     /** Update keyguard position based on a tapped X coordinate. */
updateKeyguardPosition(float x)1183     public void updateKeyguardPosition(float x) {
1184         mView.updatePositionByTouchX(x);
1185     }
1186 
reloadColors()1187     private void reloadColors() {
1188         mView.reloadColors();
1189     }
1190 
1191     /** Handles density or font scale changes. */
onDensityOrFontScaleOrOrientationChanged()1192     private void onDensityOrFontScaleOrOrientationChanged() {
1193         reinflateViewFlipper(controller -> mView.onDensityOrFontScaleChanged());
1194     }
1195 
1196     /**
1197      * Reinflate the view flipper child view.
1198      */
reinflateViewFlipper( KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedListener)1199     public void reinflateViewFlipper(
1200             KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedListener) {
1201         mSecurityViewFlipperController.clearViews();
1202         mSecurityViewFlipperController.asynchronouslyInflateView(mCurrentSecurityMode,
1203                 mKeyguardSecurityCallback, onViewInflatedListener);
1204     }
1205 
1206     /**
1207      * Fades and translates in/out the security screen.
1208      * Fades in as expansion approaches 0.
1209      * Animation duration is between 0.33f and 0.67f of panel expansion fraction.
1210      * @param fraction amount of the screen that should show.
1211      */
setExpansion(float fraction)1212     public void setExpansion(float fraction) {
1213         float scaledFraction = BouncerPanelExpansionCalculator.showBouncerProgress(fraction);
1214         setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
1215         mView.setTranslationY(scaledFraction * mTranslationY);
1216     }
1217 }
1218