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