Modernize alternate bouncer logic
Test: atest BiometricRepositoryTest
Test: atest UdfpsKeyguardViewControllerWithCoroutinesTest
Test: atest AlternateBouncerInteractorTest
Test: atest SystemUITests SystemUIGoogleTests
Test: install DPM test app, change device policy requirements
and see that biometric repository is correctly updated
Bug: 237362467
Change-Id: Ia975fd65d929505d7e1259cfca1dede4cfbc8704
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index 54aa351..a450d3a 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -366,7 +366,7 @@
val dialog = animatedDialog.dialog
// Don't animate if the dialog is not showing or if we are locked and going to show the
- // bouncer.
+ // primary bouncer.
if (
!dialog.isShowing ||
(!callback.isUnlocked() && !callback.isShowingAlternateAuthOnUnlock())
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 51ade29..a974bea 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -689,6 +689,13 @@
}
/**
+ * Whether keyguard is going away due to screen off or device entry.
+ */
+ public boolean isKeyguardGoingAway() {
+ return mKeyguardGoingAway;
+ }
+
+ /**
* Updates KeyguardUpdateMonitor's internal state to know if keyguard is showing and if
* its occluded. The keyguard is considered visible if its showing and NOT occluded.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index db2239b..d035785 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -18,6 +18,7 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
@@ -79,6 +80,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.data.repository.BiometricType;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.VibratorHelper;
@@ -88,8 +90,10 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -158,6 +162,7 @@
@Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
@Nullable private List<FingerprintSensorPropertiesInternal> mSidefpsProps;
+ @NonNull private final Map<Integer, Boolean> mFpEnrolledForUser = new HashMap<>();
@NonNull private final SparseBooleanArray mUdfpsEnrolledForUser;
@NonNull private final SparseBooleanArray mFaceEnrolledForUser;
@NonNull private final SparseBooleanArray mSfpsEnrolledForUser;
@@ -170,7 +175,6 @@
private final @Background DelayableExecutor mBackgroundExecutor;
private final DisplayInfo mCachedDisplayInfo = new DisplayInfo();
-
private final VibratorHelper mVibratorHelper;
private void vibrateSuccess(int modality) {
@@ -348,12 +352,21 @@
mExecution.assertIsMainThread();
Log.d(TAG, "handleEnrollmentsChanged, userId: " + userId + ", sensorId: " + sensorId
+ ", hasEnrollments: " + hasEnrollments);
- if (mUdfpsProps == null) {
- Log.d(TAG, "handleEnrollmentsChanged, mUdfpsProps is null");
- } else {
- for (FingerprintSensorPropertiesInternal prop : mUdfpsProps) {
+ BiometricType sensorBiometricType = BiometricType.UNKNOWN;
+ if (mFpProps != null) {
+ for (FingerprintSensorPropertiesInternal prop: mFpProps) {
if (prop.sensorId == sensorId) {
- mUdfpsEnrolledForUser.put(userId, hasEnrollments);
+ mFpEnrolledForUser.put(userId, hasEnrollments);
+ if (prop.isAnyUdfpsType()) {
+ sensorBiometricType = BiometricType.UNDER_DISPLAY_FINGERPRINT;
+ mUdfpsEnrolledForUser.put(userId, hasEnrollments);
+ } else if (prop.isAnySidefpsType()) {
+ sensorBiometricType = BiometricType.SIDE_FINGERPRINT;
+ mSfpsEnrolledForUser.put(userId, hasEnrollments);
+ } else if (prop.sensorType == TYPE_REAR) {
+ sensorBiometricType = BiometricType.REAR_FINGERPRINT;
+ }
+ break;
}
}
}
@@ -363,20 +376,14 @@
for (FaceSensorPropertiesInternal prop : mFaceProps) {
if (prop.sensorId == sensorId) {
mFaceEnrolledForUser.put(userId, hasEnrollments);
- }
- }
- }
- if (mSidefpsProps == null) {
- Log.d(TAG, "handleEnrollmentsChanged, mSidefpsProps is null");
- } else {
- for (FingerprintSensorPropertiesInternal prop : mSidefpsProps) {
- if (prop.sensorId == sensorId) {
- mSfpsEnrolledForUser.put(userId, hasEnrollments);
+ sensorBiometricType = BiometricType.FACE;
+ break;
}
}
}
for (Callback cb : mCallbacks) {
cb.onEnrollmentsChanged(modality);
+ cb.onEnrollmentsChanged(sensorBiometricType, userId, hasEnrollments);
}
}
@@ -629,6 +636,11 @@
}
}
+ /** Get FP sensor properties */
+ public @Nullable List<FingerprintSensorPropertiesInternal> getFingerprintProperties() {
+ return mFpProps;
+ }
+
/**
* @return where the face sensor exists in pixels in the current device orientation. Returns
* null if no face sensor exists.
@@ -881,7 +893,7 @@
}
@Override
- public void setBiometicContextListener(IBiometricContextListener listener) {
+ public void setBiometricContextListener(IBiometricContextListener listener) {
mBiometricContextListener = listener;
notifyDozeChanged(mStatusBarStateController.isDozing(),
mWakefulnessLifecycle.getWakefulness());
@@ -1140,6 +1152,13 @@
return mCurrentDialog != null;
}
+ /**
+ * Whether the passed userId has enrolled at least one fingerprint.
+ */
+ public boolean isFingerprintEnrolled(int userId) {
+ return mFpEnrolledForUser.getOrDefault(userId, false);
+ }
+
private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
mCurrentDialogArgs = args;
@@ -1323,6 +1342,16 @@
default void onEnrollmentsChanged(@Modality int modality) {}
/**
+ * Called when UDFPS enrollments have changed. This is called after boot and on changes to
+ * enrollment.
+ */
+ default void onEnrollmentsChanged(
+ @NonNull BiometricType biometricType,
+ int userId,
+ boolean hasEnrollments
+ ) {}
+
+ /**
* Called when the biometric prompt starts showing.
*/
default void onBiometricPromptShown() {}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
index 4130cf5..ef7dcb7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -190,11 +190,6 @@
open fun listenForTouchesOutsideView(): Boolean = false
/**
- * Called on touches outside of the view if listenForTouchesOutsideView returns true
- */
- open fun onTouchOutsideView() {}
-
- /**
* Called when a view should announce an accessibility event.
*/
open fun doAnnounceForAccessibility(str: String) {}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 19b0548..aa643f0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -74,6 +74,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -149,6 +150,7 @@
@NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator;
@NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@Nullable private final TouchProcessor mTouchProcessor;
+ @NonNull private final AlternateBouncerInteractor mAlternateBouncerInteractor;
// 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.
@@ -236,12 +238,12 @@
mShadeExpansionStateManager, mKeyguardViewManager,
mKeyguardUpdateMonitor, mDialogManager, mDumpManager,
mLockscreenShadeTransitionController, mConfigurationController,
- mSystemClock, mKeyguardStateController,
+ mKeyguardStateController,
mUnlockedScreenOffAnimationController,
mUdfpsDisplayMode, requestId, reason, callback,
(view, event, fromUdfpsView) -> onTouch(requestId, event,
fromUdfpsView), mActivityLaunchAnimator, mFeatureFlags,
- mPrimaryBouncerInteractor)));
+ mPrimaryBouncerInteractor, mAlternateBouncerInteractor)));
}
@Override
@@ -360,13 +362,13 @@
if (!mOverlayParams.equals(overlayParams)) {
mOverlayParams = overlayParams;
- final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateBouncer();
+ final boolean wasShowingAlternateBouncer = mAlternateBouncerInteractor.isVisibleState();
// When the bounds change it's always necessary to re-create the overlay's window with
// new LayoutParams. If the overlay needs to be shown, this will re-create and show the
// overlay with the updated LayoutParams. Otherwise, the overlay will remain hidden.
redrawOverlay();
- if (wasShowingAltAuth) {
+ if (wasShowingAlternateBouncer) {
mKeyguardViewManager.showBouncer(true);
}
}
@@ -574,9 +576,6 @@
final UdfpsView udfpsView = mOverlay.getOverlayView();
boolean handled = false;
switch (event.getActionMasked()) {
- case MotionEvent.ACTION_OUTSIDE:
- udfpsView.onTouchOutsideView();
- return true;
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_HOVER_ENTER:
Trace.beginSection("UdfpsController.onTouch.ACTION_DOWN");
@@ -750,7 +749,8 @@
@NonNull Optional<AlternateUdfpsTouchProvider> alternateTouchProvider,
@NonNull @BiometricsBackground Executor biometricsExecutor,
@NonNull PrimaryBouncerInteractor primaryBouncerInteractor,
- @NonNull SinglePointerTouchProcessor singlePointerTouchProcessor) {
+ @NonNull SinglePointerTouchProcessor singlePointerTouchProcessor,
+ @NonNull AlternateBouncerInteractor alternateBouncerInteractor) {
mContext = context;
mExecution = execution;
mVibrator = vibrator;
@@ -790,6 +790,7 @@
mBiometricExecutor = biometricsExecutor;
mPrimaryBouncerInteractor = primaryBouncerInteractor;
+ mAlternateBouncerInteractor = alternateBouncerInteractor;
mTouchProcessor = mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
? singlePointerTouchProcessor : null;
@@ -884,9 +885,7 @@
onFingerUp(mOverlay.getRequestId(), oldView);
}
final boolean removed = mOverlay.hide();
- if (mKeyguardViewManager.isShowingAlternateBouncer()) {
- mKeyguardViewManager.hideAlternateBouncer(true);
- }
+ mKeyguardViewManager.hideAlternateBouncer(true);
Log.v(TAG, "hideUdfpsOverlay | removing window: " + removed);
} else {
Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 8db4927..a3c4985 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -50,6 +50,7 @@
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.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionStateManager
@@ -59,7 +60,6 @@
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
private const val TAG = "UdfpsControllerOverlay"
@@ -86,7 +86,6 @@
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,
@@ -97,7 +96,8 @@
private val activityLaunchAnimator: ActivityLaunchAnimator,
private val featureFlags: FeatureFlags,
private val primaryBouncerInteractor: PrimaryBouncerInteractor,
- private val isDebuggable: Boolean = Build.IS_DEBUGGABLE
+ private val alternateBouncerInteractor: AlternateBouncerInteractor,
+ private val isDebuggable: Boolean = Build.IS_DEBUGGABLE,
) {
/** The view, when [isShowing], or null. */
var overlayView: UdfpsView? = null
@@ -255,14 +255,14 @@
dumpManager,
transitionController,
configurationController,
- systemClock,
keyguardStateController,
unlockedScreenOffAnimationController,
dialogManager,
controller,
activityLaunchAnimator,
featureFlags,
- primaryBouncerInteractor
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
)
}
REASON_AUTH_BP -> {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index 63144fc..583ee3a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -31,6 +31,7 @@
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.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -42,13 +43,13 @@
import com.android.systemui.statusbar.phone.KeyguardBouncer
import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.AlternateBouncer
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.KeyguardViewManagerCallback
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.OccludingAppBiometricUI
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
@@ -65,25 +66,27 @@
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 primaryBouncerInteractor: PrimaryBouncerInteractor
+ private val primaryBouncerInteractor: PrimaryBouncerInteractor,
+ private val alternateBouncerInteractor: AlternateBouncerInteractor,
) :
UdfpsAnimationViewController<UdfpsKeyguardView>(
view,
statusBarStateController,
shadeExpansionStateManager,
systemUIDialogManager,
- dumpManager
+ dumpManager,
) {
private val useExpandedOverlay: Boolean =
featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
private val isModernBouncerEnabled: Boolean = featureFlags.isEnabled(Flags.MODERN_BOUNCER)
+ private val isModernAlternateBouncerEnabled: Boolean =
+ featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER)
private var showingUdfpsBouncer = false
private var udfpsRequested = false
private var qsExpansion = 0f
@@ -91,7 +94,6 @@
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
@@ -244,20 +246,8 @@
}
}
- private val mAlternateBouncer: AlternateBouncer =
- object : AlternateBouncer {
- override fun showAlternateBouncer(): Boolean {
- return showUdfpsBouncer(true)
- }
-
- override fun hideAlternateBouncer(): Boolean {
- return showUdfpsBouncer(false)
- }
-
- override fun isShowingAlternateBouncer(): Boolean {
- return showingUdfpsBouncer
- }
-
+ private val occludingAppBiometricUI: OccludingAppBiometricUI =
+ object : OccludingAppBiometricUI {
override fun requestUdfps(request: Boolean, color: Int) {
udfpsRequested = request
view.requestUdfps(request, color)
@@ -275,16 +265,19 @@
override fun onInit() {
super.onInit()
- keyguardViewManager.setAlternateBouncer(mAlternateBouncer)
+ keyguardViewManager.setOccludingAppBiometricUI(occludingAppBiometricUI)
}
init {
- if (isModernBouncerEnabled) {
+ if (isModernBouncerEnabled || isModernAlternateBouncerEnabled) {
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) }
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ if (isModernBouncerEnabled) listenForBouncerExpansion(this)
+ if (isModernAlternateBouncerEnabled) listenForAlternateBouncerVisibility(this)
+ }
}
}
}
@@ -300,8 +293,18 @@
}
}
+ @VisibleForTesting
+ internal suspend fun listenForAlternateBouncerVisibility(scope: CoroutineScope): Job {
+ return scope.launch {
+ alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
+ showUdfpsBouncer(isVisible)
+ }
+ }
+ }
+
public override fun onViewAttached() {
super.onViewAttached()
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(true)
val dozeAmount = statusBarStateController.dozeAmount
lastDozeAmount = dozeAmount
stateListener.onDozeAmountChanged(dozeAmount, dozeAmount)
@@ -326,7 +329,8 @@
view.updatePadding()
updateAlpha()
updatePauseAuth()
- keyguardViewManager.setAlternateBouncer(mAlternateBouncer)
+ keyguardViewManager.setLegacyAlternateBouncer(legacyAlternateBouncer)
+ keyguardViewManager.setOccludingAppBiometricUI(occludingAppBiometricUI)
lockScreenShadeTransitionController.udfpsKeyguardViewController = this
activityLaunchAnimator.addListener(activityLaunchAnimatorListener)
view.mUseExpandedOverlay = useExpandedOverlay
@@ -334,10 +338,12 @@
override fun onViewDetached() {
super.onViewDetached()
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(false)
faceDetectRunning = false
keyguardStateController.removeCallback(keyguardStateControllerCallback)
statusBarStateController.removeCallback(stateListener)
- keyguardViewManager.removeAlternateAuthInterceptor(mAlternateBouncer)
+ keyguardViewManager.removeLegacyAlternateBouncer(legacyAlternateBouncer)
+ keyguardViewManager.removeOccludingAppBiometricUI(occludingAppBiometricUI)
keyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false)
configurationController.removeCallback(configurationListener)
shadeExpansionStateManager.removeExpansionListener(shadeExpansionListener)
@@ -356,7 +362,16 @@
override fun dump(pw: PrintWriter, args: Array<String>) {
super.dump(pw, args)
pw.println("isModernBouncerEnabled=$isModernBouncerEnabled")
+ pw.println("isModernAlternateBouncerEnabled=$isModernAlternateBouncerEnabled")
pw.println("showingUdfpsAltBouncer=$showingUdfpsBouncer")
+ pw.println(
+ "altBouncerInteractor#isAlternateBouncerVisible=" +
+ "${alternateBouncerInteractor.isVisibleState()}"
+ )
+ pw.println(
+ "altBouncerInteractor#canShowAlternateBouncerForFingerprint=" +
+ "${alternateBouncerInteractor.canShowAlternateBouncerForFingerprint()}"
+ )
pw.println("faceDetectRunning=$faceDetectRunning")
pw.println("statusBarState=" + StatusBarState.toString(statusBarState))
pw.println("transitionToFullShadeProgress=$transitionToFullShadeProgress")
@@ -385,9 +400,6 @@
val udfpsAffordanceWasNotShowing = shouldPauseAuth()
showingUdfpsBouncer = show
if (showingUdfpsBouncer) {
- lastUdfpsBouncerShowTime = systemClock.uptimeMillis()
- }
- if (showingUdfpsBouncer) {
if (udfpsAffordanceWasNotShowing) {
view.animateInUdfpsBouncer(null)
}
@@ -452,7 +464,7 @@
return if (isModernBouncerEnabled) {
inputBouncerExpansion == 1f
} else {
- keyguardViewManager.isBouncerShowing && !keyguardViewManager.isShowingAlternateBouncer
+ keyguardViewManager.isBouncerShowing && !alternateBouncerInteractor.isVisibleState()
}
}
@@ -460,30 +472,6 @@
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.showPrimaryBouncer(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
@@ -545,7 +533,7 @@
if (isModernBouncerEnabled) {
return
}
- val altBouncerShowing = keyguardViewManager.isShowingAlternateBouncer
+ val altBouncerShowing = alternateBouncerInteractor.isVisibleState()
if (altBouncerShowing || !keyguardViewManager.primaryBouncerIsOrWillBeShowing()) {
inputBouncerHiddenAmount = 1f
} else if (keyguardViewManager.isBouncerShowing) {
@@ -554,6 +542,21 @@
}
}
+ private val legacyAlternateBouncer: LegacyAlternateBouncer =
+ object : LegacyAlternateBouncer {
+ override fun showAlternateBouncer(): Boolean {
+ return showUdfpsBouncer(true)
+ }
+
+ override fun hideAlternateBouncer(): Boolean {
+ return showUdfpsBouncer(false)
+ }
+
+ override fun isShowingAlternateBouncer(): Boolean {
+ return showingUdfpsBouncer
+ }
+ }
+
companion object {
const val TAG = "UdfpsKeyguardViewController"
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
index 4a8877e..e61c614 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
@@ -111,10 +111,6 @@
}
}
- fun onTouchOutsideView() {
- animationViewController?.onTouchOutsideView()
- }
-
override fun onAttachedToWindow() {
super.onAttachedToWindow()
Log.v(TAG, "onAttachedToWindow")
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index ae2e1d1..d03ec77 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -170,6 +170,13 @@
@JvmField
val LIGHT_REVEAL_MIGRATION = unreleasedFlag(218, "light_reveal_migration", teamfood = true)
+ /**
+ * Whether to use the new alternate bouncer architecture, a refactor of and eventual replacement
+ * of the Alternate/Authentication Bouncer. No visual UI changes.
+ */
+ // TODO(b/260619425): Tracking Bug
+ @JvmField val MODERN_ALTERNATE_BOUNCER = unreleasedFlag(219, "modern_alternate_bouncer")
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricRepository.kt
new file mode 100644
index 0000000..25d8f40
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricRepository.kt
@@ -0,0 +1,184 @@
+/*
+ * 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.keyguard.data.repository
+
+import android.app.admin.DevicePolicyManager
+import android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
+import android.content.Context
+import android.content.IntentFilter
+import android.os.Looper
+import android.os.UserHandle
+import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.biometrics.AuthController
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.user.data.repository.UserRepository
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.transformLatest
+
+/**
+ * Acts as source of truth for biometric features.
+ *
+ * Abstracts-away data sources and their schemas so the rest of the app doesn't need to worry about
+ * upstream changes.
+ */
+interface BiometricRepository {
+ /** Whether any fingerprints are enrolled for the current user. */
+ val isFingerprintEnrolled: StateFlow<Boolean>
+
+ /**
+ * Whether the current user is allowed to use a strong biometric for device entry based on
+ * Android Security policies. If false, the user may be able to use primary authentication for
+ * device entry.
+ */
+ val isStrongBiometricAllowed: StateFlow<Boolean>
+
+ /** Whether fingerprint feature is enabled for the current user by the DevicePolicy */
+ val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean>
+}
+
+@SysUISingleton
+class BiometricRepositoryImpl
+@Inject
+constructor(
+ context: Context,
+ lockPatternUtils: LockPatternUtils,
+ broadcastDispatcher: BroadcastDispatcher,
+ authController: AuthController,
+ userRepository: UserRepository,
+ devicePolicyManager: DevicePolicyManager,
+ @Application scope: CoroutineScope,
+ @Background backgroundDispatcher: CoroutineDispatcher,
+ @Main looper: Looper,
+) : BiometricRepository {
+
+ /** UserId of the current selected user. */
+ private val selectedUserId: Flow<Int> =
+ userRepository.selectedUserInfo.map { it.id }.distinctUntilChanged()
+
+ override val isFingerprintEnrolled: StateFlow<Boolean> =
+ selectedUserId
+ .flatMapLatest { userId ->
+ conflatedCallbackFlow {
+ val callback =
+ object : AuthController.Callback {
+ override fun onEnrollmentsChanged(
+ sensorBiometricType: BiometricType,
+ userId: Int,
+ hasEnrollments: Boolean
+ ) {
+ if (sensorBiometricType.isFingerprint) {
+ trySendWithFailureLogging(
+ hasEnrollments,
+ TAG,
+ "update fpEnrollment"
+ )
+ }
+ }
+ }
+ authController.addCallback(callback)
+ awaitClose { authController.removeCallback(callback) }
+ }
+ }
+ .stateIn(
+ scope,
+ started = SharingStarted.Eagerly,
+ initialValue =
+ authController.isFingerprintEnrolled(userRepository.getSelectedUserInfo().id)
+ )
+
+ override val isStrongBiometricAllowed: StateFlow<Boolean> =
+ selectedUserId
+ .flatMapLatest { currUserId ->
+ conflatedCallbackFlow {
+ val callback =
+ object : LockPatternUtils.StrongAuthTracker(context, looper) {
+ override fun onStrongAuthRequiredChanged(userId: Int) {
+ if (currUserId != userId) {
+ return
+ }
+
+ trySendWithFailureLogging(
+ isBiometricAllowedForUser(true, currUserId),
+ TAG
+ )
+ }
+
+ override fun onIsNonStrongBiometricAllowedChanged(userId: Int) {
+ // no-op
+ }
+ }
+ lockPatternUtils.registerStrongAuthTracker(callback)
+ awaitClose { lockPatternUtils.unregisterStrongAuthTracker(callback) }
+ }
+ }
+ .stateIn(
+ scope,
+ started = SharingStarted.Eagerly,
+ initialValue =
+ lockPatternUtils.isBiometricAllowedForUser(
+ userRepository.getSelectedUserInfo().id
+ )
+ )
+
+ override val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean> =
+ selectedUserId
+ .flatMapLatest { userId ->
+ broadcastDispatcher
+ .broadcastFlow(
+ filter = IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+ user = UserHandle.ALL
+ )
+ .transformLatest {
+ emit(
+ (devicePolicyManager.getKeyguardDisabledFeatures(null, userId) and
+ DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) == 0
+ )
+ }
+ .flowOn(backgroundDispatcher)
+ .distinctUntilChanged()
+ }
+ .stateIn(
+ scope,
+ started = SharingStarted.Eagerly,
+ initialValue =
+ devicePolicyManager.getKeyguardDisabledFeatures(
+ null,
+ userRepository.getSelectedUserInfo().id
+ ) and DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT == 0
+ )
+
+ companion object {
+ private const val TAG = "BiometricsRepositoryImpl"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricType.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricType.kt
new file mode 100644
index 0000000..93c9781
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricType.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.keyguard.data.repository
+
+enum class BiometricType(val isFingerprint: Boolean) {
+ // An unsupported biometric type
+ UNKNOWN(false),
+
+ // Fingerprint sensor that is located on the back (opposite side of the display) of the device
+ REAR_FINGERPRINT(true),
+
+ // Fingerprint sensor that is located under the display
+ UNDER_DISPLAY_FINGERPRINT(true),
+
+ // Fingerprint sensor that is located on the side of the device, typically on the power button
+ SIDE_FINGERPRINT(true),
+ FACE(false),
+}
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 783f752..b461ebf 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
@@ -16,14 +16,15 @@
package com.android.systemui.keyguard.data.repository
-import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel
import com.android.systemui.statusbar.phone.KeyguardBouncer
+import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/** Encapsulates app state for the lock screen primary and alternate bouncer. */
@@ -32,7 +33,7 @@
@Inject
constructor(
private val viewMediatorCallback: ViewMediatorCallback,
- keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val clock: SystemClock,
) {
/** Values associated with the PrimaryBouncer (pin/pattern/password) input. */
private val _primaryBouncerVisible = MutableStateFlow(false)
@@ -77,6 +78,14 @@
val bouncerErrorMessage: CharSequence?
get() = viewMediatorCallback.consumeCustomMessage()
+ /** Values associated with the AlternateBouncer */
+ private val _isAlternateBouncerVisible = MutableStateFlow(false)
+ val isAlternateBouncerVisible = _isAlternateBouncerVisible.asStateFlow()
+ var lastAlternateBouncerVisibleTime: Long = NOT_VISIBLE
+ private val _isAlternateBouncerUIAvailable = MutableStateFlow<Boolean>(false)
+ val isAlternateBouncerUIAvailable: StateFlow<Boolean> =
+ _isAlternateBouncerUIAvailable.asStateFlow()
+
fun setPrimaryScrimmed(isScrimmed: Boolean) {
_primaryBouncerScrimmed.value = isScrimmed
}
@@ -85,6 +94,19 @@
_primaryBouncerVisible.value = isVisible
}
+ fun setAlternateVisible(isVisible: Boolean) {
+ if (isVisible && !_isAlternateBouncerVisible.value) {
+ lastAlternateBouncerVisibleTime = clock.uptimeMillis()
+ } else if (!isVisible) {
+ lastAlternateBouncerVisibleTime = NOT_VISIBLE
+ }
+ _isAlternateBouncerVisible.value = isVisible
+ }
+
+ fun setAlternateBouncerUIAvailable(isAvailable: Boolean) {
+ _isAlternateBouncerUIAvailable.value = isAvailable
+ }
+
fun setPrimaryShow(keyguardBouncerModel: KeyguardBouncerModel?) {
_primaryBouncerShow.value = keyguardBouncerModel
}
@@ -132,4 +154,8 @@
fun setOnScreenTurnedOff(onScreenTurnedOff: Boolean) {
_onScreenTurnedOff.value = onScreenTurnedOff
}
+
+ companion object {
+ private const val NOT_VISIBLE = -1L
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 26f853f..4639597 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -30,4 +30,6 @@
@Binds
fun lightRevealScrimRepository(impl: LightRevealScrimRepositoryImpl): LightRevealScrimRepository
+
+ @Binds fun biometricRepository(impl: BiometricRepositoryImpl): BiometricRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
new file mode 100644
index 0000000..28c0b28
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.keyguard.domain.interactor
+
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.BiometricRepository
+import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer
+import com.android.systemui.util.time.SystemClock
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Encapsulates business logic for interacting with the lock-screen alternate bouncer. */
+@SysUISingleton
+class AlternateBouncerInteractor
+@Inject
+constructor(
+ private val bouncerRepository: KeyguardBouncerRepository,
+ private val biometricRepository: BiometricRepository,
+ private val systemClock: SystemClock,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ featureFlags: FeatureFlags,
+) {
+ val isModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER)
+ var legacyAlternateBouncer: LegacyAlternateBouncer? = null
+ var legacyAlternateBouncerVisibleTime: Long = NOT_VISIBLE
+
+ val isVisible: Flow<Boolean> = bouncerRepository.isAlternateBouncerVisible
+
+ /**
+ * Sets the correct bouncer states to show the alternate bouncer if it can show.
+ * @return whether alternateBouncer is visible
+ */
+ fun show(): Boolean {
+ return when {
+ isModernAlternateBouncerEnabled -> {
+ bouncerRepository.setAlternateVisible(canShowAlternateBouncerForFingerprint())
+ isVisibleState()
+ }
+ canShowAlternateBouncerForFingerprint() -> {
+ if (legacyAlternateBouncer?.showAlternateBouncer() == true) {
+ legacyAlternateBouncerVisibleTime = systemClock.uptimeMillis()
+ true
+ } else {
+ false
+ }
+ }
+ else -> false
+ }
+ }
+
+ /**
+ * Sets the correct bouncer states to hide the bouncer. Should only be called through
+ * StatusBarKeyguardViewManager until ScrimController is refactored to use
+ * alternateBouncerInteractor.
+ * @return true if the alternate bouncer was newly hidden, else false.
+ */
+ fun hide(): Boolean {
+ return if (isModernAlternateBouncerEnabled) {
+ val wasAlternateBouncerVisible = isVisibleState()
+ bouncerRepository.setAlternateVisible(false)
+ wasAlternateBouncerVisible && !isVisibleState()
+ } else {
+ legacyAlternateBouncer?.hideAlternateBouncer() ?: false
+ }
+ }
+
+ fun isVisibleState(): Boolean {
+ return if (isModernAlternateBouncerEnabled) {
+ bouncerRepository.isAlternateBouncerVisible.value
+ } else {
+ legacyAlternateBouncer?.isShowingAlternateBouncer ?: false
+ }
+ }
+
+ fun setAlternateBouncerUIAvailable(isAvailable: Boolean) {
+ bouncerRepository.setAlternateBouncerUIAvailable(isAvailable)
+ }
+
+ fun canShowAlternateBouncerForFingerprint(): Boolean {
+ return if (isModernAlternateBouncerEnabled) {
+ bouncerRepository.isAlternateBouncerUIAvailable.value &&
+ biometricRepository.isFingerprintEnrolled.value &&
+ biometricRepository.isStrongBiometricAllowed.value &&
+ biometricRepository.isFingerprintEnabledByDevicePolicy.value
+ } else {
+ legacyAlternateBouncer != null &&
+ keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true)
+ }
+ }
+
+ /**
+ * Whether the alt bouncer has shown for a minimum time before allowing touches to dismiss the
+ * alternate bouncer and show the primary bouncer.
+ */
+ fun hasAlternateBouncerShownWithMinTime(): Boolean {
+ return if (isModernAlternateBouncerEnabled) {
+ (systemClock.uptimeMillis() - bouncerRepository.lastAlternateBouncerVisibleTime) >
+ MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS
+ } else {
+ systemClock.uptimeMillis() - legacyAlternateBouncerVisibleTime > 200
+ }
+ }
+
+ companion object {
+ private const val MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS = 200L
+ private const val NOT_VISIBLE = -1L
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 507dec6..4ee1051 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -136,6 +136,7 @@
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
@@ -351,6 +352,7 @@
private final FragmentListener mQsFragmentListener = new QsFragmentListener();
private final AccessibilityDelegate mAccessibilityDelegate = new ShadeAccessibilityDelegate();
private final NotificationGutsManager mGutsManager;
+ private final AlternateBouncerInteractor mAlternateBouncerInteractor;
private long mDownTime;
private boolean mTouchSlopExceededBeforeDown;
@@ -757,6 +759,7 @@
SystemClock systemClock,
KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
KeyguardBottomAreaInteractor keyguardBottomAreaInteractor,
+ AlternateBouncerInteractor alternateBouncerInteractor,
DumpManager dumpManager) {
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
@@ -937,6 +940,7 @@
unlockAnimationStarted(playingCannedAnimation, isWakeAndUnlock, startDelay);
}
});
+ mAlternateBouncerInteractor = alternateBouncerInteractor;
dumpManager.registerDumpable(this);
}
@@ -4810,7 +4814,7 @@
mUpdateFlingVelocity = vel;
}
} else if (!mCentralSurfaces.isBouncerShowing()
- && !mStatusBarKeyguardViewManager.isShowingAlternateBouncer()
+ && !mAlternateBouncerInteractor.isVisibleState()
&& !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 d773c01..3a011c5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -38,6 +38,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.ui.binder.KeyguardBouncerViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.statusbar.DragDownHelper;
@@ -78,6 +79,7 @@
private final AmbientState mAmbientState;
private final PulsingGestureListener mPulsingGestureListener;
private final NotificationInsetsController mNotificationInsetsController;
+ private final AlternateBouncerInteractor mAlternateBouncerInteractor;
private GestureDetector mPulsingWakeupGestureHandler;
private View mBrightnessMirror;
@@ -118,7 +120,8 @@
PulsingGestureListener pulsingGestureListener,
FeatureFlags featureFlags,
KeyguardBouncerViewModel keyguardBouncerViewModel,
- KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory
+ KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
+ AlternateBouncerInteractor alternateBouncerInteractor
) {
mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
@@ -138,6 +141,7 @@
mAmbientState = ambientState;
mPulsingGestureListener = pulsingGestureListener;
mNotificationInsetsController = notificationInsetsController;
+ mAlternateBouncerInteractor = alternateBouncerInteractor;
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -289,7 +293,7 @@
return true;
}
- if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) {
+ if (mAlternateBouncerInteractor.isVisibleState()) {
// capture all touches if the alt auth bouncer is showing
return true;
}
@@ -327,7 +331,7 @@
handled = !mService.isPulsing();
}
- if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) {
+ if (mAlternateBouncerInteractor.isVisibleState()) {
// eat the touch
handled = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 590a04a..bad942f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -332,7 +332,7 @@
/**
* @see IStatusBar#setBiometicContextListener(IBiometricContextListener)
*/
- default void setBiometicContextListener(IBiometricContextListener listener) {
+ default void setBiometricContextListener(IBiometricContextListener listener) {
}
/**
@@ -1580,7 +1580,7 @@
}
case MSG_SET_BIOMETRICS_LISTENER:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).setBiometicContextListener(
+ mCallbacks.get(i).setBiometricContextListener(
(IBiometricContextListener) msg.obj);
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 0f27420..efe0ee2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -90,6 +90,7 @@
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -155,6 +156,7 @@
private final KeyguardBypassController mKeyguardBypassController;
private final AccessibilityManager mAccessibilityManager;
private final Handler mHandler;
+ private final AlternateBouncerInteractor mAlternateBouncerInteractor;
@VisibleForTesting
public KeyguardIndicationRotateTextViewController mRotateTextViewController;
@@ -234,7 +236,8 @@
KeyguardBypassController keyguardBypassController,
AccessibilityManager accessibilityManager,
FaceHelpMessageDeferral faceHelpMessageDeferral,
- KeyguardLogger keyguardLogger) {
+ KeyguardLogger keyguardLogger,
+ AlternateBouncerInteractor alternateBouncerInteractor) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mDevicePolicyManager = devicePolicyManager;
@@ -256,6 +259,7 @@
mScreenLifecycle = screenLifecycle;
mKeyguardLogger = keyguardLogger;
mScreenLifecycle.addObserver(mScreenObserver);
+ mAlternateBouncerInteractor = alternateBouncerInteractor;
mFaceAcquiredMessageDeferral = faceHelpMessageDeferral;
mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
@@ -928,7 +932,7 @@
}
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
- if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) {
+ if (mAlternateBouncerInteractor.isVisibleState()) {
return; // udfps affordance is highlighted, no need to show action to unlock
} else if (mKeyguardUpdateMonitor.isFaceEnrolled()) {
String message = mContext.getString(R.string.keyguard_retry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 14d0d7e..9a65e34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -31,6 +31,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpHandler;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -61,7 +62,6 @@
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarIconList;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallFlags;
@@ -280,7 +280,7 @@
@SysUISingleton
static DialogLaunchAnimator provideDialogLaunchAnimator(IDreamManager dreamManager,
KeyguardStateController keyguardStateController,
- Lazy<StatusBarKeyguardViewManager> statusBarKeyguardViewManager,
+ Lazy<AlternateBouncerInteractor> alternateBouncerInteractor,
InteractionJankMonitor interactionJankMonitor) {
DialogLaunchAnimator.Callback callback = new DialogLaunchAnimator.Callback() {
@Override
@@ -300,7 +300,7 @@
@Override
public boolean isShowingAlternateAuthOnUnlock() {
- return statusBarKeyguardViewManager.get().canShowAlternateBouncer();
+ return alternateBouncerInteractor.get().canShowAlternateBouncerForFingerprint();
}
};
return new DialogLaunchAnimator(callback, interactionJankMonitor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index b394535..d2be8f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -157,6 +157,7 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.ui.binder.LightRevealScrimViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
import com.android.systemui.navigationbar.NavigationBarController;
@@ -465,6 +466,7 @@
private final ShadeController mShadeController;
private final InitController mInitController;
private final Lazy<CameraLauncher> mCameraLauncherLazy;
+ private final AlternateBouncerInteractor mAlternateBouncerInteractor;
private final PluginDependencyProvider mPluginDependencyProvider;
private final KeyguardDismissUtil mKeyguardDismissUtil;
@@ -743,7 +745,9 @@
WiredChargingRippleController wiredChargingRippleController,
IDreamManager dreamManager,
Lazy<CameraLauncher> cameraLauncherLazy,
- Lazy<LightRevealScrimViewModel> lightRevealScrimViewModelLazy) {
+ Lazy<LightRevealScrimViewModel> lightRevealScrimViewModelLazy,
+ AlternateBouncerInteractor alternateBouncerInteractor
+ ) {
mContext = context;
mNotificationsController = notificationsController;
mFragmentService = fragmentService;
@@ -821,6 +825,7 @@
mWallpaperManager = wallpaperManager;
mJankMonitor = jankMonitor;
mCameraLauncherLazy = cameraLauncherLazy;
+ mAlternateBouncerInteractor = alternateBouncerInteractor;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mStartingSurfaceOptional = startingSurfaceOptional;
@@ -3222,8 +3227,7 @@
private void showBouncerOrLockScreenIfKeyguard() {
// If the keyguard is animating away, we aren't really the keyguard anymore and should not
// show the bouncer/lockscreen.
- if (!mKeyguardViewMediator.isHiding()
- && !mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
+ if (!mKeyguardViewMediator.isHiding() && !mKeyguardUpdateMonitor.isKeyguardGoingAway()) {
if (mState == StatusBarState.SHADE_LOCKED) {
// shade is showing while locked on the keyguard, so go back to showing the
// lock screen where users can use the UDFPS affordance to enter the device
@@ -3702,7 +3706,7 @@
boolean launchingAffordanceWithPreview = mLaunchingAffordance;
mScrimController.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
- if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) {
+ if (mAlternateBouncerInteractor.isVisibleState()) {
if (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
|| mTransitionToFullShadeProgress > 0f) {
mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
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 aafcddd..9e069e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -58,6 +58,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.data.BouncerView;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationBarView;
@@ -134,6 +135,7 @@
private KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController;
private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+ private final AlternateBouncerInteractor mAlternateBouncerInteractor;
private final BouncerView mPrimaryBouncerView;
private final Lazy<com.android.systemui.shade.ShadeController> mShadeController;
@@ -252,6 +254,7 @@
private float mQsExpansion;
final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
private boolean mIsModernBouncerEnabled;
+ private boolean mIsModernAlternateBouncerEnabled;
private OnDismissAction mAfterKeyguardGoneAction;
private Runnable mKeyguardGoneCancelAction;
@@ -268,7 +271,7 @@
private final LatencyTracker mLatencyTracker;
private final KeyguardSecurityModel mKeyguardSecurityModel;
@Nullable private KeyguardBypassController mBypassController;
- @Nullable private AlternateBouncer mAlternateBouncer;
+ @Nullable private OccludingAppBiometricUI mOccludingAppBiometricUI;
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@@ -305,7 +308,8 @@
FeatureFlags featureFlags,
PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor,
PrimaryBouncerInteractor primaryBouncerInteractor,
- BouncerView primaryBouncerView) {
+ BouncerView primaryBouncerView,
+ AlternateBouncerInteractor alternateBouncerInteractor) {
mContext = context;
mViewMediatorCallback = callback;
mLockPatternUtils = lockPatternUtils;
@@ -329,6 +333,8 @@
mFoldAodAnimationController = sysUIUnfoldComponent
.map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
mIsModernBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_BOUNCER);
+ mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER);
+ mAlternateBouncerInteractor = alternateBouncerInteractor;
}
@Override
@@ -361,23 +367,51 @@
}
/**
- * Sets the given alt auth interceptor to null if it's the current auth interceptor. Else,
- * does nothing.
+ * Sets the given legacy alternate bouncer to null if it's the current alternate bouncer. Else,
+ * does nothing. Only used if modern alternate bouncer is NOT enabled.
*/
- public void removeAlternateAuthInterceptor(@NonNull AlternateBouncer authInterceptor) {
- if (Objects.equals(mAlternateBouncer, authInterceptor)) {
- mAlternateBouncer = null;
- hideAlternateBouncer(true);
+ public void removeLegacyAlternateBouncer(
+ @NonNull LegacyAlternateBouncer alternateBouncerLegacy) {
+ if (!mIsModernAlternateBouncerEnabled) {
+ if (Objects.equals(mAlternateBouncerInteractor.getLegacyAlternateBouncer(),
+ alternateBouncerLegacy)) {
+ mAlternateBouncerInteractor.setLegacyAlternateBouncer(null);
+ hideAlternateBouncer(true);
+ }
}
}
/**
- * Sets a new alt auth interceptor.
+ * Sets a new legacy alternate bouncer. Only used if mdoern alternate bouncer is NOT enable.
*/
- public void setAlternateBouncer(@NonNull AlternateBouncer authInterceptor) {
- if (!Objects.equals(mAlternateBouncer, authInterceptor)) {
- mAlternateBouncer = authInterceptor;
- hideAlternateBouncer(false);
+ public void setLegacyAlternateBouncer(@NonNull LegacyAlternateBouncer alternateBouncerLegacy) {
+ if (!mIsModernAlternateBouncerEnabled) {
+ if (!Objects.equals(mAlternateBouncerInteractor.getLegacyAlternateBouncer(),
+ alternateBouncerLegacy)) {
+ mAlternateBouncerInteractor.setLegacyAlternateBouncer(alternateBouncerLegacy);
+ hideAlternateBouncer(false);
+ }
+ }
+
+ }
+
+
+ /**
+ * Sets the given OccludingAppBiometricUI to null if it's the current auth interceptor. Else,
+ * does nothing.
+ */
+ public void removeOccludingAppBiometricUI(@NonNull OccludingAppBiometricUI biometricUI) {
+ if (Objects.equals(mOccludingAppBiometricUI, biometricUI)) {
+ mOccludingAppBiometricUI = null;
+ }
+ }
+
+ /**
+ * Sets a new OccludingAppBiometricUI.
+ */
+ public void setOccludingAppBiometricUI(@NonNull OccludingAppBiometricUI biometricUI) {
+ if (!Objects.equals(mOccludingAppBiometricUI, biometricUI)) {
+ mOccludingAppBiometricUI = biometricUI;
}
}
@@ -564,18 +598,11 @@
* {@see KeyguardBouncer#show(boolean, boolean)}
*/
public void showBouncer(boolean scrimmed) {
- if (canShowAlternateBouncer()) {
- updateAlternateBouncerShowing(mAlternateBouncer.showAlternateBouncer());
- return;
+ if (!mAlternateBouncerInteractor.show()) {
+ showPrimaryBouncer(scrimmed);
+ } else {
+ updateAlternateBouncerShowing(mAlternateBouncerInteractor.isVisibleState());
}
-
- showPrimaryBouncer(scrimmed);
- }
-
- /** Whether we can show the alternate bouncer instead of the primary bouncer. */
- public boolean canShowAlternateBouncer() {
- return mAlternateBouncer != null
- && mKeyguardUpdateManager.isUnlockingWithBiometricAllowed(true);
}
/**
@@ -639,9 +666,9 @@
mKeyguardGoneCancelAction = cancelAction;
mDismissActionWillAnimateOnKeyguard = r != null && r.willRunAnimationOnKeyguard();
- // If there is an an alternate auth interceptor (like the UDFPS), show that one
+ // If there is an alternate auth interceptor (like the UDFPS), show that one
// instead of the bouncer.
- if (canShowAlternateBouncer()) {
+ if (mAlternateBouncerInteractor.canShowAlternateBouncerForFingerprint()) {
if (!afterKeyguardGone) {
if (mPrimaryBouncer != null) {
mPrimaryBouncer.setDismissAction(mAfterKeyguardGoneAction,
@@ -654,7 +681,7 @@
mKeyguardGoneCancelAction = null;
}
- updateAlternateBouncerShowing(mAlternateBouncer.showAlternateBouncer());
+ updateAlternateBouncerShowing(mAlternateBouncerInteractor.show());
return;
}
@@ -723,10 +750,7 @@
@Override
public void hideAlternateBouncer(boolean forceUpdateScrim) {
- final boolean updateScrim = (mAlternateBouncer != null
- && mAlternateBouncer.hideAlternateBouncer())
- || forceUpdateScrim;
- updateAlternateBouncerShowing(updateScrim);
+ updateAlternateBouncerShowing(mAlternateBouncerInteractor.hide() || forceUpdateScrim);
}
private void updateAlternateBouncerShowing(boolean updateScrim) {
@@ -736,7 +760,7 @@
return;
}
- final boolean isShowingAlternateBouncer = isShowingAlternateBouncer();
+ final boolean isShowingAlternateBouncer = mAlternateBouncerInteractor.isVisibleState();
if (mKeyguardMessageAreaController != null) {
mKeyguardMessageAreaController.setIsVisible(isShowingAlternateBouncer);
mKeyguardMessageAreaController.setMessage("");
@@ -1090,7 +1114,7 @@
@Override
public boolean isBouncerShowing() {
- return primaryBouncerIsShowing() || isShowingAlternateBouncer();
+ return primaryBouncerIsShowing() || mAlternateBouncerInteractor.isVisibleState();
}
@Override
@@ -1334,7 +1358,7 @@
mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
}
- if (mAlternateBouncer != null && isShowingAlternateBouncer()) {
+ if (mAlternateBouncerInteractor.isVisibleState()) {
hideAlternateBouncer(false);
executeAfterKeyguardGoneAction();
}
@@ -1342,7 +1366,7 @@
/** Display security message to relevant KeyguardMessageArea. */
public void setKeyguardMessage(String message, ColorStateList colorState) {
- if (isShowingAlternateBouncer()) {
+ if (mAlternateBouncerInteractor.isVisibleState()) {
if (mKeyguardMessageAreaController != null) {
mKeyguardMessageAreaController.setMessage(message);
}
@@ -1416,6 +1440,7 @@
public void dump(PrintWriter pw) {
pw.println("StatusBarKeyguardViewManager:");
+ pw.println(" mIsModernAlternateBouncerEnabled: " + mIsModernAlternateBouncerEnabled);
pw.println(" mRemoteInputActive: " + mRemoteInputActive);
pw.println(" mDozing: " + mDozing);
pw.println(" mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction);
@@ -1433,9 +1458,9 @@
mPrimaryBouncer.dump(pw);
}
- if (mAlternateBouncer != null) {
- pw.println("AlternateBouncer:");
- mAlternateBouncer.dump(pw);
+ if (mOccludingAppBiometricUI != null) {
+ pw.println("mOccludingAppBiometricUI:");
+ mOccludingAppBiometricUI.dump(pw);
}
}
@@ -1487,14 +1512,17 @@
return mPrimaryBouncer;
}
- public boolean isShowingAlternateBouncer() {
- return mAlternateBouncer != null && mAlternateBouncer.isShowingAlternateBouncer();
- }
-
/**
- * Forward touches to callbacks.
+ * For any touches on the NPVC, show the primary bouncer if the alternate bouncer is currently
+ * showing.
*/
public void onTouch(MotionEvent event) {
+ if (mAlternateBouncerInteractor.isVisibleState()
+ && mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()) {
+ showPrimaryBouncer(true);
+ }
+
+ // Forward NPVC touches to callbacks in case they want to respond to touches
for (KeyguardViewManagerCallback callback: mCallbacks) {
callback.onTouch(event);
}
@@ -1537,8 +1565,8 @@
*/
public void requestFp(boolean request, int udfpsColor) {
mKeyguardUpdateManager.requestFingerprintAuthOnOccludingApp(request);
- if (mAlternateBouncer != null) {
- mAlternateBouncer.requestUdfps(request, udfpsColor);
+ if (mOccludingAppBiometricUI != null) {
+ mOccludingAppBiometricUI.requestUdfps(request, udfpsColor);
}
}
@@ -1609,10 +1637,9 @@
}
/**
- * Delegate used to send show and hide events to an alternate authentication method instead of
- * the regular pin/pattern/password bouncer.
+ * @Deprecated Delegate used to send show and hide events to an alternate bouncer.
*/
- public interface AlternateBouncer {
+ public interface LegacyAlternateBouncer {
/**
* Show alternate authentication bouncer.
* @return whether alternate auth method was newly shown
@@ -1629,7 +1656,13 @@
* @return true if the alternate auth bouncer is showing
*/
boolean isShowingAlternateBouncer();
+ }
+ /**
+ * Delegate used to send show and hide events to an alternate authentication method instead of
+ * the regular pin/pattern/password bouncer.
+ */
+ public interface OccludingAppBiometricUI {
/**
* Use when an app occluding the keyguard would like to give the user ability to
* unlock the device using udfps.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 40b2cdf..30dc9c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -812,7 +812,7 @@
public void testForwardsDozeEvents() throws RemoteException {
when(mStatusBarStateController.isDozing()).thenReturn(true);
when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
- mAuthController.setBiometicContextListener(mContextListener);
+ mAuthController.setBiometricContextListener(mContextListener);
mStatusBarStateListenerCaptor.getValue().onDozingChanged(true);
mStatusBarStateListenerCaptor.getValue().onDozingChanged(false);
@@ -827,7 +827,7 @@
public void testForwardsWakeEvents() throws RemoteException {
when(mStatusBarStateController.isDozing()).thenReturn(false);
when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
- mAuthController.setBiometicContextListener(mContextListener);
+ mAuthController.setBiometricContextListener(mContextListener);
mWakefullnessObserverCaptor.getValue().onStartedGoingToSleep();
mWakefullnessObserverCaptor.getValue().onFinishedGoingToSleep();
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 4b459c0..c6fa983 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -43,6 +43,7 @@
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.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionStateManager
@@ -52,7 +53,6 @@
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 com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
@@ -95,7 +95,6 @@
@Mock private lateinit var dumpManager: DumpManager
@Mock private lateinit var transitionController: LockscreenShadeTransitionController
@Mock private lateinit var configurationController: ConfigurationController
- @Mock private lateinit var systemClock: SystemClock
@Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var unlockedScreenOffAnimationController:
UnlockedScreenOffAnimationController
@@ -106,7 +105,8 @@
@Mock private lateinit var udfpsEnrollView: UdfpsEnrollView
@Mock private lateinit var activityLaunchAnimator: ActivityLaunchAnimator
@Mock private lateinit var featureFlags: FeatureFlags
- @Mock private lateinit var mPrimaryBouncerInteractor: PrimaryBouncerInteractor
+ @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ @Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
@@ -138,10 +138,10 @@
context, fingerprintManager, inflater, windowManager, accessibilityManager,
statusBarStateController, shadeExpansionStateManager, statusBarKeyguardViewManager,
keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
- configurationController, systemClock, keyguardStateController,
+ configurationController, keyguardStateController,
unlockedScreenOffAnimationController, udfpsDisplayMode, REQUEST_ID, reason,
controllerCallback, onTouch, activityLaunchAnimator, featureFlags,
- mPrimaryBouncerInteractor, isDebuggable
+ primaryBouncerInteractor, alternateBouncerInteractor, 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 b267a5c..3907335 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -78,6 +78,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -197,6 +198,8 @@
private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@Mock
private SinglePointerTouchProcessor mSinglePointerTouchProcessor;
+ @Mock
+ private AlternateBouncerInteractor mAlternateBouncerInteractor;
// Capture listeners so that they can be used to send events
@Captor
@@ -282,7 +285,8 @@
mDisplayManager, mHandler, mConfigurationController, mSystemClock,
mUnlockedScreenOffAnimationController, mSystemUIDialogManager, mLatencyTracker,
mActivityLaunchAnimator, alternateTouchProvider, mBiometricsExecutor,
- mPrimaryBouncerInteractor, mSinglePointerTouchProcessor);
+ mPrimaryBouncerInteractor, mSinglePointerTouchProcessor,
+ mAlternateBouncerInteractor);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -396,7 +400,7 @@
// GIVEN overlay was showing and the udfps bouncer is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
- when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(true);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
// WHEN the overlay is hidden
mOverlayController.hideUdfpsOverlay(mOpticalProps.sensorId);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java
index 3c61382..9c32c38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java
@@ -30,6 +30,7 @@
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.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
@@ -43,7 +44,6 @@
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;
@@ -73,9 +73,9 @@
protected @Mock ActivityLaunchAnimator mActivityLaunchAnimator;
protected @Mock KeyguardBouncer mBouncer;
protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+ protected @Mock AlternateBouncerInteractor mAlternateBouncerInteractor;
protected FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
- protected FakeSystemClock mSystemClock = new FakeSystemClock();
protected UdfpsKeyguardViewController mController;
@@ -86,10 +86,6 @@
private @Captor ArgumentCaptor<ShadeExpansionListener> mExpansionListenerCaptor;
protected List<ShadeExpansionListener> mExpansionListeners;
- private @Captor ArgumentCaptor<StatusBarKeyguardViewManager.AlternateBouncer>
- mAlternateBouncerCaptor;
- protected StatusBarKeyguardViewManager.AlternateBouncer mAlternateBouncer;
-
private @Captor ArgumentCaptor<KeyguardStateController.Callback>
mKeyguardStateControllerCallbackCaptor;
protected KeyguardStateController.Callback mKeyguardStateControllerCallback;
@@ -135,12 +131,6 @@
}
}
- protected void captureAltAuthInterceptor() {
- verify(mStatusBarKeyguardViewManager).setAlternateBouncer(
- mAlternateBouncerCaptor.capture());
- mAlternateBouncer = mAlternateBouncerCaptor.getValue();
- }
-
protected void captureKeyguardStateControllerCallback() {
verify(mKeyguardStateController).addCallback(
mKeyguardStateControllerCallbackCaptor.capture());
@@ -160,6 +150,7 @@
protected UdfpsKeyguardViewController createUdfpsKeyguardViewController(
boolean useModernBouncer, boolean useExpandedOverlay) {
mFeatureFlags.set(Flags.MODERN_BOUNCER, useModernBouncer);
+ mFeatureFlags.set(Flags.MODERN_ALTERNATE_BOUNCER, useModernBouncer);
mFeatureFlags.set(Flags.UDFPS_NEW_TOUCH_DETECTION, useExpandedOverlay);
when(mStatusBarKeyguardViewManager.getPrimaryBouncer()).thenReturn(
useModernBouncer ? null : mBouncer);
@@ -172,14 +163,14 @@
mDumpManager,
mLockscreenShadeTransitionController,
mConfigurationController,
- mSystemClock,
mKeyguardStateController,
mUnlockedScreenOffAnimationController,
mDialogManager,
mUdfpsController,
mActivityLaunchAnimator,
mFeatureFlags,
- mPrimaryBouncerInteractor);
+ mPrimaryBouncerInteractor,
+ mAlternateBouncerInteractor);
return controller;
}
}
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 babe533..813eeeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -19,18 +19,15 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeast;
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.verify;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
+import android.testing.TestableLooper;
import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
@@ -46,7 +43,8 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest {
private @Captor ArgumentCaptor<KeyguardBouncer.PrimaryBouncerExpansionCallback>
mBouncerExpansionCallbackCaptor;
@@ -72,8 +70,6 @@
assertTrue(mController.shouldPauseAuth());
}
-
-
@Test
public void testRegistersExpansionChangedListenerOnAttached() {
mController.onViewAttached();
@@ -237,85 +233,9 @@
public void testOverrideShouldPauseAuthOnShadeLocked() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureAltAuthInterceptor();
sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED);
assertTrue(mController.shouldPauseAuth());
-
- mAlternateBouncer.showAlternateBouncer(); // force show
- assertFalse(mController.shouldPauseAuth());
- assertTrue(mAlternateBouncer.isShowingAlternateBouncer());
-
- mAlternateBouncer.hideAlternateBouncer(); // stop force show
- assertTrue(mController.shouldPauseAuth());
- assertFalse(mAlternateBouncer.isShowingAlternateBouncer());
- }
-
- @Test
- public void testOnDetachedStateReset() {
- // GIVEN view is attached
- mController.onViewAttached();
- captureAltAuthInterceptor();
-
- // WHEN view is detached
- mController.onViewDetached();
-
- // THEN remove alternate auth interceptor
- verify(mStatusBarKeyguardViewManager).removeAlternateAuthInterceptor(mAlternateBouncer);
- }
-
- @Test
- public void testHiddenUdfpsBouncerOnTouchOutside_nothingHappens() {
- // GIVEN view is attached
- mController.onViewAttached();
- captureAltAuthInterceptor();
-
- // GIVEN udfps bouncer isn't showing
- mAlternateBouncer.hideAlternateBouncer();
-
- // WHEN touch is observed outside the view
- mController.onTouchOutsideView();
-
- // THEN bouncer / alt auth methods are never called
- verify(mStatusBarKeyguardViewManager, never()).showPrimaryBouncer(anyBoolean());
- verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
- verify(mStatusBarKeyguardViewManager, never()).hideAlternateBouncer(anyBoolean());
- }
-
- @Test
- public void testShowingUdfpsBouncerOnTouchOutsideWithinThreshold_nothingHappens() {
- // GIVEN view is attached
- mController.onViewAttached();
- captureAltAuthInterceptor();
-
- // GIVEN udfps bouncer is showing
- mAlternateBouncer.showAlternateBouncer();
-
- // WHEN touch is observed outside the view 200ms later (just within threshold)
- mSystemClock.advanceTime(200);
- mController.onTouchOutsideView();
-
- // THEN bouncer / alt auth methods are never called because not enough time has passed
- verify(mStatusBarKeyguardViewManager, never()).showPrimaryBouncer(anyBoolean());
- verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
- verify(mStatusBarKeyguardViewManager, never()).hideAlternateBouncer(anyBoolean());
- }
-
- @Test
- public void testShowingUdfpsBouncerOnTouchOutsideAboveThreshold_showPrimaryBouncer() {
- // GIVEN view is attached
- mController.onViewAttached();
- captureAltAuthInterceptor();
-
- // GIVEN udfps bouncer is showing
- mAlternateBouncer.showAlternateBouncer();
-
- // WHEN touch is observed outside the view 205ms later
- mSystemClock.advanceTime(205);
- mController.onTouchOutsideView();
-
- // THEN show the bouncer
- verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(eq(true));
}
@Test
@@ -334,25 +254,6 @@
}
@Test
- public void testShowUdfpsBouncer() {
- // GIVEN view is attached and status bar expansion is 0
- mController.onViewAttached();
- captureStatusBarExpansionListeners();
- captureKeyguardStateControllerCallback();
- captureAltAuthInterceptor();
- updateStatusBarExpansion(0, true);
- reset(mView);
- when(mView.getContext()).thenReturn(mResourceContext);
- when(mResourceContext.getString(anyInt())).thenReturn("test string");
-
- // WHEN status bar expansion is 0 but udfps bouncer is requested
- mAlternateBouncer.showAlternateBouncer();
-
- // THEN alpha is 255
- verify(mView).setUnpausedAlpha(255);
- }
-
- @Test
public void testTransitionToFullShadeProgress() {
// GIVEN view is attached and status bar expansion is 1f
mController.onViewAttached();
@@ -370,24 +271,6 @@
}
@Test
- public void testShowUdfpsBouncer_transitionToFullShadeProgress() {
- // GIVEN view is attached and status bar expansion is 1f
- mController.onViewAttached();
- captureStatusBarExpansionListeners();
- captureKeyguardStateControllerCallback();
- captureAltAuthInterceptor();
- updateStatusBarExpansion(1f, true);
- mAlternateBouncer.showAlternateBouncer();
- reset(mView);
-
- // WHEN we're transitioning to the full shade
- mController.setTransitionToFullShadeProgress(1.0f);
-
- // THEN alpha is 255 (b/c udfps bouncer is requested)
- verify(mView).setUnpausedAlpha(255);
- }
-
- @Test
public void testUpdatePanelExpansion_pauseAuth() {
// GIVEN view is attached + on the keyguard
mController.onViewAttached();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index 517e27a..c8c4290 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -21,23 +21,32 @@
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.BouncerView
+import com.android.systemui.keyguard.data.repository.BiometricRepository
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.KeyguardBouncer
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.time.SystemClock
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.yield
+import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -53,7 +62,7 @@
keyguardBouncerRepository =
KeyguardBouncerRepository(
mock(com.android.keyguard.ViewMediatorCallback::class.java),
- mKeyguardUpdateMonitor
+ FakeSystemClock()
)
super.setUp()
}
@@ -72,15 +81,43 @@
mock(KeyguardBypassController::class.java),
mKeyguardUpdateMonitor
)
+ mAlternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ keyguardBouncerRepository,
+ mock(BiometricRepository::class.java),
+ mock(SystemClock::class.java),
+ mock(KeyguardUpdateMonitor::class.java),
+ mock(FeatureFlags::class.java)
+ )
return createUdfpsKeyguardViewController(
/* useModernBouncer */ true, /* useExpandedOverlay */
false
)
}
- /** After migration, replaces LockIconViewControllerTest version */
@Test
- fun testShouldPauseAuthBouncerShowing() =
+ fun shadeLocked_showAlternateBouncer_unpauseAuth() =
+ runBlocking(IMMEDIATE) {
+ // GIVEN view is attached + on the SHADE_LOCKED (udfps view not showing)
+ mController.onViewAttached()
+ captureStatusBarStateListeners()
+ sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED)
+
+ // WHEN alternate bouncer is requested
+ val job = mController.listenForAlternateBouncerVisibility(this)
+ keyguardBouncerRepository.setAlternateVisible(true)
+ yield()
+
+ // THEN udfps view will animate in & pause auth is updated to NOT pause
+ verify(mView).animateInUdfpsBouncer(any())
+ assertFalse(mController.shouldPauseAuth())
+
+ job.cancel()
+ }
+
+ /** After migration to MODERN_BOUNCER, replaces UdfpsKeyguardViewControllerTest version */
+ @Test
+ fun shouldPauseAuthBouncerShowing() =
runBlocking(IMMEDIATE) {
// GIVEN view attached and we're on the keyguard
mController.onViewAttached()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
index ac936e1..44fa4eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
@@ -80,15 +80,6 @@
}
@Test
- fun forwardsEvents() {
- view.dozeTimeTick()
- verify(animationViewController).dozeTimeTick()
-
- view.onTouchOutsideView()
- verify(animationViewController).onTouchOutsideView()
- }
-
- @Test
fun layoutSizeFitsSensor() {
val params = withArgCaptor<RectF> {
verify(animationViewController).onSensorRectUpdated(capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricRepositoryTest.kt
new file mode 100644
index 0000000..a92dd3b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricRepositoryTest.kt
@@ -0,0 +1,176 @@
+/*
+ * 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.keyguard.data.repository
+
+import android.app.admin.DevicePolicyManager
+import android.content.Intent
+import android.content.pm.UserInfo
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.widget.LockPatternUtils
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.AuthController
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidTestingRunner::class)
+class BiometricRepositoryTest : SysuiTestCase() {
+ private lateinit var underTest: BiometricRepository
+
+ @Mock private lateinit var authController: AuthController
+ @Mock private lateinit var lockPatternUtils: LockPatternUtils
+ @Mock private lateinit var devicePolicyManager: DevicePolicyManager
+ private lateinit var userRepository: FakeUserRepository
+
+ private lateinit var testDispatcher: TestDispatcher
+ private lateinit var testScope: TestScope
+ private var testableLooper: TestableLooper? = null
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+ testDispatcher = StandardTestDispatcher()
+ testScope = TestScope(testDispatcher)
+ userRepository = FakeUserRepository()
+ }
+
+ private suspend fun createBiometricRepository() {
+ userRepository.setUserInfos(listOf(PRIMARY_USER))
+ userRepository.setSelectedUserInfo(PRIMARY_USER)
+ underTest =
+ BiometricRepositoryImpl(
+ context = context,
+ lockPatternUtils = lockPatternUtils,
+ broadcastDispatcher = fakeBroadcastDispatcher,
+ authController = authController,
+ userRepository = userRepository,
+ devicePolicyManager = devicePolicyManager,
+ scope = testScope.backgroundScope,
+ backgroundDispatcher = testDispatcher,
+ looper = testableLooper!!.looper,
+ )
+ }
+
+ @Test
+ fun fingerprintEnrollmentChange() =
+ testScope.runTest {
+ createBiometricRepository()
+ val fingerprintEnabledByDevicePolicy = collectLastValue(underTest.isFingerprintEnrolled)
+ runCurrent()
+
+ val captor = argumentCaptor<AuthController.Callback>()
+ verify(authController).addCallback(captor.capture())
+ whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(true)
+ captor.value.onEnrollmentsChanged(
+ BiometricType.UNDER_DISPLAY_FINGERPRINT,
+ PRIMARY_USER_ID,
+ true
+ )
+ assertThat(fingerprintEnabledByDevicePolicy()).isTrue()
+
+ whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(false)
+ captor.value.onEnrollmentsChanged(
+ BiometricType.UNDER_DISPLAY_FINGERPRINT,
+ PRIMARY_USER_ID,
+ false
+ )
+ assertThat(fingerprintEnabledByDevicePolicy()).isFalse()
+ }
+
+ @Test
+ fun strongBiometricAllowedChange() =
+ testScope.runTest {
+ createBiometricRepository()
+ val strongBiometricAllowed = collectLastValue(underTest.isStrongBiometricAllowed)
+ runCurrent()
+
+ val captor = argumentCaptor<LockPatternUtils.StrongAuthTracker>()
+ verify(lockPatternUtils).registerStrongAuthTracker(captor.capture())
+
+ captor.value
+ .getStub()
+ .onStrongAuthRequiredChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
+ testableLooper?.processAllMessages() // StrongAuthTracker uses the TestableLooper
+ assertThat(strongBiometricAllowed()).isTrue()
+
+ captor.value
+ .getStub()
+ .onStrongAuthRequiredChanged(STRONG_AUTH_REQUIRED_AFTER_BOOT, PRIMARY_USER_ID)
+ testableLooper?.processAllMessages() // StrongAuthTracker uses the TestableLooper
+ assertThat(strongBiometricAllowed()).isFalse()
+ }
+
+ @Test
+ fun fingerprintDisabledByDpmChange() =
+ testScope.runTest {
+ createBiometricRepository()
+ val fingerprintEnabledByDevicePolicy =
+ collectLastValue(underTest.isFingerprintEnabledByDevicePolicy)
+ runCurrent()
+
+ whenever(devicePolicyManager.getKeyguardDisabledFeatures(any(), anyInt()))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT)
+ broadcastDPMStateChange()
+ assertThat(fingerprintEnabledByDevicePolicy()).isFalse()
+
+ whenever(devicePolicyManager.getKeyguardDisabledFeatures(any(), anyInt())).thenReturn(0)
+ broadcastDPMStateChange()
+ assertThat(fingerprintEnabledByDevicePolicy()).isTrue()
+ }
+
+ private fun broadcastDPMStateChange() {
+ fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
+ receiver.onReceive(
+ context,
+ Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED)
+ )
+ }
+ }
+
+ companion object {
+ private const val PRIMARY_USER_ID = 0
+ private val PRIMARY_USER =
+ UserInfo(
+ /* id= */ PRIMARY_USER_ID,
+ /* name= */ "primary user",
+ /* flags= */ UserInfo.FLAG_PRIMARY
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
new file mode 100644
index 0000000..ba302a2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -0,0 +1,146 @@
+/*
+ * 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.keyguard.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.ViewMediatorCallback
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeBiometricRepository
+import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
+import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.time.SystemClock
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class AlternateBouncerInteractorTest : SysuiTestCase() {
+ private lateinit var underTest: AlternateBouncerInteractor
+ private lateinit var bouncerRepository: KeyguardBouncerRepository
+ private lateinit var biometricRepository: FakeBiometricRepository
+ @Mock private lateinit var systemClock: SystemClock
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ private lateinit var featureFlags: FakeFeatureFlags
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ bouncerRepository =
+ KeyguardBouncerRepository(mock(ViewMediatorCallback::class.java), FakeSystemClock())
+ biometricRepository = FakeBiometricRepository()
+ featureFlags = FakeFeatureFlags().apply { this.set(Flags.MODERN_ALTERNATE_BOUNCER, true) }
+ underTest =
+ AlternateBouncerInteractor(
+ bouncerRepository,
+ biometricRepository,
+ systemClock,
+ keyguardUpdateMonitor,
+ featureFlags,
+ )
+ }
+
+ @Test
+ fun canShowAlternateBouncerForFingerprint_givenCanShow() {
+ givenCanShowAlternateBouncer()
+ assertTrue(underTest.canShowAlternateBouncerForFingerprint())
+ }
+
+ @Test
+ fun canShowAlternateBouncerForFingerprint_alternateBouncerUIUnavailable() {
+ givenCanShowAlternateBouncer()
+ bouncerRepository.setAlternateBouncerUIAvailable(false)
+
+ assertFalse(underTest.canShowAlternateBouncerForFingerprint())
+ }
+
+ @Test
+ fun canShowAlternateBouncerForFingerprint_noFingerprintsEnrolled() {
+ givenCanShowAlternateBouncer()
+ biometricRepository.setFingerprintEnrolled(false)
+
+ assertFalse(underTest.canShowAlternateBouncerForFingerprint())
+ }
+
+ @Test
+ fun canShowAlternateBouncerForFingerprint_strongBiometricNotAllowed() {
+ givenCanShowAlternateBouncer()
+ biometricRepository.setStrongBiometricAllowed(false)
+
+ assertFalse(underTest.canShowAlternateBouncerForFingerprint())
+ }
+
+ @Test
+ fun canShowAlternateBouncerForFingerprint_devicePolicyDoesNotAllowFingerprint() {
+ givenCanShowAlternateBouncer()
+ biometricRepository.setFingerprintEnabledByDevicePolicy(false)
+
+ assertFalse(underTest.canShowAlternateBouncerForFingerprint())
+ }
+
+ @Test
+ fun show_whenCanShow() {
+ givenCanShowAlternateBouncer()
+
+ assertTrue(underTest.show())
+ assertTrue(bouncerRepository.isAlternateBouncerVisible.value)
+ }
+
+ @Test
+ fun show_whenCannotShow() {
+ givenCannotShowAlternateBouncer()
+
+ assertFalse(underTest.show())
+ assertFalse(bouncerRepository.isAlternateBouncerVisible.value)
+ }
+
+ @Test
+ fun hide_wasPreviouslyShowing() {
+ bouncerRepository.setAlternateVisible(true)
+
+ assertTrue(underTest.hide())
+ assertFalse(bouncerRepository.isAlternateBouncerVisible.value)
+ }
+
+ @Test
+ fun hide_wasNotPreviouslyShowing() {
+ bouncerRepository.setAlternateVisible(false)
+
+ assertFalse(underTest.hide())
+ assertFalse(bouncerRepository.isAlternateBouncerVisible.value)
+ }
+
+ private fun givenCanShowAlternateBouncer() {
+ bouncerRepository.setAlternateBouncerUIAvailable(true)
+ biometricRepository.setFingerprintEnrolled(true)
+ biometricRepository.setStrongBiometricAllowed(true)
+ biometricRepository.setFingerprintEnabledByDevicePolicy(true)
+ }
+
+ private fun givenCannotShowAlternateBouncer() {
+ biometricRepository.setFingerprintEnrolled(false)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 56a840c..3244da1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -103,6 +103,7 @@
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
@@ -284,6 +285,7 @@
@Mock private ViewTreeObserver mViewTreeObserver;
@Mock private KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
@Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
+ @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private MotionEvent mDownMotionEvent;
@Captor
private ArgumentCaptor<NotificationStackScrollLayout.OnEmptySpaceClickListener>
@@ -499,6 +501,7 @@
systemClock,
mKeyguardBottomAreaViewModel,
mKeyguardBottomAreaInteractor,
+ mAlternateBouncerInteractor,
mDumpManager);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index c3207c2..3137aa5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -30,6 +30,7 @@
import com.android.systemui.dock.DockManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -97,6 +98,8 @@
private lateinit var pulsingGestureListener: PulsingGestureListener
@Mock
private lateinit var notificationInsetsController: NotificationInsetsController
+ @Mock
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerContainer: ViewGroup
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@@ -132,7 +135,8 @@
pulsingGestureListener,
featureFlags,
keyguardBouncerViewModel,
- keyguardBouncerComponentFactory
+ keyguardBouncerComponentFactory,
+ alternateBouncerInteractor
)
underTest.setupExpandedStatusBar()
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 4bf00c4..544b00e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
@@ -40,6 +40,7 @@
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -93,6 +94,7 @@
@Mock private KeyguardBouncerViewModel mKeyguardBouncerViewModel;
@Mock private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock private NotificationInsetsController mNotificationInsetsController;
+ @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
mInteractionEventHandlerCaptor;
@@ -132,7 +134,8 @@
mPulsingGestureListener,
mFeatureFlags,
mKeyguardBouncerViewModel,
- mKeyguardBouncerComponentFactory
+ mKeyguardBouncerComponentFactory,
+ mAlternateBouncerInteractor
);
mController.setupExpandedStatusBar();
mController.setDragDownHelper(mDragDownHelper);
@@ -155,7 +158,7 @@
// WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
when(mStatusBarStateController.isDozing()).thenReturn(false);
- when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(true);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
// THEN we should intercept touch
@@ -168,7 +171,7 @@
// WHEN not showing alt auth, not dozing, drag down helper doesn't want to intercept
when(mStatusBarStateController.isDozing()).thenReturn(false);
- when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(false);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
// THEN we shouldn't intercept touch
@@ -181,7 +184,7 @@
// WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
when(mStatusBarStateController.isDozing()).thenReturn(false);
- when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(true);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
// THEN we should handle the touch
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index c8a392b..5ed7282 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -99,6 +99,7 @@
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -177,6 +178,8 @@
@Mock
private FaceHelpMessageDeferral mFaceHelpMessageDeferral;
@Mock
+ private AlternateBouncerInteractor mAlternateBouncerInteractor;
+ @Mock
private ScreenLifecycle mScreenLifecycle;
@Mock
private AuthController mAuthController;
@@ -273,7 +276,8 @@
mUserManager, mExecutor, mExecutor, mFalsingManager,
mAuthController, mLockPatternUtils, mScreenLifecycle,
mKeyguardBypassController, mAccessibilityManager,
- mFaceHelpMessageDeferral, mock(KeyguardLogger.class));
+ mFaceHelpMessageDeferral, mock(KeyguardLogger.class),
+ mAlternateBouncerInteractor);
mController.init();
mController.setIndicationArea(mIndicationArea);
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 521e518..1503392 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -106,6 +106,7 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
@@ -293,6 +294,7 @@
@Mock private WiredChargingRippleController mWiredChargingRippleController;
@Mock private Lazy<CameraLauncher> mCameraLauncherLazy;
@Mock private CameraLauncher mCameraLauncher;
+ @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
/**
* The process of registering/unregistering a predictive back callback requires a
* ViewRootImpl, which is present IRL, but may be missing during a Mockito unit test.
@@ -500,7 +502,9 @@
mWiredChargingRippleController,
mDreamManager,
mCameraLauncherLazy,
- () -> mLightRevealScrimViewModel) {
+ () -> mLightRevealScrimViewModel,
+ mAlternateBouncerInteractor
+ ) {
@Override
protected ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 14a319b..04a6700 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -56,6 +56,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.data.BouncerView;
import com.android.systemui.keyguard.data.BouncerViewDelegate;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -105,7 +106,6 @@
@Mock private KeyguardBouncer.Factory mKeyguardBouncerFactory;
@Mock private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
@Mock private KeyguardMessageAreaController mKeyguardMessageAreaController;
- @Mock private StatusBarKeyguardViewManager.AlternateBouncer mAlternateBouncer;
@Mock private KeyguardMessageArea mKeyguardMessageArea;
@Mock private ShadeController mShadeController;
@Mock private SysUIUnfoldComponent mSysUiUnfoldComponent;
@@ -115,6 +115,7 @@
@Mock private KeyguardSecurityModel mKeyguardSecurityModel;
@Mock private PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
@Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+ @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private BouncerView mBouncerView;
@Mock private BouncerViewDelegate mBouncerViewDelegate;
@@ -163,7 +164,8 @@
mFeatureFlags,
mPrimaryBouncerCallbackInteractor,
mPrimaryBouncerInteractor,
- mBouncerView) {
+ mBouncerView,
+ mAlternateBouncerInteractor) {
@Override
public ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
@@ -434,37 +436,35 @@
@Test
public void testShowing_whenAlternateAuthShowing() {
- mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer);
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(false);
- when(mAlternateBouncer.isShowingAlternateBouncer()).thenReturn(true);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
assertTrue(
- "Is showing not accurate when alternative auth showing",
+ "Is showing not accurate when alternative bouncer is visible",
mStatusBarKeyguardViewManager.isBouncerShowing());
}
@Test
public void testWillBeShowing_whenAlternateAuthShowing() {
- mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer);
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(false);
- when(mAlternateBouncer.isShowingAlternateBouncer()).thenReturn(true);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
assertTrue(
- "Is or will be showing not accurate when alternative auth showing",
+ "Is or will be showing not accurate when alternate bouncer is visible",
mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing());
}
@Test
- public void testHideAlternateBouncer_onShowBouncer() {
- // GIVEN alt auth is showing
- mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer);
+ public void testHideAlternateBouncer_onShowPrimaryBouncer() {
+ reset(mAlternateBouncerInteractor);
+
+ // GIVEN alt bouncer is showing
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(false);
- when(mAlternateBouncer.isShowingAlternateBouncer()).thenReturn(true);
- reset(mAlternateBouncer);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
// WHEN showBouncer is called
mStatusBarKeyguardViewManager.showPrimaryBouncer(true);
// THEN alt bouncer should be hidden
- verify(mAlternateBouncer).hideAlternateBouncer();
+ verify(mAlternateBouncerInteractor).hide();
}
@Test
@@ -479,11 +479,9 @@
@Test
public void testShowAltAuth_unlockingWithBiometricNotAllowed() {
- // GIVEN alt auth exists, unlocking with biometric isn't allowed
- mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer);
+ // GIVEN cannot use alternate bouncer
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(false);
- when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean()))
- .thenReturn(false);
+ when(mAlternateBouncerInteractor.canShowAlternateBouncerForFingerprint()).thenReturn(false);
// WHEN showGenericBouncer is called
final boolean scrimmed = true;
@@ -491,21 +489,19 @@
// THEN regular bouncer is shown
verify(mPrimaryBouncerInteractor).show(eq(scrimmed));
- verify(mAlternateBouncer, never()).showAlternateBouncer();
}
@Test
public void testShowAlternateBouncer_unlockingWithBiometricAllowed() {
- // GIVEN alt auth exists, unlocking with biometric is allowed
- mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer);
+ // GIVEN will show alternate bouncer
when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(false);
- when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+ when(mAlternateBouncerInteractor.show()).thenReturn(true);
// WHEN showGenericBouncer is called
mStatusBarKeyguardViewManager.showBouncer(true);
// THEN alt auth bouncer is shown
- verify(mAlternateBouncer).showAlternateBouncer();
+ verify(mAlternateBouncerInteractor).show();
verify(mPrimaryBouncerInteractor, never()).show(anyBoolean());
}
@@ -613,7 +609,8 @@
mFeatureFlags,
mPrimaryBouncerCallbackInteractor,
mPrimaryBouncerInteractor,
- mBouncerView) {
+ mBouncerView,
+ mAlternateBouncerInteractor) {
@Override
public ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
index 96fba39..a9c55fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
@@ -56,6 +56,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.data.BouncerView;
import com.android.systemui.keyguard.data.BouncerViewDelegate;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -109,7 +110,6 @@
@Mock private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
@Mock private KeyguardMessageAreaController mKeyguardMessageAreaController;
@Mock private KeyguardBouncer mPrimaryBouncer;
- @Mock private StatusBarKeyguardViewManager.AlternateBouncer mAlternateBouncer;
@Mock private KeyguardMessageArea mKeyguardMessageArea;
@Mock private ShadeController mShadeController;
@Mock private SysUIUnfoldComponent mSysUiUnfoldComponent;
@@ -119,6 +119,7 @@
@Mock private KeyguardSecurityModel mKeyguardSecurityModel;
@Mock private PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
@Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+ @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private BouncerView mBouncerView;
@Mock private BouncerViewDelegate mBouncerViewDelegate;
@@ -169,7 +170,8 @@
mFeatureFlags,
mPrimaryBouncerCallbackInteractor,
mPrimaryBouncerInteractor,
- mBouncerView) {
+ mBouncerView,
+ mAlternateBouncerInteractor) {
@Override
public ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
@@ -439,41 +441,6 @@
}
@Test
- public void testShowing_whenAlternateAuthShowing() {
- mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer);
- when(mPrimaryBouncer.isShowing()).thenReturn(false);
- when(mAlternateBouncer.isShowingAlternateBouncer()).thenReturn(true);
- assertTrue(
- "Is showing not accurate when alternative auth showing",
- mStatusBarKeyguardViewManager.isBouncerShowing());
- }
-
- @Test
- public void testWillBeShowing_whenAlternateAuthShowing() {
- mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer);
- when(mPrimaryBouncer.isShowing()).thenReturn(false);
- when(mAlternateBouncer.isShowingAlternateBouncer()).thenReturn(true);
- assertTrue(
- "Is or will be showing not accurate when alternative auth showing",
- mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing());
- }
-
- @Test
- public void testHideAlternateBouncer_onShowBouncer() {
- // GIVEN alt auth is showing
- mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer);
- when(mPrimaryBouncer.isShowing()).thenReturn(false);
- when(mAlternateBouncer.isShowingAlternateBouncer()).thenReturn(true);
- reset(mAlternateBouncer);
-
- // WHEN showBouncer is called
- mStatusBarKeyguardViewManager.showPrimaryBouncer(true);
-
- // THEN alt bouncer should be hidden
- verify(mAlternateBouncer).hideAlternateBouncer();
- }
-
- @Test
public void testBouncerIsOrWillBeShowing_whenBouncerIsInTransit() {
when(mPrimaryBouncer.isShowing()).thenReturn(false);
when(mPrimaryBouncer.inTransit()).thenReturn(true);
@@ -484,38 +451,6 @@
}
@Test
- public void testShowAltAuth_unlockingWithBiometricNotAllowed() {
- // GIVEN alt auth exists, unlocking with biometric isn't allowed
- mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer);
- when(mPrimaryBouncer.isShowing()).thenReturn(false);
- when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean()))
- .thenReturn(false);
-
- // WHEN showGenericBouncer is called
- final boolean scrimmed = true;
- mStatusBarKeyguardViewManager.showBouncer(scrimmed);
-
- // THEN regular bouncer is shown
- verify(mPrimaryBouncer).show(anyBoolean(), eq(scrimmed));
- verify(mAlternateBouncer, never()).showAlternateBouncer();
- }
-
- @Test
- public void testShowAlternateBouncer_unlockingWithBiometricAllowed() {
- // GIVEN alt auth exists, unlocking with biometric is allowed
- mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer);
- when(mPrimaryBouncer.isShowing()).thenReturn(false);
- when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
-
- // WHEN showGenericBouncer is called
- mStatusBarKeyguardViewManager.showBouncer(true);
-
- // THEN alt auth bouncer is shown
- verify(mAlternateBouncer).showAlternateBouncer();
- verify(mPrimaryBouncer, never()).show(anyBoolean(), anyBoolean());
- }
-
- @Test
public void testUpdateResources_delegatesToBouncer() {
mStatusBarKeyguardViewManager.updateResources();
@@ -628,7 +563,8 @@
mFeatureFlags,
mPrimaryBouncerCallbackInteractor,
mPrimaryBouncerInteractor,
- mBouncerView) {
+ mBouncerView,
+ mAlternateBouncerInteractor) {
@Override
public ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricRepository.kt
new file mode 100644
index 0000000..f3e52de
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricRepository.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.keyguard.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeBiometricRepository : BiometricRepository {
+
+ private val _isFingerprintEnrolled = MutableStateFlow<Boolean>(false)
+ override val isFingerprintEnrolled: StateFlow<Boolean> = _isFingerprintEnrolled.asStateFlow()
+
+ private val _isStrongBiometricAllowed = MutableStateFlow(false)
+ override val isStrongBiometricAllowed = _isStrongBiometricAllowed.asStateFlow()
+
+ private val _isFingerprintEnabledByDevicePolicy = MutableStateFlow(false)
+ override val isFingerprintEnabledByDevicePolicy =
+ _isFingerprintEnabledByDevicePolicy.asStateFlow()
+
+ fun setFingerprintEnrolled(isFingerprintEnrolled: Boolean) {
+ _isFingerprintEnrolled.value = isFingerprintEnrolled
+ }
+
+ fun setStrongBiometricAllowed(isStrongBiometricAllowed: Boolean) {
+ _isStrongBiometricAllowed.value = isStrongBiometricAllowed
+ }
+
+ fun setFingerprintEnabledByDevicePolicy(isFingerprintEnabledByDevicePolicy: Boolean) {
+ _isFingerprintEnabledByDevicePolicy.value = isFingerprintEnabledByDevicePolicy
+ }
+}