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