diff options
18 files changed, 1029 insertions, 817 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 96fe65f8fd40..65fcd760360c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -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, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt index 7d0109686351..d70861ac5f19 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt @@ -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 -> { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java deleted file mode 100644 index 4d7f89d7b727..000000000000 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ /dev/null @@ -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(); - } - }; -} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt new file mode 100644 index 000000000000..5bae2dc502d6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt @@ -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" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt index 543389e0a7cd..76b8f26ea92c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt @@ -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) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractor.kt index 2af9318d92ec..e644347f5577 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractor.kt @@ -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. */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt index 9ad52117bfc6..9b76a2c9b073 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index e00f5ebad571..106fc75ac15a 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -4644,7 +4644,7 @@ public final class NotificationPanelViewController { mUpdateFlingVelocity = vel; } } else if (!mCentralSurfaces.isBouncerShowing() - && !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating() + && !mStatusBarKeyguardViewManager.isShowingAlternateAuth() && !mKeyguardStateController.isKeyguardGoingAway()) { onEmptySpaceClick(); onTrackingStopped(true); diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 65bd58d0d801..1e63b2dd134f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -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; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 9bb4132490d4..b2a9509a03b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -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; @@ -143,6 +148,14 @@ public class KeyguardBouncer { } /** + * 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 */ public void setBackButtonEnabled(boolean enabled) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index ccb5d8800ddb..f2d603ff0ca4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -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); @@ -1466,6 +1467,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. */ public float getQsExpansion() { @@ -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. */ @@ -1640,45 +1647,33 @@ 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 + * Use when an app occluding the keyguard would like to give the user ability to + * unlock the device using udfps. + * + * @param color of the udfps icon. should have proper contrast with its background. only + * used if requestUdfps = true */ - boolean onTouch(MotionEvent event); + void requestUdfps(boolean requestUdfps, int color); /** - * Update pin/pattern/password bouncer expansion amount where 0 is visible and 1 is fully - * hidden + * print information for the alternate auth interceptor registered */ - void setBouncerExpansionChanged(float expansion); + void dump(PrintWriter pw); + } + /** + * Callback for KeyguardViewManager state changes. + */ + public interface KeyguardViewManagerCallback { /** - * called when the bouncer view visibility has changed. + * Set the amount qs is expanded. For example, swipe down from the top of the + * lock screen to start the full QS expansion. */ - void onBouncerVisibilityChanged(); + default void onQSExpansionChanged(float qsExpansion) { } /** - * Use when an app occluding the keyguard would like to give the user ability to - * unlock the device using udfps. - * - * @param color of the udfps icon. should have proper contrast with its background. only - * used if requestUdfps = true + * Forward touch events to callbacks */ - void requestUdfps(boolean requestUdfps, int color); - + default void onTouch(MotionEvent event) { } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index c85334db9499..90948ff3b769 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -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() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 28e13b8e81ab..be39c0de22a1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -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()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java new file mode 100644 index 000000000000..e5c7a42c06a6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java @@ -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); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java index c0f9c82fb131..55b61948ee45 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -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 org.junit.Before; +import com.android.systemui.statusbar.phone.KeyguardBouncer; + 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(); - - 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); +public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest { + private @Captor ArgumentCaptor<KeyguardBouncer.BouncerExpansionCallback> + mBouncerExpansionCallbackCaptor; + private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback; + + @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(); @@ -202,20 +129,6 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { } @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(); captureStatusBarStateListeners(); @@ -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(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt new file mode 100644 index 000000000000..7b1976811868 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt @@ -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 + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractorTest.kt index e6c8dd87d982..c4e7dd241eb9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractorTest.kt @@ -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() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java index 26a0770a7bba..a4a7995ae3c8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java @@ -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 |