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