Merge changes from topic "udfps_keyguard_view_controller_to_kotlin" into tm-qpr-dev
* changes: DO NOT MERGE [1.5/N] side fps bouncer - Update UdfpsKeyguardViewControllerBaseTest 1/N sideFPs bouncer, separate altBouncer callback Refactor file from java => kotlin
This commit is contained in:
@@ -60,7 +60,9 @@ import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.doze.DozeReceiver;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.keyguard.ScreenLifecycle;
|
||||
import com.android.systemui.keyguard.domain.interactor.BouncerInteractor;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shade.ShadeExpansionStateManager;
|
||||
@@ -119,6 +121,7 @@ public class UdfpsController implements DozeReceiver {
|
||||
@NonNull private final SystemUIDialogManager mDialogManager;
|
||||
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
@NonNull private final VibratorHelper mVibrator;
|
||||
@NonNull private final FeatureFlags mFeatureFlags;
|
||||
@NonNull private final FalsingManager mFalsingManager;
|
||||
@NonNull private final PowerManager mPowerManager;
|
||||
@NonNull private final AccessibilityManager mAccessibilityManager;
|
||||
@@ -130,6 +133,7 @@ public class UdfpsController implements DozeReceiver {
|
||||
@NonNull private final LatencyTracker mLatencyTracker;
|
||||
@VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener;
|
||||
@NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
@NonNull private final BouncerInteractor mBouncerInteractor;
|
||||
|
||||
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
|
||||
// sensors, this, in addition to a lot of the code here, will be updated.
|
||||
@@ -212,7 +216,8 @@ public class UdfpsController implements DozeReceiver {
|
||||
mUnlockedScreenOffAnimationController,
|
||||
mUdfpsDisplayMode, requestId, reason, callback,
|
||||
(view, event, fromUdfpsView) -> onTouch(requestId, event,
|
||||
fromUdfpsView), mActivityLaunchAnimator)));
|
||||
fromUdfpsView), mActivityLaunchAnimator, mFeatureFlags,
|
||||
mBouncerInteractor)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -590,6 +595,7 @@ public class UdfpsController implements DozeReceiver {
|
||||
@NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager,
|
||||
@NonNull DumpManager dumpManager,
|
||||
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
@NonNull FeatureFlags featureFlags,
|
||||
@NonNull FalsingManager falsingManager,
|
||||
@NonNull PowerManager powerManager,
|
||||
@NonNull AccessibilityManager accessibilityManager,
|
||||
@@ -608,7 +614,8 @@ public class UdfpsController implements DozeReceiver {
|
||||
@NonNull LatencyTracker latencyTracker,
|
||||
@NonNull ActivityLaunchAnimator activityLaunchAnimator,
|
||||
@NonNull Optional<AlternateUdfpsTouchProvider> alternateTouchProvider,
|
||||
@BiometricsBackground Executor biometricsExecutor) {
|
||||
@BiometricsBackground Executor biometricsExecutor,
|
||||
@NonNull BouncerInteractor bouncerInteractor) {
|
||||
mContext = context;
|
||||
mExecution = execution;
|
||||
mVibrator = vibrator;
|
||||
@@ -638,6 +645,8 @@ public class UdfpsController implements DozeReceiver {
|
||||
mActivityLaunchAnimator = activityLaunchAnimator;
|
||||
mAlternateTouchProvider = alternateTouchProvider.orElse(null);
|
||||
mBiometricExecutor = biometricsExecutor;
|
||||
mFeatureFlags = featureFlags;
|
||||
mBouncerInteractor = bouncerInteractor;
|
||||
|
||||
mOrientationListener = new BiometricDisplayListener(
|
||||
context,
|
||||
|
||||
@@ -48,6 +48,8 @@ import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.keyguard.domain.interactor.BouncerInteractor
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.shade.ShadeExpansionStateManager
|
||||
import com.android.systemui.statusbar.LockscreenShadeTransitionController
|
||||
@@ -70,29 +72,31 @@ const val SETTING_REMOVE_ENROLLMENT_UI = "udfps_overlay_remove_enrollment_ui"
|
||||
*/
|
||||
@UiThread
|
||||
class UdfpsControllerOverlay @JvmOverloads constructor(
|
||||
private val context: Context,
|
||||
fingerprintManager: FingerprintManager,
|
||||
private val inflater: LayoutInflater,
|
||||
private val windowManager: WindowManager,
|
||||
private val accessibilityManager: AccessibilityManager,
|
||||
private val statusBarStateController: StatusBarStateController,
|
||||
private val shadeExpansionStateManager: ShadeExpansionStateManager,
|
||||
private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
private val dialogManager: SystemUIDialogManager,
|
||||
private val dumpManager: DumpManager,
|
||||
private val transitionController: LockscreenShadeTransitionController,
|
||||
private val configurationController: ConfigurationController,
|
||||
private val systemClock: SystemClock,
|
||||
private val keyguardStateController: KeyguardStateController,
|
||||
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
|
||||
private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider,
|
||||
val requestId: Long,
|
||||
@ShowReason val requestReason: Int,
|
||||
private val controllerCallback: IUdfpsOverlayControllerCallback,
|
||||
private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
|
||||
private val activityLaunchAnimator: ActivityLaunchAnimator,
|
||||
private val isDebuggable: Boolean = Build.IS_DEBUGGABLE
|
||||
private val context: Context,
|
||||
fingerprintManager: FingerprintManager,
|
||||
private val inflater: LayoutInflater,
|
||||
private val windowManager: WindowManager,
|
||||
private val accessibilityManager: AccessibilityManager,
|
||||
private val statusBarStateController: StatusBarStateController,
|
||||
private val shadeExpansionStateManager: ShadeExpansionStateManager,
|
||||
private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
private val dialogManager: SystemUIDialogManager,
|
||||
private val dumpManager: DumpManager,
|
||||
private val transitionController: LockscreenShadeTransitionController,
|
||||
private val configurationController: ConfigurationController,
|
||||
private val systemClock: SystemClock,
|
||||
private val keyguardStateController: KeyguardStateController,
|
||||
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
|
||||
private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider,
|
||||
val requestId: Long,
|
||||
@ShowReason val requestReason: Int,
|
||||
private val controllerCallback: IUdfpsOverlayControllerCallback,
|
||||
private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
|
||||
private val activityLaunchAnimator: ActivityLaunchAnimator,
|
||||
private val featureFlags: FeatureFlags,
|
||||
private val bouncerInteractor: BouncerInteractor,
|
||||
private val isDebuggable: Boolean = Build.IS_DEBUGGABLE
|
||||
) {
|
||||
/** The view, when [isShowing], or null. */
|
||||
var overlayView: UdfpsView? = null
|
||||
@@ -246,7 +250,9 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
|
||||
unlockedScreenOffAnimationController,
|
||||
dialogManager,
|
||||
controller,
|
||||
activityLaunchAnimator
|
||||
activityLaunchAnimator,
|
||||
featureFlags,
|
||||
bouncerInteractor
|
||||
)
|
||||
}
|
||||
REASON_AUTH_BP -> {
|
||||
|
||||
@@ -1,548 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.biometrics;
|
||||
|
||||
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.content.res.Configuration;
|
||||
import android.util.MathUtils;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.android.keyguard.BouncerPanelExpansionCalculator;
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator;
|
||||
import com.android.systemui.animation.Interpolators;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shade.ShadeExpansionChangeEvent;
|
||||
import com.android.systemui.shade.ShadeExpansionListener;
|
||||
import com.android.systemui.shade.ShadeExpansionStateManager;
|
||||
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
|
||||
import com.android.systemui.statusbar.phone.KeyguardBouncer;
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialogManager;
|
||||
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.time.SystemClock;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Class that coordinates non-HBM animations during keyguard authentication.
|
||||
*/
|
||||
public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> {
|
||||
public static final String TAG = "UdfpsKeyguardViewCtrl";
|
||||
@NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
|
||||
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
@NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController;
|
||||
@NonNull private final ConfigurationController mConfigurationController;
|
||||
@NonNull private final SystemClock mSystemClock;
|
||||
@NonNull private final KeyguardStateController mKeyguardStateController;
|
||||
@NonNull private final UdfpsController mUdfpsController;
|
||||
@NonNull private final UnlockedScreenOffAnimationController
|
||||
mUnlockedScreenOffAnimationController;
|
||||
@NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
private final ValueAnimator mUnlockedScreenOffDozeAnimator = ValueAnimator.ofFloat(0f, 1f);
|
||||
|
||||
private boolean mShowingUdfpsBouncer;
|
||||
private boolean mUdfpsRequested;
|
||||
private float mQsExpansion;
|
||||
private boolean mFaceDetectRunning;
|
||||
private int mStatusBarState;
|
||||
private float mTransitionToFullShadeProgress;
|
||||
private float mLastDozeAmount;
|
||||
private long mLastUdfpsBouncerShowTime = -1;
|
||||
private float mPanelExpansionFraction;
|
||||
private boolean mLaunchTransitionFadingAway;
|
||||
private boolean mIsLaunchingActivity;
|
||||
private float mActivityLaunchProgress;
|
||||
|
||||
/**
|
||||
* hidden amount of pin/pattern/password bouncer
|
||||
* {@link KeyguardBouncer#EXPANSION_VISIBLE} (0f) to
|
||||
* {@link KeyguardBouncer#EXPANSION_HIDDEN} (1f)
|
||||
*/
|
||||
private float mInputBouncerHiddenAmount;
|
||||
private boolean mIsGenericBouncerShowing; // whether UDFPS bouncer or input bouncer is visible
|
||||
|
||||
protected UdfpsKeyguardViewController(
|
||||
@NonNull UdfpsKeyguardView view,
|
||||
@NonNull StatusBarStateController statusBarStateController,
|
||||
@NonNull ShadeExpansionStateManager shadeExpansionStateManager,
|
||||
@NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager,
|
||||
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
@NonNull DumpManager dumpManager,
|
||||
@NonNull LockscreenShadeTransitionController transitionController,
|
||||
@NonNull ConfigurationController configurationController,
|
||||
@NonNull SystemClock systemClock,
|
||||
@NonNull KeyguardStateController keyguardStateController,
|
||||
@NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
|
||||
@NonNull SystemUIDialogManager systemUIDialogManager,
|
||||
@NonNull UdfpsController udfpsController,
|
||||
@NonNull ActivityLaunchAnimator activityLaunchAnimator) {
|
||||
super(view, statusBarStateController, shadeExpansionStateManager, systemUIDialogManager,
|
||||
dumpManager);
|
||||
mKeyguardViewManager = statusBarKeyguardViewManager;
|
||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||
mLockScreenShadeTransitionController = transitionController;
|
||||
mConfigurationController = configurationController;
|
||||
mSystemClock = systemClock;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
mUdfpsController = udfpsController;
|
||||
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
|
||||
mActivityLaunchAnimator = activityLaunchAnimator;
|
||||
|
||||
mUnlockedScreenOffDozeAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
|
||||
mUnlockedScreenOffDozeAnimator.setInterpolator(Interpolators.ALPHA_IN);
|
||||
mUnlockedScreenOffDozeAnimator.addUpdateListener(
|
||||
new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mView.onDozeAmountChanged(
|
||||
animation.getAnimatedFraction(),
|
||||
(float) animation.getAnimatedValue(),
|
||||
UdfpsKeyguardView.ANIMATION_UNLOCKED_SCREEN_OFF);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull protected String getTag() {
|
||||
return "UdfpsKeyguardViewController";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInit() {
|
||||
super.onInit();
|
||||
mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewAttached() {
|
||||
super.onViewAttached();
|
||||
final float dozeAmount = getStatusBarStateController().getDozeAmount();
|
||||
mLastDozeAmount = dozeAmount;
|
||||
mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
|
||||
getStatusBarStateController().addCallback(mStateListener);
|
||||
|
||||
mUdfpsRequested = false;
|
||||
|
||||
mLaunchTransitionFadingAway = mKeyguardStateController.isLaunchTransitionFadingAway();
|
||||
mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
|
||||
mStatusBarState = getStatusBarStateController().getState();
|
||||
mQsExpansion = mKeyguardViewManager.getQsExpansion();
|
||||
updateGenericBouncerVisibility();
|
||||
mConfigurationController.addCallback(mConfigurationListener);
|
||||
getShadeExpansionStateManager().addExpansionListener(mShadeExpansionListener);
|
||||
updateScaleFactor();
|
||||
mView.updatePadding();
|
||||
updateAlpha();
|
||||
updatePauseAuth();
|
||||
|
||||
mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
|
||||
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(this);
|
||||
mActivityLaunchAnimator.addListener(mActivityLaunchAnimatorListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewDetached() {
|
||||
super.onViewDetached();
|
||||
mFaceDetectRunning = false;
|
||||
|
||||
mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback);
|
||||
getStatusBarStateController().removeCallback(mStateListener);
|
||||
mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
|
||||
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
|
||||
mConfigurationController.removeCallback(mConfigurationListener);
|
||||
getShadeExpansionStateManager().removeExpansionListener(mShadeExpansionListener);
|
||||
if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
|
||||
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
|
||||
}
|
||||
mActivityLaunchAnimator.removeListener(mActivityLaunchAnimatorListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, String[] args) {
|
||||
super.dump(pw, args);
|
||||
pw.println("mShowingUdfpsBouncer=" + mShowingUdfpsBouncer);
|
||||
pw.println("mFaceDetectRunning=" + mFaceDetectRunning);
|
||||
pw.println("mStatusBarState=" + StatusBarState.toString(mStatusBarState));
|
||||
pw.println("mTransitionToFullShadeProgress=" + mTransitionToFullShadeProgress);
|
||||
pw.println("mQsExpansion=" + mQsExpansion);
|
||||
pw.println("mIsGenericBouncerShowing=" + mIsGenericBouncerShowing);
|
||||
pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount);
|
||||
pw.println("mPanelExpansionFraction=" + mPanelExpansionFraction);
|
||||
pw.println("unpausedAlpha=" + mView.getUnpausedAlpha());
|
||||
pw.println("mUdfpsRequested=" + mUdfpsRequested);
|
||||
pw.println("mLaunchTransitionFadingAway=" + mLaunchTransitionFadingAway);
|
||||
pw.println("mLastDozeAmount=" + mLastDozeAmount);
|
||||
|
||||
mView.dump(pw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides non-bouncer show logic in shouldPauseAuth to still show icon.
|
||||
* @return whether the udfpsBouncer has been newly shown or hidden
|
||||
*/
|
||||
private boolean showUdfpsBouncer(boolean show) {
|
||||
if (mShowingUdfpsBouncer == show) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean udfpsAffordanceWasNotShowing = shouldPauseAuth();
|
||||
mShowingUdfpsBouncer = show;
|
||||
if (mShowingUdfpsBouncer) {
|
||||
mLastUdfpsBouncerShowTime = mSystemClock.uptimeMillis();
|
||||
}
|
||||
if (mShowingUdfpsBouncer) {
|
||||
if (udfpsAffordanceWasNotShowing) {
|
||||
mView.animateInUdfpsBouncer(null);
|
||||
}
|
||||
|
||||
if (mKeyguardStateController.isOccluded()) {
|
||||
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true);
|
||||
}
|
||||
|
||||
mView.announceForAccessibility(mView.getContext().getString(
|
||||
R.string.accessibility_fingerprint_bouncer));
|
||||
} else {
|
||||
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
|
||||
}
|
||||
|
||||
updateGenericBouncerVisibility();
|
||||
updateAlpha();
|
||||
updatePauseAuth();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the fingerprint manager is running but we want to temporarily pause
|
||||
* authentication. On the keyguard, we may want to show udfps when the shade
|
||||
* is expanded, so this can be overridden with the showBouncer method.
|
||||
*/
|
||||
public boolean shouldPauseAuth() {
|
||||
if (mShowingUdfpsBouncer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mUdfpsRequested && !getNotificationShadeVisible()
|
||||
&& (!mIsGenericBouncerShowing
|
||||
|| mInputBouncerHiddenAmount != KeyguardBouncer.EXPANSION_VISIBLE)
|
||||
&& mKeyguardStateController.isShowing()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mLaunchTransitionFadingAway) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only pause auth if we're not on the keyguard AND we're not transitioning to doze
|
||||
// (ie: dozeAmount = 0f). For the UnlockedScreenOffAnimation, the statusBarState is
|
||||
// delayed. However, we still animate in the UDFPS affordance with the
|
||||
// mUnlockedScreenOffDozeAnimator.
|
||||
if (mStatusBarState != KEYGUARD && mLastDozeAmount == 0f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mInputBouncerHiddenAmount < .5f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mView.getUnpausedAlpha() < (255 * .1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean listenForTouchesOutsideView() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTouchOutsideView() {
|
||||
maybeShowInputBouncer();
|
||||
}
|
||||
|
||||
/**
|
||||
* If we were previously showing the udfps bouncer, hide it and instead show the regular
|
||||
* (pin/pattern/password) bouncer.
|
||||
*
|
||||
* Does nothing if we weren't previously showing the UDFPS bouncer.
|
||||
*/
|
||||
private void maybeShowInputBouncer() {
|
||||
if (mShowingUdfpsBouncer && hasUdfpsBouncerShownWithMinTime()) {
|
||||
mKeyguardViewManager.showBouncer(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the udfps bouncer has shown for at least 200ms before allowing touches outside
|
||||
* of the udfps icon area to dismiss the udfps bouncer and show the pin/pattern/password
|
||||
* bouncer.
|
||||
*/
|
||||
private boolean hasUdfpsBouncerShownWithMinTime() {
|
||||
return (mSystemClock.uptimeMillis() - mLastUdfpsBouncerShowTime) > 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the progress we're currently transitioning to the full shade. 0.0f means we're not
|
||||
* transitioning yet, while 1.0f means we've fully dragged down.
|
||||
*
|
||||
* For example, start swiping down to expand the notification shade from the empty space in
|
||||
* the middle of the lock screen.
|
||||
*/
|
||||
public void setTransitionToFullShadeProgress(float progress) {
|
||||
mTransitionToFullShadeProgress = progress;
|
||||
updateAlpha();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update alpha for the UDFPS lock screen affordance. The AoD UDFPS visual affordance's
|
||||
* alpha is based on the doze amount.
|
||||
*/
|
||||
@Override
|
||||
public void updateAlpha() {
|
||||
// Fade icon on transitions to showing the status bar or bouncer, but if mUdfpsRequested,
|
||||
// then the keyguard is occluded by some application - so instead use the input bouncer
|
||||
// hidden amount to determine the fade.
|
||||
float expansion = mUdfpsRequested ? mInputBouncerHiddenAmount : mPanelExpansionFraction;
|
||||
|
||||
int alpha = mShowingUdfpsBouncer ? 255
|
||||
: (int) MathUtils.constrain(
|
||||
MathUtils.map(.5f, .9f, 0f, 255f, expansion),
|
||||
0f, 255f);
|
||||
|
||||
if (!mShowingUdfpsBouncer) {
|
||||
// swipe from top of the lockscreen to expand full QS:
|
||||
alpha *= (1.0f - Interpolators.EMPHASIZED_DECELERATE.getInterpolation(mQsExpansion));
|
||||
|
||||
// swipe from the middle (empty space) of lockscreen to expand the notification shade:
|
||||
alpha *= (1.0f - mTransitionToFullShadeProgress);
|
||||
|
||||
// Fade out the icon if we are animating an activity launch over the lockscreen and the
|
||||
// activity didn't request the UDFPS.
|
||||
if (mIsLaunchingActivity && !mUdfpsRequested) {
|
||||
alpha *= (1.0f - mActivityLaunchProgress);
|
||||
}
|
||||
|
||||
// Fade out alpha when a dialog is shown
|
||||
// Fade in alpha when a dialog is hidden
|
||||
alpha *= mView.getDialogSuggestedAlpha();
|
||||
}
|
||||
mView.setUnpausedAlpha(alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates mIsGenericBouncerShowing (whether any bouncer is showing) and updates the
|
||||
* mInputBouncerHiddenAmount to reflect whether the input bouncer is fully showing or not.
|
||||
*/
|
||||
private void updateGenericBouncerVisibility() {
|
||||
mIsGenericBouncerShowing = mKeyguardViewManager.isBouncerShowing(); // includes altBouncer
|
||||
final boolean altBouncerShowing = mKeyguardViewManager.isShowingAlternateAuth();
|
||||
if (altBouncerShowing || !mKeyguardViewManager.bouncerIsOrWillBeShowing()) {
|
||||
mInputBouncerHiddenAmount = 1f;
|
||||
} else if (mIsGenericBouncerShowing) {
|
||||
// input bouncer is fully showing
|
||||
mInputBouncerHiddenAmount = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the scale factor based on the device's resolution.
|
||||
*/
|
||||
private void updateScaleFactor() {
|
||||
if (mUdfpsController != null && mUdfpsController.mOverlayParams != null) {
|
||||
mView.setScaleFactor(mUdfpsController.mOverlayParams.getScaleFactor());
|
||||
}
|
||||
}
|
||||
|
||||
private final StatusBarStateController.StateListener mStateListener =
|
||||
new StatusBarStateController.StateListener() {
|
||||
@Override
|
||||
public void onDozeAmountChanged(float linear, float eased) {
|
||||
if (mLastDozeAmount < linear) {
|
||||
showUdfpsBouncer(false);
|
||||
}
|
||||
mUnlockedScreenOffDozeAnimator.cancel();
|
||||
final boolean animatingFromUnlockedScreenOff =
|
||||
mUnlockedScreenOffAnimationController.isAnimationPlaying();
|
||||
if (animatingFromUnlockedScreenOff && linear != 0f) {
|
||||
// we manually animate the fade in of the UDFPS icon since the unlocked
|
||||
// screen off animation prevents the doze amounts to be incrementally eased in
|
||||
mUnlockedScreenOffDozeAnimator.start();
|
||||
} else {
|
||||
mView.onDozeAmountChanged(linear, eased,
|
||||
UdfpsKeyguardView.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN);
|
||||
}
|
||||
|
||||
mLastDozeAmount = linear;
|
||||
updatePauseAuth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateChanged(int statusBarState) {
|
||||
mStatusBarState = statusBarState;
|
||||
updateAlpha();
|
||||
updatePauseAuth();
|
||||
}
|
||||
};
|
||||
|
||||
private final StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor =
|
||||
new StatusBarKeyguardViewManager.AlternateAuthInterceptor() {
|
||||
@Override
|
||||
public boolean showAlternateAuthBouncer() {
|
||||
return showUdfpsBouncer(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hideAlternateAuthBouncer() {
|
||||
return showUdfpsBouncer(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowingAlternateAuthBouncer() {
|
||||
return mShowingUdfpsBouncer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestUdfps(boolean request, int color) {
|
||||
mUdfpsRequested = request;
|
||||
mView.requestUdfps(request, color);
|
||||
updateAlpha();
|
||||
updatePauseAuth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnimating() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the amount qs is expanded. Forxample, swipe down from the top of the
|
||||
* lock screen to start the full QS expansion.
|
||||
*/
|
||||
@Override
|
||||
public void setQsExpansion(float qsExpansion) {
|
||||
mQsExpansion = qsExpansion;
|
||||
updateAlpha();
|
||||
updatePauseAuth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(MotionEvent event) {
|
||||
if (mTransitionToFullShadeProgress != 0) {
|
||||
return false;
|
||||
}
|
||||
return mUdfpsController.onTouch(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBouncerExpansionChanged(float expansion) {
|
||||
mInputBouncerHiddenAmount = expansion;
|
||||
updateAlpha();
|
||||
updatePauseAuth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only called on primary auth bouncer changes, not on whether the UDFPS bouncer
|
||||
* visibility changes.
|
||||
*/
|
||||
@Override
|
||||
public void onBouncerVisibilityChanged() {
|
||||
updateGenericBouncerVisibility();
|
||||
updateAlpha();
|
||||
updatePauseAuth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.println(getTag());
|
||||
}
|
||||
};
|
||||
|
||||
private final ConfigurationController.ConfigurationListener mConfigurationListener =
|
||||
new ConfigurationController.ConfigurationListener() {
|
||||
@Override
|
||||
public void onUiModeChanged() {
|
||||
mView.updateColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onThemeChanged() {
|
||||
mView.updateColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigChanged(Configuration newConfig) {
|
||||
updateScaleFactor();
|
||||
mView.updatePadding();
|
||||
mView.updateColor();
|
||||
}
|
||||
};
|
||||
|
||||
private final ShadeExpansionListener mShadeExpansionListener = new ShadeExpansionListener() {
|
||||
@Override
|
||||
public void onPanelExpansionChanged(ShadeExpansionChangeEvent event) {
|
||||
float fraction = event.getFraction();
|
||||
mPanelExpansionFraction =
|
||||
mKeyguardViewManager.isBouncerInTransit() ? BouncerPanelExpansionCalculator
|
||||
.aboutToShowBouncerProgress(fraction) : fraction;
|
||||
updateAlpha();
|
||||
updatePauseAuth();
|
||||
}
|
||||
};
|
||||
|
||||
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
|
||||
new KeyguardStateController.Callback() {
|
||||
@Override
|
||||
public void onLaunchTransitionFadingAwayChanged() {
|
||||
mLaunchTransitionFadingAway =
|
||||
mKeyguardStateController.isLaunchTransitionFadingAway();
|
||||
updatePauseAuth();
|
||||
}
|
||||
};
|
||||
|
||||
private final ActivityLaunchAnimator.Listener mActivityLaunchAnimatorListener =
|
||||
new ActivityLaunchAnimator.Listener() {
|
||||
@Override
|
||||
public void onLaunchAnimationStart() {
|
||||
mIsLaunchingActivity = true;
|
||||
mActivityLaunchProgress = 0f;
|
||||
updateAlpha();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLaunchAnimationEnd() {
|
||||
mIsLaunchingActivity = false;
|
||||
updateAlpha();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLaunchAnimationProgress(float linearProgress) {
|
||||
mActivityLaunchProgress = linearProgress;
|
||||
updateAlpha();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,550 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.biometrics
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.res.Configuration
|
||||
import android.util.MathUtils
|
||||
import android.view.MotionEvent
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator
|
||||
import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.keyguard.domain.interactor.BouncerInteractor
|
||||
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.shade.ShadeExpansionListener
|
||||
import com.android.systemui.shade.ShadeExpansionStateManager
|
||||
import com.android.systemui.statusbar.LockscreenShadeTransitionController
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
|
||||
import com.android.systemui.statusbar.phone.KeyguardBouncer
|
||||
import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.AlternateAuthInterceptor
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.KeyguardViewManagerCallback
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialogManager
|
||||
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import com.android.systemui.util.time.SystemClock
|
||||
import java.io.PrintWriter
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/** Class that coordinates non-HBM animations during keyguard authentication. */
|
||||
open class UdfpsKeyguardViewController
|
||||
constructor(
|
||||
private val view: UdfpsKeyguardView,
|
||||
statusBarStateController: StatusBarStateController,
|
||||
shadeExpansionStateManager: ShadeExpansionStateManager,
|
||||
private val keyguardViewManager: StatusBarKeyguardViewManager,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
dumpManager: DumpManager,
|
||||
private val lockScreenShadeTransitionController: LockscreenShadeTransitionController,
|
||||
private val configurationController: ConfigurationController,
|
||||
private val systemClock: SystemClock,
|
||||
private val keyguardStateController: KeyguardStateController,
|
||||
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
|
||||
systemUIDialogManager: SystemUIDialogManager,
|
||||
private val udfpsController: UdfpsController,
|
||||
private val activityLaunchAnimator: ActivityLaunchAnimator,
|
||||
featureFlags: FeatureFlags,
|
||||
private val bouncerInteractor: BouncerInteractor
|
||||
) :
|
||||
UdfpsAnimationViewController<UdfpsKeyguardView>(
|
||||
view,
|
||||
statusBarStateController,
|
||||
shadeExpansionStateManager,
|
||||
systemUIDialogManager,
|
||||
dumpManager
|
||||
) {
|
||||
private val isModernBouncerEnabled: Boolean = featureFlags.isEnabled(Flags.MODERN_BOUNCER)
|
||||
private var showingUdfpsBouncer = false
|
||||
private var udfpsRequested = false
|
||||
private var qsExpansion = 0f
|
||||
private var faceDetectRunning = false
|
||||
private var statusBarState = 0
|
||||
private var transitionToFullShadeProgress = 0f
|
||||
private var lastDozeAmount = 0f
|
||||
private var lastUdfpsBouncerShowTime: Long = -1
|
||||
private var panelExpansionFraction = 0f
|
||||
private var launchTransitionFadingAway = false
|
||||
private var isLaunchingActivity = false
|
||||
private var activityLaunchProgress = 0f
|
||||
private val unlockedScreenOffDozeAnimator =
|
||||
ValueAnimator.ofFloat(0f, 1f).apply {
|
||||
duration = StackStateAnimator.ANIMATION_DURATION_STANDARD.toLong()
|
||||
interpolator = Interpolators.ALPHA_IN
|
||||
addUpdateListener { animation ->
|
||||
view.onDozeAmountChanged(
|
||||
animation.animatedFraction,
|
||||
animation.animatedValue as Float,
|
||||
UdfpsKeyguardView.ANIMATION_UNLOCKED_SCREEN_OFF
|
||||
)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Hidden amount of input (pin/pattern/password) bouncer. This is used
|
||||
* [KeyguardBouncer.EXPANSION_VISIBLE] (0f) to [KeyguardBouncer.EXPANSION_HIDDEN] (1f). Only
|
||||
* used for the non-modernBouncer.
|
||||
*/
|
||||
private var inputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN
|
||||
private var inputBouncerExpansion = 0f // only used for modernBouncer
|
||||
|
||||
private val stateListener: StatusBarStateController.StateListener =
|
||||
object : StatusBarStateController.StateListener {
|
||||
override fun onDozeAmountChanged(linear: Float, eased: Float) {
|
||||
if (lastDozeAmount < linear) {
|
||||
showUdfpsBouncer(false)
|
||||
}
|
||||
unlockedScreenOffDozeAnimator.cancel()
|
||||
val animatingFromUnlockedScreenOff =
|
||||
unlockedScreenOffAnimationController.isAnimationPlaying()
|
||||
if (animatingFromUnlockedScreenOff && linear != 0f) {
|
||||
// we manually animate the fade in of the UDFPS icon since the unlocked
|
||||
// screen off animation prevents the doze amounts to be incrementally eased in
|
||||
unlockedScreenOffDozeAnimator.start()
|
||||
} else {
|
||||
view.onDozeAmountChanged(
|
||||
linear,
|
||||
eased,
|
||||
UdfpsKeyguardView.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN
|
||||
)
|
||||
}
|
||||
lastDozeAmount = linear
|
||||
updatePauseAuth()
|
||||
}
|
||||
|
||||
override fun onStateChanged(statusBarState: Int) {
|
||||
this@UdfpsKeyguardViewController.statusBarState = statusBarState
|
||||
updateAlpha()
|
||||
updatePauseAuth()
|
||||
}
|
||||
}
|
||||
|
||||
private val bouncerExpansionCallback: BouncerExpansionCallback =
|
||||
object : BouncerExpansionCallback {
|
||||
override fun onExpansionChanged(expansion: Float) {
|
||||
inputBouncerHiddenAmount = expansion
|
||||
updateAlpha()
|
||||
updatePauseAuth()
|
||||
}
|
||||
|
||||
override fun onVisibilityChanged(isVisible: Boolean) {
|
||||
updateBouncerHiddenAmount()
|
||||
updateAlpha()
|
||||
updatePauseAuth()
|
||||
}
|
||||
}
|
||||
|
||||
private val configurationListener: ConfigurationController.ConfigurationListener =
|
||||
object : ConfigurationController.ConfigurationListener {
|
||||
override fun onUiModeChanged() {
|
||||
view.updateColor()
|
||||
}
|
||||
|
||||
override fun onThemeChanged() {
|
||||
view.updateColor()
|
||||
}
|
||||
|
||||
override fun onConfigChanged(newConfig: Configuration) {
|
||||
updateScaleFactor()
|
||||
view.updatePadding()
|
||||
view.updateColor()
|
||||
}
|
||||
}
|
||||
|
||||
private val shadeExpansionListener = ShadeExpansionListener { (fraction) ->
|
||||
panelExpansionFraction =
|
||||
if (keyguardViewManager.isBouncerInTransit) {
|
||||
aboutToShowBouncerProgress(fraction)
|
||||
} else {
|
||||
fraction
|
||||
}
|
||||
updateAlpha()
|
||||
updatePauseAuth()
|
||||
}
|
||||
|
||||
private val keyguardStateControllerCallback: KeyguardStateController.Callback =
|
||||
object : KeyguardStateController.Callback {
|
||||
override fun onLaunchTransitionFadingAwayChanged() {
|
||||
launchTransitionFadingAway = keyguardStateController.isLaunchTransitionFadingAway
|
||||
updatePauseAuth()
|
||||
}
|
||||
}
|
||||
|
||||
private val activityLaunchAnimatorListener: ActivityLaunchAnimator.Listener =
|
||||
object : ActivityLaunchAnimator.Listener {
|
||||
override fun onLaunchAnimationStart() {
|
||||
isLaunchingActivity = true
|
||||
activityLaunchProgress = 0f
|
||||
updateAlpha()
|
||||
}
|
||||
|
||||
override fun onLaunchAnimationEnd() {
|
||||
isLaunchingActivity = false
|
||||
updateAlpha()
|
||||
}
|
||||
|
||||
override fun onLaunchAnimationProgress(linearProgress: Float) {
|
||||
activityLaunchProgress = linearProgress
|
||||
updateAlpha()
|
||||
}
|
||||
}
|
||||
|
||||
private val statusBarKeyguardViewManagerCallback: KeyguardViewManagerCallback =
|
||||
object : KeyguardViewManagerCallback {
|
||||
override fun onQSExpansionChanged(qsExpansion: Float) {
|
||||
this@UdfpsKeyguardViewController.qsExpansion = qsExpansion
|
||||
updateAlpha()
|
||||
updatePauseAuth()
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward touches to the UdfpsController. This allows the touch to start from outside
|
||||
* the sensor area and then slide their finger into the sensor area.
|
||||
*/
|
||||
override fun onTouch(event: MotionEvent) {
|
||||
// Don't forward touches if the shade has already started expanding.
|
||||
if (transitionToFullShadeProgress != 0f) {
|
||||
return
|
||||
}
|
||||
udfpsController.onTouch(event)
|
||||
}
|
||||
}
|
||||
|
||||
private val alternateAuthInterceptor: AlternateAuthInterceptor =
|
||||
object : AlternateAuthInterceptor {
|
||||
override fun showAlternateAuthBouncer(): Boolean {
|
||||
return showUdfpsBouncer(true)
|
||||
}
|
||||
|
||||
override fun hideAlternateAuthBouncer(): Boolean {
|
||||
return showUdfpsBouncer(false)
|
||||
}
|
||||
|
||||
override fun isShowingAlternateAuthBouncer(): Boolean {
|
||||
return showingUdfpsBouncer
|
||||
}
|
||||
|
||||
override fun requestUdfps(request: Boolean, color: Int) {
|
||||
udfpsRequested = request
|
||||
view.requestUdfps(request, color)
|
||||
updateAlpha()
|
||||
updatePauseAuth()
|
||||
}
|
||||
|
||||
override fun dump(pw: PrintWriter) {
|
||||
pw.println(tag)
|
||||
}
|
||||
}
|
||||
|
||||
override val tag: String
|
||||
get() = TAG
|
||||
|
||||
override fun onInit() {
|
||||
super.onInit()
|
||||
keyguardViewManager.setAlternateAuthInterceptor(alternateAuthInterceptor)
|
||||
}
|
||||
|
||||
init {
|
||||
if (isModernBouncerEnabled) {
|
||||
view.repeatWhenAttached {
|
||||
// repeatOnLifecycle CREATED (as opposed to STARTED) because the Bouncer expansion
|
||||
// can make the view not visible; and we still want to listen for events
|
||||
// that may make the view visible again.
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) { listenForBouncerExpansion(this) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal suspend fun listenForBouncerExpansion(scope: CoroutineScope): Job {
|
||||
return scope.launch {
|
||||
bouncerInteractor.bouncerExpansion.collect { bouncerExpansion: Float ->
|
||||
inputBouncerExpansion = bouncerExpansion
|
||||
updateAlpha()
|
||||
updatePauseAuth()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun onViewAttached() {
|
||||
super.onViewAttached()
|
||||
val dozeAmount = statusBarStateController.dozeAmount
|
||||
lastDozeAmount = dozeAmount
|
||||
stateListener.onDozeAmountChanged(dozeAmount, dozeAmount)
|
||||
statusBarStateController.addCallback(stateListener)
|
||||
udfpsRequested = false
|
||||
launchTransitionFadingAway = keyguardStateController.isLaunchTransitionFadingAway
|
||||
keyguardStateController.addCallback(keyguardStateControllerCallback)
|
||||
statusBarState = statusBarStateController.state
|
||||
qsExpansion = keyguardViewManager.qsExpansion
|
||||
keyguardViewManager.addCallback(statusBarKeyguardViewManagerCallback)
|
||||
if (!isModernBouncerEnabled) {
|
||||
val bouncer = keyguardViewManager.bouncer
|
||||
bouncer?.expansion?.let {
|
||||
bouncerExpansionCallback.onExpansionChanged(it)
|
||||
bouncer.addBouncerExpansionCallback(bouncerExpansionCallback)
|
||||
}
|
||||
updateBouncerHiddenAmount()
|
||||
}
|
||||
configurationController.addCallback(configurationListener)
|
||||
shadeExpansionStateManager.addExpansionListener(shadeExpansionListener)
|
||||
updateScaleFactor()
|
||||
view.updatePadding()
|
||||
updateAlpha()
|
||||
updatePauseAuth()
|
||||
keyguardViewManager.setAlternateAuthInterceptor(alternateAuthInterceptor)
|
||||
lockScreenShadeTransitionController.udfpsKeyguardViewController = this
|
||||
activityLaunchAnimator.addListener(activityLaunchAnimatorListener)
|
||||
}
|
||||
|
||||
override fun onViewDetached() {
|
||||
super.onViewDetached()
|
||||
faceDetectRunning = false
|
||||
keyguardStateController.removeCallback(keyguardStateControllerCallback)
|
||||
statusBarStateController.removeCallback(stateListener)
|
||||
keyguardViewManager.removeAlternateAuthInterceptor(alternateAuthInterceptor)
|
||||
keyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false)
|
||||
configurationController.removeCallback(configurationListener)
|
||||
shadeExpansionStateManager.removeExpansionListener(shadeExpansionListener)
|
||||
if (lockScreenShadeTransitionController.udfpsKeyguardViewController === this) {
|
||||
lockScreenShadeTransitionController.udfpsKeyguardViewController = null
|
||||
}
|
||||
activityLaunchAnimator.removeListener(activityLaunchAnimatorListener)
|
||||
keyguardViewManager.removeCallback(statusBarKeyguardViewManagerCallback)
|
||||
if (!isModernBouncerEnabled) {
|
||||
keyguardViewManager.bouncer?.removeBouncerExpansionCallback(bouncerExpansionCallback)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<String>) {
|
||||
super.dump(pw, args)
|
||||
pw.println("isModernBouncerEnabled=$isModernBouncerEnabled")
|
||||
pw.println("showingUdfpsAltBouncer=$showingUdfpsBouncer")
|
||||
pw.println("faceDetectRunning=$faceDetectRunning")
|
||||
pw.println("statusBarState=" + StatusBarState.toString(statusBarState))
|
||||
pw.println("transitionToFullShadeProgress=$transitionToFullShadeProgress")
|
||||
pw.println("qsExpansion=$qsExpansion")
|
||||
pw.println("panelExpansionFraction=$panelExpansionFraction")
|
||||
pw.println("unpausedAlpha=" + view.unpausedAlpha)
|
||||
pw.println("udfpsRequestedByApp=$udfpsRequested")
|
||||
pw.println("launchTransitionFadingAway=$launchTransitionFadingAway")
|
||||
pw.println("lastDozeAmount=$lastDozeAmount")
|
||||
if (isModernBouncerEnabled) {
|
||||
pw.println("inputBouncerExpansion=$inputBouncerExpansion")
|
||||
} else {
|
||||
pw.println("inputBouncerHiddenAmount=$inputBouncerHiddenAmount")
|
||||
}
|
||||
view.dump(pw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides non-bouncer show logic in shouldPauseAuth to still show icon.
|
||||
* @return whether the udfpsBouncer has been newly shown or hidden
|
||||
*/
|
||||
private fun showUdfpsBouncer(show: Boolean): Boolean {
|
||||
if (showingUdfpsBouncer == show) {
|
||||
return false
|
||||
}
|
||||
val udfpsAffordanceWasNotShowing = shouldPauseAuth()
|
||||
showingUdfpsBouncer = show
|
||||
if (showingUdfpsBouncer) {
|
||||
lastUdfpsBouncerShowTime = systemClock.uptimeMillis()
|
||||
}
|
||||
if (showingUdfpsBouncer) {
|
||||
if (udfpsAffordanceWasNotShowing) {
|
||||
view.animateInUdfpsBouncer(null)
|
||||
}
|
||||
if (keyguardStateController.isOccluded) {
|
||||
keyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true)
|
||||
}
|
||||
view.announceForAccessibility(
|
||||
view.context.getString(R.string.accessibility_fingerprint_bouncer)
|
||||
)
|
||||
} else {
|
||||
keyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false)
|
||||
}
|
||||
updateBouncerHiddenAmount()
|
||||
updateAlpha()
|
||||
updatePauseAuth()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the fingerprint manager is running but we want to temporarily pause
|
||||
* authentication. On the keyguard, we may want to show udfps when the shade is expanded, so
|
||||
* this can be overridden with the showBouncer method.
|
||||
*/
|
||||
override fun shouldPauseAuth(): Boolean {
|
||||
if (showingUdfpsBouncer) {
|
||||
return false
|
||||
}
|
||||
if (
|
||||
udfpsRequested &&
|
||||
!notificationShadeVisible &&
|
||||
!isInputBouncerFullyVisible() &&
|
||||
keyguardStateController.isShowing
|
||||
) {
|
||||
return false
|
||||
}
|
||||
if (launchTransitionFadingAway) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Only pause auth if we're not on the keyguard AND we're not transitioning to doze
|
||||
// (ie: dozeAmount = 0f). For the UnlockedScreenOffAnimation, the statusBarState is
|
||||
// delayed. However, we still animate in the UDFPS affordance with the
|
||||
// mUnlockedScreenOffDozeAnimator.
|
||||
if (statusBarState != StatusBarState.KEYGUARD && lastDozeAmount == 0f) {
|
||||
return true
|
||||
}
|
||||
if (isBouncerExpansionGreaterThan(.5f)) {
|
||||
return true
|
||||
}
|
||||
return view.unpausedAlpha < 255 * .1
|
||||
}
|
||||
|
||||
fun isBouncerExpansionGreaterThan(bouncerExpansionThreshold: Float): Boolean {
|
||||
return if (isModernBouncerEnabled) {
|
||||
inputBouncerExpansion >= bouncerExpansionThreshold
|
||||
} else {
|
||||
inputBouncerHiddenAmount < bouncerExpansionThreshold
|
||||
}
|
||||
}
|
||||
|
||||
fun isInputBouncerFullyVisible(): Boolean {
|
||||
return if (isModernBouncerEnabled) {
|
||||
inputBouncerExpansion == 1f
|
||||
} else {
|
||||
keyguardViewManager.isBouncerShowing && !keyguardViewManager.isShowingAlternateAuth
|
||||
}
|
||||
}
|
||||
|
||||
override fun listenForTouchesOutsideView(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onTouchOutsideView() {
|
||||
maybeShowInputBouncer()
|
||||
}
|
||||
|
||||
/**
|
||||
* If we were previously showing the udfps bouncer, hide it and instead show the regular
|
||||
* (pin/pattern/password) bouncer.
|
||||
*
|
||||
* Does nothing if we weren't previously showing the UDFPS bouncer.
|
||||
*/
|
||||
private fun maybeShowInputBouncer() {
|
||||
if (showingUdfpsBouncer && hasUdfpsBouncerShownWithMinTime()) {
|
||||
keyguardViewManager.showBouncer(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the udfps bouncer has shown for at least 200ms before allowing touches outside of the
|
||||
* udfps icon area to dismiss the udfps bouncer and show the pin/pattern/password bouncer.
|
||||
*/
|
||||
private fun hasUdfpsBouncerShownWithMinTime(): Boolean {
|
||||
return systemClock.uptimeMillis() - lastUdfpsBouncerShowTime > 200
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the progress we're currently transitioning to the full shade. 0.0f means we're not
|
||||
* transitioning yet, while 1.0f means we've fully dragged down. For example, start swiping down
|
||||
* to expand the notification shade from the empty space in the middle of the lock screen.
|
||||
*/
|
||||
fun setTransitionToFullShadeProgress(progress: Float) {
|
||||
transitionToFullShadeProgress = progress
|
||||
updateAlpha()
|
||||
}
|
||||
|
||||
/**
|
||||
* Update alpha for the UDFPS lock screen affordance. The AoD UDFPS visual affordance's alpha is
|
||||
* based on the doze amount.
|
||||
*/
|
||||
override fun updateAlpha() {
|
||||
// Fade icon on transitions to showing the status bar or bouncer, but if mUdfpsRequested,
|
||||
// then the keyguard is occluded by some application - so instead use the input bouncer
|
||||
// hidden amount to determine the fade.
|
||||
val expansion = if (udfpsRequested) getInputBouncerHiddenAmt() else panelExpansionFraction
|
||||
var alpha: Int =
|
||||
if (showingUdfpsBouncer) 255
|
||||
else MathUtils.constrain(MathUtils.map(.5f, .9f, 0f, 255f, expansion), 0f, 255f).toInt()
|
||||
if (!showingUdfpsBouncer) {
|
||||
// swipe from top of the lockscreen to expand full QS:
|
||||
alpha =
|
||||
(alpha * (1.0f - Interpolators.EMPHASIZED_DECELERATE.getInterpolation(qsExpansion)))
|
||||
.toInt()
|
||||
|
||||
// swipe from the middle (empty space) of lockscreen to expand the notification shade:
|
||||
alpha = (alpha * (1.0f - transitionToFullShadeProgress)).toInt()
|
||||
|
||||
// Fade out the icon if we are animating an activity launch over the lockscreen and the
|
||||
// activity didn't request the UDFPS.
|
||||
if (isLaunchingActivity && !udfpsRequested) {
|
||||
alpha = (alpha * (1.0f - activityLaunchProgress)).toInt()
|
||||
}
|
||||
|
||||
// Fade out alpha when a dialog is shown
|
||||
// Fade in alpha when a dialog is hidden
|
||||
alpha = (alpha * view.dialogSuggestedAlpha).toInt()
|
||||
}
|
||||
view.unpausedAlpha = alpha
|
||||
}
|
||||
|
||||
private fun getInputBouncerHiddenAmt(): Float {
|
||||
return if (isModernBouncerEnabled) {
|
||||
1f - inputBouncerExpansion
|
||||
} else {
|
||||
inputBouncerHiddenAmount
|
||||
}
|
||||
}
|
||||
|
||||
/** Update the scale factor based on the device's resolution. */
|
||||
private fun updateScaleFactor() {
|
||||
udfpsController.mOverlayParams?.scaleFactor?.let { view.setScaleFactor(it) }
|
||||
}
|
||||
|
||||
private fun updateBouncerHiddenAmount() {
|
||||
if (isModernBouncerEnabled) {
|
||||
return
|
||||
}
|
||||
val altBouncerShowing = keyguardViewManager.isShowingAlternateAuth
|
||||
if (altBouncerShowing || !keyguardViewManager.bouncerIsOrWillBeShowing()) {
|
||||
inputBouncerHiddenAmount = 1f
|
||||
} else if (keyguardViewManager.isBouncerShowing) {
|
||||
// input bouncer is fully showing
|
||||
inputBouncerHiddenAmount = 0f
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "UdfpsKeyguardViewController"
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyguard.shared.model.BouncerCallbackActionsModel
|
||||
import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel
|
||||
import com.android.systemui.statusbar.phone.KeyguardBouncer.EXPANSION_HIDDEN
|
||||
import com.android.systemui.statusbar.phone.KeyguardBouncer
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
@@ -41,9 +41,15 @@ constructor(
|
||||
/** Determines if we want to instantaneously show the bouncer instead of translating. */
|
||||
private val _isScrimmed = MutableStateFlow(false)
|
||||
val isScrimmed = _isScrimmed.asStateFlow()
|
||||
/** Set amount of how much of the bouncer is showing on the screen */
|
||||
private val _expansionAmount = MutableStateFlow(EXPANSION_HIDDEN)
|
||||
val expansionAmount = _expansionAmount.asStateFlow()
|
||||
/**
|
||||
* Set how much of the panel is showing on the screen.
|
||||
* ```
|
||||
* 0f = panel fully hidden = bouncer fully showing
|
||||
* 1f = panel fully showing = bouncer fully hidden
|
||||
* ```
|
||||
*/
|
||||
private val _panelExpansionAmount = MutableStateFlow(KeyguardBouncer.EXPANSION_HIDDEN)
|
||||
val panelExpansionAmount = _panelExpansionAmount.asStateFlow()
|
||||
private val _isVisible = MutableStateFlow(false)
|
||||
val isVisible = _isVisible.asStateFlow()
|
||||
private val _show = MutableStateFlow<KeyguardBouncerModel?>(null)
|
||||
@@ -96,8 +102,8 @@ constructor(
|
||||
_isScrimmed.value = isScrimmed
|
||||
}
|
||||
|
||||
fun setExpansion(expansion: Float) {
|
||||
_expansionAmount.value = expansion
|
||||
fun setPanelExpansion(panelExpansion: Float) {
|
||||
_panelExpansionAmount.value = panelExpansion
|
||||
}
|
||||
|
||||
fun setVisible(isVisible: Boolean) {
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -77,7 +78,7 @@ constructor(
|
||||
KeyguardBouncerModel(
|
||||
promptReason = repository.bouncerPromptReason ?: 0,
|
||||
errorMessage = repository.bouncerErrorMessage,
|
||||
expansionAmount = repository.expansionAmount.value
|
||||
expansionAmount = repository.panelExpansionAmount.value
|
||||
)
|
||||
)
|
||||
repository.setShowingSoon(false)
|
||||
@@ -90,7 +91,6 @@ constructor(
|
||||
val startingToHide: Flow<Unit> = repository.startingToHide.filter { it }.map {}
|
||||
val isVisible: Flow<Boolean> = repository.isVisible
|
||||
val isBackButtonEnabled: Flow<Boolean> = repository.isBackButtonEnabled.filterNotNull()
|
||||
val expansionAmount: Flow<Float> = repository.expansionAmount
|
||||
val showMessage: Flow<BouncerShowMessageModel> = repository.showMessage.filterNotNull()
|
||||
val startingDisappearAnimation: Flow<Runnable> =
|
||||
repository.startingDisappearAnimation.filterNotNull()
|
||||
@@ -98,6 +98,17 @@ constructor(
|
||||
repository.onDismissAction.filterNotNull()
|
||||
val resourceUpdateRequests: Flow<Boolean> = repository.resourceUpdateRequests.filter { it }
|
||||
val keyguardPosition: Flow<Float> = repository.keyguardPosition
|
||||
val panelExpansionAmount: Flow<Float> = repository.panelExpansionAmount
|
||||
/** 0f = bouncer fully hidden. 1f = bouncer fully visible. */
|
||||
val bouncerExpansion: Flow<Float> = //
|
||||
combine(repository.panelExpansionAmount, repository.isVisible) { expansionAmount, isVisible
|
||||
->
|
||||
if (isVisible) {
|
||||
1f - expansionAmount
|
||||
} else {
|
||||
0f
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/243685699): Move isScrimmed logic to data layer.
|
||||
// TODO(b/243695312): Encapsulate all of the show logic for the bouncer.
|
||||
@@ -128,7 +139,7 @@ constructor(
|
||||
Trace.beginSection("KeyguardBouncer#show")
|
||||
repository.setScrimmed(isScrimmed)
|
||||
if (isScrimmed) {
|
||||
setExpansion(KeyguardBouncer.EXPANSION_VISIBLE)
|
||||
setPanelExpansion(KeyguardBouncer.EXPANSION_VISIBLE)
|
||||
}
|
||||
|
||||
if (resumeBouncer) {
|
||||
@@ -176,14 +187,17 @@ constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the panel expansion which is calculated further upstream. Expansion is from 0f to 1f
|
||||
* where 0f => showing and 1f => hiding
|
||||
* Sets the panel expansion which is calculated further upstream. Panel expansion is from 0f
|
||||
* (panel fully hidden) to 1f (panel fully showing). As the panel shows (from 0f => 1f), the
|
||||
* bouncer hides and as the panel becomes hidden (1f => 0f), the bouncer starts to show.
|
||||
* Therefore, a panel expansion of 1f represents the bouncer fully hidden and a panel expansion
|
||||
* of 0f represents the bouncer fully showing.
|
||||
*/
|
||||
fun setExpansion(expansion: Float) {
|
||||
val oldExpansion = repository.expansionAmount.value
|
||||
fun setPanelExpansion(expansion: Float) {
|
||||
val oldExpansion = repository.panelExpansionAmount.value
|
||||
val expansionChanged = oldExpansion != expansion
|
||||
if (repository.startingDisappearAnimation.value == null) {
|
||||
repository.setExpansion(expansion)
|
||||
repository.setPanelExpansion(expansion)
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -282,7 +296,7 @@ constructor(
|
||||
/** Returns whether bouncer is fully showing. */
|
||||
fun isFullyShowing(): Boolean {
|
||||
return (repository.showingSoon.value || repository.isVisible.value) &&
|
||||
repository.expansionAmount.value == KeyguardBouncer.EXPANSION_VISIBLE &&
|
||||
repository.panelExpansionAmount.value == KeyguardBouncer.EXPANSION_VISIBLE &&
|
||||
repository.startingDisappearAnimation.value == null
|
||||
}
|
||||
|
||||
@@ -294,8 +308,8 @@ constructor(
|
||||
/** If bouncer expansion is between 0f and 1f non-inclusive. */
|
||||
fun isInTransit(): Boolean {
|
||||
return repository.showingSoon.value ||
|
||||
repository.expansionAmount.value != KeyguardBouncer.EXPANSION_HIDDEN &&
|
||||
repository.expansionAmount.value != KeyguardBouncer.EXPANSION_VISIBLE
|
||||
repository.panelExpansionAmount.value != KeyguardBouncer.EXPANSION_HIDDEN &&
|
||||
repository.panelExpansionAmount.value != KeyguardBouncer.EXPANSION_VISIBLE
|
||||
}
|
||||
|
||||
/** Return whether bouncer is animating away. */
|
||||
|
||||
@@ -38,7 +38,7 @@ constructor(
|
||||
private val interactor: BouncerInteractor,
|
||||
) {
|
||||
/** Observe on bouncer expansion amount. */
|
||||
val bouncerExpansionAmount: Flow<Float> = interactor.expansionAmount
|
||||
val bouncerExpansionAmount: Flow<Float> = interactor.panelExpansionAmount
|
||||
|
||||
/** Observe on bouncer visibility. */
|
||||
val isBouncerVisible: Flow<Boolean> = interactor.isVisible
|
||||
|
||||
@@ -4644,7 +4644,7 @@ public final class NotificationPanelViewController {
|
||||
mUpdateFlingVelocity = vel;
|
||||
}
|
||||
} else if (!mCentralSurfaces.isBouncerShowing()
|
||||
&& !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()
|
||||
&& !mStatusBarKeyguardViewManager.isShowingAlternateAuth()
|
||||
&& !mKeyguardStateController.isKeyguardGoingAway()) {
|
||||
onEmptySpaceClick();
|
||||
onTrackingStopped(true);
|
||||
|
||||
@@ -284,7 +284,7 @@ public class NotificationShadeWindowViewController {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) {
|
||||
if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
|
||||
// capture all touches if the alt auth bouncer is showing
|
||||
return true;
|
||||
}
|
||||
@@ -322,7 +322,7 @@ public class NotificationShadeWindowViewController {
|
||||
handled = !mService.isPulsing();
|
||||
}
|
||||
|
||||
if (mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) {
|
||||
if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
|
||||
// eat the touch
|
||||
handled = true;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,11 @@ public class KeyguardBouncer {
|
||||
private static final String TAG = "KeyguardBouncer";
|
||||
static final long BOUNCER_FACE_DELAY = 1200;
|
||||
public static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
|
||||
/**
|
||||
* Values for the bouncer expansion represented as the panel expansion.
|
||||
* Panel expansion 1f = panel fully showing = bouncer fully hidden
|
||||
* Panel expansion 0f = panel fully hiding = bouncer fully showing
|
||||
*/
|
||||
public static final float EXPANSION_HIDDEN = 1f;
|
||||
public static final float EXPANSION_VISIBLE = 0f;
|
||||
|
||||
@@ -142,6 +147,14 @@ public class KeyguardBouncer {
|
||||
mExpansionCallbacks.add(expansionCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the KeyguardBouncer expansion
|
||||
* @return 1=HIDDEN, 0=SHOWING, in between 0 and 1 means the bouncer is in transition.
|
||||
*/
|
||||
public float getExpansion() {
|
||||
return mExpansion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable only the back button
|
||||
*/
|
||||
|
||||
@@ -86,8 +86,10 @@ import com.android.systemui.unfold.SysUIUnfoldComponent;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -166,9 +168,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
|
||||
@Override
|
||||
public void onExpansionChanged(float expansion) {
|
||||
if (mAlternateAuthInterceptor != null) {
|
||||
mAlternateAuthInterceptor.setBouncerExpansionChanged(expansion);
|
||||
}
|
||||
if (mBouncerAnimating) {
|
||||
mCentralSurfaces.setBouncerHiddenFraction(expansion);
|
||||
}
|
||||
@@ -184,9 +183,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
if (!isVisible) {
|
||||
mCentralSurfaces.setBouncerHiddenFraction(KeyguardBouncer.EXPANSION_HIDDEN);
|
||||
}
|
||||
if (mAlternateAuthInterceptor != null) {
|
||||
mAlternateAuthInterceptor.onBouncerVisibilityChanged();
|
||||
}
|
||||
|
||||
/* Register predictive back callback when keyguard becomes visible, and unregister
|
||||
when it's hidden. */
|
||||
@@ -252,6 +248,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
private int mLastBiometricMode;
|
||||
private boolean mLastScreenOffAnimationPlaying;
|
||||
private float mQsExpansion;
|
||||
final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
|
||||
private boolean mIsModernBouncerEnabled;
|
||||
|
||||
private OnDismissAction mAfterKeyguardGoneAction;
|
||||
@@ -465,7 +462,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
if (mBouncer != null) {
|
||||
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
|
||||
} else {
|
||||
mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
|
||||
mBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
|
||||
}
|
||||
} else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
|
||||
// Don't expand to the bouncer. Instead transition back to the lock screen (see
|
||||
@@ -475,7 +472,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
if (mBouncer != null) {
|
||||
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
|
||||
} else {
|
||||
mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
|
||||
mBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
|
||||
}
|
||||
} else if (mKeyguardStateController.isShowing() && !hideBouncerOverDream) {
|
||||
if (!isWakeAndUnlocking()
|
||||
@@ -485,7 +482,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
if (mBouncer != null) {
|
||||
mBouncer.setExpansion(fraction);
|
||||
} else {
|
||||
mBouncerInteractor.setExpansion(fraction);
|
||||
mBouncerInteractor.setPanelExpansion(fraction);
|
||||
}
|
||||
}
|
||||
if (fraction != KeyguardBouncer.EXPANSION_HIDDEN && tracking
|
||||
@@ -504,7 +501,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
if (mBouncer != null) {
|
||||
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
|
||||
} else {
|
||||
mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
|
||||
mBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
|
||||
}
|
||||
} else if (mPulsing && fraction == KeyguardBouncer.EXPANSION_VISIBLE) {
|
||||
// Panel expanded while pulsing but didn't translate the bouncer (because we are
|
||||
@@ -1356,7 +1353,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
mBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
|
||||
}
|
||||
|
||||
if (mAlternateAuthInterceptor != null && isShowingAlternateAuthOrAnimating()) {
|
||||
if (mAlternateAuthInterceptor != null && isShowingAlternateAuth()) {
|
||||
resetAlternateAuth(false);
|
||||
executeAfterKeyguardGoneAction();
|
||||
}
|
||||
@@ -1442,6 +1439,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
pw.println(" mPendingWakeupAction: " + mPendingWakeupAction);
|
||||
pw.println(" isBouncerShowing(): " + isBouncerShowing());
|
||||
pw.println(" bouncerIsOrWillBeShowing(): " + bouncerIsOrWillBeShowing());
|
||||
pw.println(" Registered KeyguardViewManagerCallbacks:");
|
||||
for (KeyguardViewManagerCallback callback : mCallbacks) {
|
||||
pw.println(" " + callback);
|
||||
}
|
||||
|
||||
if (mBouncer != null) {
|
||||
mBouncer.dump(pw);
|
||||
@@ -1465,6 +1466,20 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback to listen for changes
|
||||
*/
|
||||
public void addCallback(KeyguardViewManagerCallback callback) {
|
||||
mCallbacks.add(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes callback to stop receiving updates
|
||||
*/
|
||||
public void removeCallback(KeyguardViewManagerCallback callback) {
|
||||
mCallbacks.remove(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether qs is currently expanded.
|
||||
*/
|
||||
@@ -1477,8 +1492,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
*/
|
||||
public void setQsExpansion(float qsExpansion) {
|
||||
mQsExpansion = qsExpansion;
|
||||
if (mAlternateAuthInterceptor != null) {
|
||||
mAlternateAuthInterceptor.setQsExpansion(qsExpansion);
|
||||
for (KeyguardViewManagerCallback callback : mCallbacks) {
|
||||
callback.onQSExpansionChanged(mQsExpansion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1492,21 +1507,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
&& mAlternateAuthInterceptor.isShowingAlternateAuthBouncer();
|
||||
}
|
||||
|
||||
public boolean isShowingAlternateAuthOrAnimating() {
|
||||
return mAlternateAuthInterceptor != null
|
||||
&& (mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()
|
||||
|| mAlternateAuthInterceptor.isAnimating());
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward touches to any alternate authentication affordances.
|
||||
* Forward touches to callbacks.
|
||||
*/
|
||||
public boolean onTouch(MotionEvent event) {
|
||||
if (mAlternateAuthInterceptor == null) {
|
||||
return false;
|
||||
public void onTouch(MotionEvent event) {
|
||||
for (KeyguardViewManagerCallback callback: mCallbacks) {
|
||||
callback.onTouch(event);
|
||||
}
|
||||
|
||||
return mAlternateAuthInterceptor.onTouch(event);
|
||||
}
|
||||
|
||||
/** Update keyguard position based on a tapped X coordinate. */
|
||||
@@ -1639,38 +1646,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
*/
|
||||
boolean isShowingAlternateAuthBouncer();
|
||||
|
||||
/**
|
||||
* print information for the alternate auth interceptor registered
|
||||
*/
|
||||
void dump(PrintWriter pw);
|
||||
|
||||
/**
|
||||
* @return true if the new auth method bouncer is currently animating in or out.
|
||||
*/
|
||||
boolean isAnimating();
|
||||
|
||||
/**
|
||||
* How much QS is fully expanded where 0f is not showing and 1f is fully expanded.
|
||||
*/
|
||||
void setQsExpansion(float qsExpansion);
|
||||
|
||||
/**
|
||||
* Forward potential touches to authentication interceptor
|
||||
* @return true if event was handled
|
||||
*/
|
||||
boolean onTouch(MotionEvent event);
|
||||
|
||||
/**
|
||||
* Update pin/pattern/password bouncer expansion amount where 0 is visible and 1 is fully
|
||||
* hidden
|
||||
*/
|
||||
void setBouncerExpansionChanged(float expansion);
|
||||
|
||||
/**
|
||||
* called when the bouncer view visibility has changed.
|
||||
*/
|
||||
void onBouncerVisibilityChanged();
|
||||
|
||||
/**
|
||||
* Use when an app occluding the keyguard would like to give the user ability to
|
||||
* unlock the device using udfps.
|
||||
@@ -1680,5 +1655,25 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
*/
|
||||
void requestUdfps(boolean requestUdfps, int color);
|
||||
|
||||
/**
|
||||
* print information for the alternate auth interceptor registered
|
||||
*/
|
||||
void dump(PrintWriter pw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for KeyguardViewManager state changes.
|
||||
*/
|
||||
public interface KeyguardViewManagerCallback {
|
||||
/**
|
||||
* Set the amount qs is expanded. For example, swipe down from the top of the
|
||||
* lock screen to start the full QS expansion.
|
||||
*/
|
||||
default void onQSExpansionChanged(float qsExpansion) { }
|
||||
|
||||
/**
|
||||
* Forward touch events to callbacks
|
||||
*/
|
||||
default void onTouch(MotionEvent event) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.keyguard.domain.interactor.BouncerInteractor
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.shade.ShadeExpansionStateManager
|
||||
import com.android.systemui.statusbar.LockscreenShadeTransitionController
|
||||
@@ -103,6 +105,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
|
||||
@Mock private lateinit var udfpsView: UdfpsView
|
||||
@Mock private lateinit var udfpsEnrollView: UdfpsEnrollView
|
||||
@Mock private lateinit var activityLaunchAnimator: ActivityLaunchAnimator
|
||||
@Mock private lateinit var featureFlags: FeatureFlags
|
||||
@Mock private lateinit var bouncerInteractor: BouncerInteractor
|
||||
@Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
|
||||
|
||||
private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
|
||||
@@ -136,7 +140,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
|
||||
keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
|
||||
configurationController, systemClock, keyguardStateController,
|
||||
unlockedScreenOffAnimationController, udfpsDisplayMode, REQUEST_ID, reason,
|
||||
controllerCallback, onTouch, activityLaunchAnimator, isDebuggable
|
||||
controllerCallback, onTouch, activityLaunchAnimator, featureFlags,
|
||||
bouncerInteractor, isDebuggable
|
||||
)
|
||||
block()
|
||||
}
|
||||
|
||||
@@ -69,7 +69,9 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.keyguard.ScreenLifecycle;
|
||||
import com.android.systemui.keyguard.domain.interactor.BouncerInteractor;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shade.ShadeExpansionStateManager;
|
||||
@@ -171,6 +173,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
private FakeExecutor mFgExecutor;
|
||||
@Mock
|
||||
private UdfpsDisplayMode mUdfpsDisplayMode;
|
||||
@Mock
|
||||
private FeatureFlags mFeatureFlags;
|
||||
|
||||
// Stuff for configuring mocks
|
||||
@Mock
|
||||
@@ -191,6 +195,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
private ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
@Mock
|
||||
private AlternateUdfpsTouchProvider mAlternateTouchProvider;
|
||||
@Mock
|
||||
private BouncerInteractor mBouncerInteractor;
|
||||
|
||||
// Capture listeners so that they can be used to send events
|
||||
@Captor private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor;
|
||||
@@ -252,6 +258,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
mStatusBarKeyguardViewManager,
|
||||
mDumpManager,
|
||||
mKeyguardUpdateMonitor,
|
||||
mFeatureFlags,
|
||||
mFalsingManager,
|
||||
mPowerManager,
|
||||
mAccessibilityManager,
|
||||
@@ -270,7 +277,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
mLatencyTracker,
|
||||
mActivityLaunchAnimator,
|
||||
Optional.of(mAlternateTouchProvider),
|
||||
mBiometricsExecutor);
|
||||
mBiometricsExecutor,
|
||||
mBouncerInteractor);
|
||||
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
|
||||
mOverlayController = mOverlayCaptor.getValue();
|
||||
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.biometrics;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FakeFeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.keyguard.domain.interactor.BouncerInteractor;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shade.ShadeExpansionChangeEvent;
|
||||
import com.android.systemui.shade.ShadeExpansionListener;
|
||||
import com.android.systemui.shade.ShadeExpansionStateManager;
|
||||
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
|
||||
import com.android.systemui.statusbar.phone.KeyguardBouncer;
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialogManager;
|
||||
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase {
|
||||
// Dependencies
|
||||
protected @Mock UdfpsKeyguardView mView;
|
||||
protected @Mock Context mResourceContext;
|
||||
protected @Mock StatusBarStateController mStatusBarStateController;
|
||||
protected @Mock ShadeExpansionStateManager mShadeExpansionStateManager;
|
||||
protected @Mock StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
||||
protected @Mock LockscreenShadeTransitionController mLockscreenShadeTransitionController;
|
||||
protected @Mock DumpManager mDumpManager;
|
||||
protected @Mock DelayableExecutor mExecutor;
|
||||
protected @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
protected @Mock KeyguardStateController mKeyguardStateController;
|
||||
protected @Mock KeyguardViewMediator mKeyguardViewMediator;
|
||||
protected @Mock ConfigurationController mConfigurationController;
|
||||
protected @Mock UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
|
||||
protected @Mock SystemUIDialogManager mDialogManager;
|
||||
protected @Mock UdfpsController mUdfpsController;
|
||||
protected @Mock ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
protected @Mock KeyguardBouncer mBouncer;
|
||||
protected @Mock BouncerInteractor mBouncerInteractor;
|
||||
|
||||
protected FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
|
||||
protected FakeSystemClock mSystemClock = new FakeSystemClock();
|
||||
|
||||
protected UdfpsKeyguardViewController mController;
|
||||
|
||||
// Capture listeners so that they can be used to send events
|
||||
private @Captor ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerCaptor;
|
||||
protected StatusBarStateController.StateListener mStatusBarStateListener;
|
||||
|
||||
private @Captor ArgumentCaptor<ShadeExpansionListener> mExpansionListenerCaptor;
|
||||
protected List<ShadeExpansionListener> mExpansionListeners;
|
||||
|
||||
private @Captor ArgumentCaptor<StatusBarKeyguardViewManager.AlternateAuthInterceptor>
|
||||
mAltAuthInterceptorCaptor;
|
||||
protected StatusBarKeyguardViewManager.AlternateAuthInterceptor mAltAuthInterceptor;
|
||||
|
||||
private @Captor ArgumentCaptor<KeyguardStateController.Callback>
|
||||
mKeyguardStateControllerCallbackCaptor;
|
||||
protected KeyguardStateController.Callback mKeyguardStateControllerCallback;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mView.getContext()).thenReturn(mResourceContext);
|
||||
when(mResourceContext.getString(anyInt())).thenReturn("test string");
|
||||
when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(false);
|
||||
when(mView.getUnpausedAlpha()).thenReturn(255);
|
||||
mController = createUdfpsKeyguardViewController();
|
||||
}
|
||||
|
||||
protected void sendStatusBarStateChanged(int statusBarState) {
|
||||
mStatusBarStateListener.onStateChanged(statusBarState);
|
||||
}
|
||||
|
||||
protected void captureStatusBarStateListeners() {
|
||||
verify(mStatusBarStateController).addCallback(mStateListenerCaptor.capture());
|
||||
mStatusBarStateListener = mStateListenerCaptor.getValue();
|
||||
}
|
||||
|
||||
protected void captureStatusBarExpansionListeners() {
|
||||
verify(mShadeExpansionStateManager, times(2))
|
||||
.addExpansionListener(mExpansionListenerCaptor.capture());
|
||||
// first (index=0) is from super class, UdfpsAnimationViewController.
|
||||
// second (index=1) is from UdfpsKeyguardViewController
|
||||
mExpansionListeners = mExpansionListenerCaptor.getAllValues();
|
||||
}
|
||||
|
||||
protected void updateStatusBarExpansion(float fraction, boolean expanded) {
|
||||
ShadeExpansionChangeEvent event =
|
||||
new ShadeExpansionChangeEvent(
|
||||
fraction, expanded, /* tracking= */ false, /* dragDownPxAmount= */ 0f);
|
||||
for (ShadeExpansionListener listener : mExpansionListeners) {
|
||||
listener.onPanelExpansionChanged(event);
|
||||
}
|
||||
}
|
||||
|
||||
protected void captureAltAuthInterceptor() {
|
||||
verify(mStatusBarKeyguardViewManager).setAlternateAuthInterceptor(
|
||||
mAltAuthInterceptorCaptor.capture());
|
||||
mAltAuthInterceptor = mAltAuthInterceptorCaptor.getValue();
|
||||
}
|
||||
|
||||
protected void captureKeyguardStateControllerCallback() {
|
||||
verify(mKeyguardStateController).addCallback(
|
||||
mKeyguardStateControllerCallbackCaptor.capture());
|
||||
mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
|
||||
}
|
||||
|
||||
public UdfpsKeyguardViewController createUdfpsKeyguardViewController() {
|
||||
return createUdfpsKeyguardViewController(false);
|
||||
}
|
||||
|
||||
protected UdfpsKeyguardViewController createUdfpsKeyguardViewController(
|
||||
boolean useModernBouncer) {
|
||||
mFeatureFlags.set(Flags.MODERN_BOUNCER, useModernBouncer);
|
||||
when(mStatusBarKeyguardViewManager.getBouncer()).thenReturn(
|
||||
useModernBouncer ? null : mBouncer);
|
||||
return new UdfpsKeyguardViewController(
|
||||
mView,
|
||||
mStatusBarStateController,
|
||||
mShadeExpansionStateManager,
|
||||
mStatusBarKeyguardViewManager,
|
||||
mKeyguardUpdateMonitor,
|
||||
mDumpManager,
|
||||
mLockscreenShadeTransitionController,
|
||||
mConfigurationController,
|
||||
mSystemClock,
|
||||
mKeyguardStateController,
|
||||
mUnlockedScreenOffAnimationController,
|
||||
mDialogManager,
|
||||
mUdfpsController,
|
||||
mActivityLaunchAnimator,
|
||||
mFeatureFlags,
|
||||
mBouncerInteractor);
|
||||
}
|
||||
}
|
||||
@@ -25,125 +25,52 @@ import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shade.ShadeExpansionChangeEvent;
|
||||
import com.android.systemui.shade.ShadeExpansionListener;
|
||||
import com.android.systemui.shade.ShadeExpansionStateManager;
|
||||
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialogManager;
|
||||
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
import com.android.systemui.statusbar.phone.KeyguardBouncer;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper
|
||||
public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
|
||||
// Dependencies
|
||||
@Mock
|
||||
private UdfpsKeyguardView mView;
|
||||
@Mock
|
||||
private Context mResourceContext;
|
||||
@Mock
|
||||
private StatusBarStateController mStatusBarStateController;
|
||||
@Mock
|
||||
private ShadeExpansionStateManager mShadeExpansionStateManager;
|
||||
@Mock
|
||||
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
||||
@Mock
|
||||
private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
|
||||
@Mock
|
||||
private DumpManager mDumpManager;
|
||||
@Mock
|
||||
private DelayableExecutor mExecutor;
|
||||
@Mock
|
||||
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
@Mock
|
||||
private KeyguardStateController mKeyguardStateController;
|
||||
@Mock
|
||||
private KeyguardViewMediator mKeyguardViewMediator;
|
||||
@Mock
|
||||
private ConfigurationController mConfigurationController;
|
||||
@Mock
|
||||
private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
|
||||
@Mock
|
||||
private SystemUIDialogManager mDialogManager;
|
||||
@Mock
|
||||
private UdfpsController mUdfpsController;
|
||||
@Mock
|
||||
private ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
private FakeSystemClock mSystemClock = new FakeSystemClock();
|
||||
public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest {
|
||||
private @Captor ArgumentCaptor<KeyguardBouncer.BouncerExpansionCallback>
|
||||
mBouncerExpansionCallbackCaptor;
|
||||
private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback;
|
||||
|
||||
private UdfpsKeyguardViewController mController;
|
||||
|
||||
// Capture listeners so that they can be used to send events
|
||||
@Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerCaptor;
|
||||
private StatusBarStateController.StateListener mStatusBarStateListener;
|
||||
|
||||
@Captor private ArgumentCaptor<ShadeExpansionListener> mExpansionListenerCaptor;
|
||||
private List<ShadeExpansionListener> mExpansionListeners;
|
||||
|
||||
@Captor private ArgumentCaptor<StatusBarKeyguardViewManager.AlternateAuthInterceptor>
|
||||
mAltAuthInterceptorCaptor;
|
||||
private StatusBarKeyguardViewManager.AlternateAuthInterceptor mAltAuthInterceptor;
|
||||
|
||||
@Captor private ArgumentCaptor<KeyguardStateController.Callback>
|
||||
mKeyguardStateControllerCallbackCaptor;
|
||||
private KeyguardStateController.Callback mKeyguardStateControllerCallback;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mView.getContext()).thenReturn(mResourceContext);
|
||||
when(mResourceContext.getString(anyInt())).thenReturn("test string");
|
||||
when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(false);
|
||||
when(mView.getUnpausedAlpha()).thenReturn(255);
|
||||
mController = new UdfpsKeyguardViewController(
|
||||
mView,
|
||||
mStatusBarStateController,
|
||||
mShadeExpansionStateManager,
|
||||
mStatusBarKeyguardViewManager,
|
||||
mKeyguardUpdateMonitor,
|
||||
mDumpManager,
|
||||
mLockscreenShadeTransitionController,
|
||||
mConfigurationController,
|
||||
mSystemClock,
|
||||
mKeyguardStateController,
|
||||
mUnlockedScreenOffAnimationController,
|
||||
mDialogManager,
|
||||
mUdfpsController,
|
||||
mActivityLaunchAnimator);
|
||||
@Override
|
||||
public UdfpsKeyguardViewController createUdfpsKeyguardViewController() {
|
||||
return createUdfpsKeyguardViewController(/* useModernBouncer */ false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldPauseAuth_bouncerShowing() {
|
||||
mController.onViewAttached();
|
||||
captureStatusBarStateListeners();
|
||||
sendStatusBarStateChanged(StatusBarState.KEYGUARD);
|
||||
|
||||
captureBouncerExpansionCallback();
|
||||
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
|
||||
when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
|
||||
mBouncerExpansionCallback.onVisibilityChanged(true);
|
||||
|
||||
assertTrue(mController.shouldPauseAuth());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testRegistersExpansionChangedListenerOnAttached() {
|
||||
mController.onViewAttached();
|
||||
@@ -201,20 +128,6 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
|
||||
UdfpsKeyguardView.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldPauseAuthBouncerShowing() {
|
||||
mController.onViewAttached();
|
||||
captureStatusBarStateListeners();
|
||||
sendStatusBarStateChanged(StatusBarState.KEYGUARD);
|
||||
|
||||
captureAltAuthInterceptor();
|
||||
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
|
||||
when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
|
||||
mAltAuthInterceptor.onBouncerVisibilityChanged();
|
||||
|
||||
assertTrue(mController.shouldPauseAuth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldPauseAuthUnpausedAlpha0() {
|
||||
mController.onViewAttached();
|
||||
@@ -503,41 +416,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
|
||||
verify(mView, atLeastOnce()).setPauseAuth(false);
|
||||
}
|
||||
|
||||
private void sendStatusBarStateChanged(int statusBarState) {
|
||||
mStatusBarStateListener.onStateChanged(statusBarState);
|
||||
}
|
||||
|
||||
private void captureStatusBarStateListeners() {
|
||||
verify(mStatusBarStateController).addCallback(mStateListenerCaptor.capture());
|
||||
mStatusBarStateListener = mStateListenerCaptor.getValue();
|
||||
}
|
||||
|
||||
private void captureStatusBarExpansionListeners() {
|
||||
verify(mShadeExpansionStateManager, times(2))
|
||||
.addExpansionListener(mExpansionListenerCaptor.capture());
|
||||
// first (index=0) is from super class, UdfpsAnimationViewController.
|
||||
// second (index=1) is from UdfpsKeyguardViewController
|
||||
mExpansionListeners = mExpansionListenerCaptor.getAllValues();
|
||||
}
|
||||
|
||||
private void updateStatusBarExpansion(float fraction, boolean expanded) {
|
||||
ShadeExpansionChangeEvent event =
|
||||
new ShadeExpansionChangeEvent(
|
||||
fraction, expanded, /* tracking= */ false, /* dragDownPxAmount= */ 0f);
|
||||
for (ShadeExpansionListener listener : mExpansionListeners) {
|
||||
listener.onPanelExpansionChanged(event);
|
||||
}
|
||||
}
|
||||
|
||||
private void captureAltAuthInterceptor() {
|
||||
verify(mStatusBarKeyguardViewManager).setAlternateAuthInterceptor(
|
||||
mAltAuthInterceptorCaptor.capture());
|
||||
mAltAuthInterceptor = mAltAuthInterceptorCaptor.getValue();
|
||||
}
|
||||
|
||||
private void captureKeyguardStateControllerCallback() {
|
||||
verify(mKeyguardStateController).addCallback(
|
||||
mKeyguardStateControllerCallbackCaptor.capture());
|
||||
mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
|
||||
private void captureBouncerExpansionCallback() {
|
||||
verify(mBouncer).addBouncerExpansionCallback(mBouncerExpansionCallbackCaptor.capture());
|
||||
mBouncerExpansionCallback = mBouncerExpansionCallbackCaptor.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.biometrics
|
||||
|
||||
import android.os.Handler
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.keyguard.KeyguardSecurityModel
|
||||
import com.android.systemui.classifier.FalsingCollector
|
||||
import com.android.systemui.keyguard.DismissCallbackRegistry
|
||||
import com.android.systemui.keyguard.data.BouncerView
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.BouncerCallbackInteractor
|
||||
import com.android.systemui.keyguard.domain.interactor.BouncerInteractor
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.phone.KeyguardBouncer
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.yield
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
@TestableLooper.RunWithLooper
|
||||
class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControllerBaseTest() {
|
||||
lateinit var keyguardBouncerRepository: KeyguardBouncerRepository
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
allowTestableLooperAsMainThread() // repeatWhenAttached requires the main thread
|
||||
MockitoAnnotations.initMocks(this)
|
||||
keyguardBouncerRepository =
|
||||
KeyguardBouncerRepository(
|
||||
mock(com.android.keyguard.ViewMediatorCallback::class.java),
|
||||
mKeyguardUpdateMonitor
|
||||
)
|
||||
super.setUp()
|
||||
}
|
||||
|
||||
override fun createUdfpsKeyguardViewController(): UdfpsKeyguardViewController? {
|
||||
mBouncerInteractor =
|
||||
BouncerInteractor(
|
||||
keyguardBouncerRepository,
|
||||
mock(BouncerView::class.java),
|
||||
mock(Handler::class.java),
|
||||
mKeyguardStateController,
|
||||
mock(KeyguardSecurityModel::class.java),
|
||||
mock(BouncerCallbackInteractor::class.java),
|
||||
mock(FalsingCollector::class.java),
|
||||
mock(DismissCallbackRegistry::class.java),
|
||||
mock(KeyguardBypassController::class.java),
|
||||
mKeyguardUpdateMonitor
|
||||
)
|
||||
return createUdfpsKeyguardViewController(/* useModernBouncer */ true)
|
||||
}
|
||||
|
||||
/** After migration, replaces LockIconViewControllerTest version */
|
||||
@Test
|
||||
fun testShouldPauseAuthBouncerShowing() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
// GIVEN view attached and we're on the keyguard
|
||||
mController.onViewAttached()
|
||||
captureStatusBarStateListeners()
|
||||
sendStatusBarStateChanged(StatusBarState.KEYGUARD)
|
||||
|
||||
// WHEN the bouncer expansion is VISIBLE
|
||||
val job = mController.listenForBouncerExpansion(this)
|
||||
keyguardBouncerRepository.setVisible(true)
|
||||
keyguardBouncerRepository.setPanelExpansion(KeyguardBouncer.EXPANSION_VISIBLE)
|
||||
yield()
|
||||
|
||||
// THEN UDFPS shouldPauseAuth == true
|
||||
assertTrue(mController.shouldPauseAuth())
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
verify(repository).setHide(false)
|
||||
verify(repository).setStartingToHide(false)
|
||||
verify(repository).setScrimmed(true)
|
||||
verify(repository).setExpansion(EXPANSION_VISIBLE)
|
||||
verify(repository).setPanelExpansion(EXPANSION_VISIBLE)
|
||||
verify(repository).setShowingSoon(true)
|
||||
verify(keyguardStateController).notifyBouncerShowing(true)
|
||||
verify(bouncerCallbackInteractor).dispatchStartingToShow()
|
||||
@@ -108,7 +108,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testShow_isNotScrimmed() {
|
||||
verify(repository, never()).setExpansion(EXPANSION_VISIBLE)
|
||||
verify(repository, never()).setPanelExpansion(EXPANSION_VISIBLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -132,26 +132,26 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testExpansion() {
|
||||
`when`(repository.expansionAmount.value).thenReturn(0.5f)
|
||||
bouncerInteractor.setExpansion(0.6f)
|
||||
verify(repository).setExpansion(0.6f)
|
||||
`when`(repository.panelExpansionAmount.value).thenReturn(0.5f)
|
||||
bouncerInteractor.setPanelExpansion(0.6f)
|
||||
verify(repository).setPanelExpansion(0.6f)
|
||||
verify(bouncerCallbackInteractor).dispatchExpansionChanged(0.6f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExpansion_fullyShown() {
|
||||
`when`(repository.expansionAmount.value).thenReturn(0.5f)
|
||||
`when`(repository.panelExpansionAmount.value).thenReturn(0.5f)
|
||||
`when`(repository.startingDisappearAnimation.value).thenReturn(null)
|
||||
bouncerInteractor.setExpansion(EXPANSION_VISIBLE)
|
||||
bouncerInteractor.setPanelExpansion(EXPANSION_VISIBLE)
|
||||
verify(falsingCollector).onBouncerShown()
|
||||
verify(bouncerCallbackInteractor).dispatchFullyShown()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExpansion_fullyHidden() {
|
||||
`when`(repository.expansionAmount.value).thenReturn(0.5f)
|
||||
`when`(repository.panelExpansionAmount.value).thenReturn(0.5f)
|
||||
`when`(repository.startingDisappearAnimation.value).thenReturn(null)
|
||||
bouncerInteractor.setExpansion(EXPANSION_HIDDEN)
|
||||
bouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN)
|
||||
verify(repository).setVisible(false)
|
||||
verify(repository).setShow(null)
|
||||
verify(falsingCollector).onBouncerHidden()
|
||||
@@ -161,8 +161,8 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testExpansion_startingToHide() {
|
||||
`when`(repository.expansionAmount.value).thenReturn(EXPANSION_VISIBLE)
|
||||
bouncerInteractor.setExpansion(0.1f)
|
||||
`when`(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE)
|
||||
bouncerInteractor.setPanelExpansion(0.1f)
|
||||
verify(repository).setStartingToHide(true)
|
||||
verify(bouncerCallbackInteractor).dispatchStartingToHide()
|
||||
}
|
||||
@@ -234,7 +234,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testIsFullShowing() {
|
||||
`when`(repository.isVisible.value).thenReturn(true)
|
||||
`when`(repository.expansionAmount.value).thenReturn(EXPANSION_VISIBLE)
|
||||
`when`(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE)
|
||||
`when`(repository.startingDisappearAnimation.value).thenReturn(null)
|
||||
assertThat(bouncerInteractor.isFullyShowing()).isTrue()
|
||||
`when`(repository.isVisible.value).thenReturn(false)
|
||||
@@ -255,7 +255,7 @@ class BouncerInteractorTest : SysuiTestCase() {
|
||||
assertThat(bouncerInteractor.isInTransit()).isTrue()
|
||||
`when`(repository.showingSoon.value).thenReturn(false)
|
||||
assertThat(bouncerInteractor.isInTransit()).isFalse()
|
||||
`when`(repository.expansionAmount.value).thenReturn(0.5f)
|
||||
`when`(repository.panelExpansionAmount.value).thenReturn(0.5f)
|
||||
assertThat(bouncerInteractor.isInTransit()).isTrue()
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
|
||||
|
||||
// WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(true);
|
||||
when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true);
|
||||
when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
|
||||
|
||||
// THEN we should intercept touch
|
||||
@@ -165,7 +165,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
|
||||
|
||||
// WHEN not showing alt auth, not dozing, drag down helper doesn't want to intercept
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(false);
|
||||
when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(false);
|
||||
when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
|
||||
|
||||
// THEN we shouldn't intercept touch
|
||||
@@ -178,7 +178,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
|
||||
|
||||
// WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(true);
|
||||
when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true);
|
||||
when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
|
||||
|
||||
// THEN we should handle the touch
|
||||
|
||||
Reference in New Issue
Block a user