RESTRICT AUTOMERGE Modernize alternate bouncer logic am: 5b5fa66779
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20440222 Change-Id: I2ede77fde244fc2f375d8660ca9de4a8cd30e358 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -366,7 +366,7 @@ constructor(
|
||||
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())
|
||||
|
||||
@@ -715,6 +715,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
updateBiometricListeningState(BIOMETRIC_ACTION_STOP, FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.biometrics;
|
||||
|
||||
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;
|
||||
@@ -76,6 +77,7 @@ import com.android.systemui.dagger.qualifiers.Background;
|
||||
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;
|
||||
@@ -85,8 +87,10 @@ import com.android.systemui.util.concurrency.Execution;
|
||||
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;
|
||||
|
||||
@@ -150,6 +154,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
@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 mSfpsEnrolledForUser;
|
||||
@NonNull private final SensorPrivacyManager mSensorPrivacyManager;
|
||||
@@ -161,7 +166,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
private final @Background DelayableExecutor mBackgroundExecutor;
|
||||
private final DisplayInfo mCachedDisplayInfo = new DisplayInfo();
|
||||
|
||||
|
||||
private final VibratorHelper mVibratorHelper;
|
||||
|
||||
private void vibrateSuccess(int modality) {
|
||||
@@ -331,27 +335,35 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mSidefpsProps == null) {
|
||||
Log.d(TAG, "handleEnrollmentsChanged, mSidefpsProps is null");
|
||||
} else {
|
||||
for (FingerprintSensorPropertiesInternal prop : mSidefpsProps) {
|
||||
if (mFaceProps != null && sensorBiometricType == BiometricType.UNKNOWN) {
|
||||
for (FaceSensorPropertiesInternal prop : mFaceProps) {
|
||||
if (prop.sensorId == sensorId) {
|
||||
mSfpsEnrolledForUser.put(userId, hasEnrollments);
|
||||
sensorBiometricType = BiometricType.FACE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Callback cb : mCallbacks) {
|
||||
cb.onEnrollmentsChanged();
|
||||
cb.onEnrollmentsChanged(sensorBiometricType, userId, hasEnrollments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,6 +616,11 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
}
|
||||
}
|
||||
|
||||
/** 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.
|
||||
@@ -828,7 +845,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiometicContextListener(IBiometricContextListener listener) {
|
||||
public void setBiometricContextListener(IBiometricContextListener listener) {
|
||||
mBiometricContextListener = listener;
|
||||
notifyDozeChanged(mStatusBarStateController.isDozing(),
|
||||
mWakefulnessLifecycle.getWakefulness());
|
||||
@@ -1081,6 +1098,13 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
return mSfpsEnrolledForUser.get(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@@ -1262,6 +1286,16 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
*/
|
||||
default void onEnrollmentsChanged() {}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -189,11 +189,6 @@ abstract class UdfpsAnimationViewController<T : UdfpsAnimationView>(
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -73,6 +73,7 @@ import com.android.systemui.dump.DumpManager;
|
||||
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 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
||||
@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.
|
||||
@@ -232,12 +234,12 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
||||
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
|
||||
@@ -329,13 +331,13 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -543,9 +545,6 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
||||
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");
|
||||
@@ -719,7 +718,8 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
||||
@NonNull Optional<Provider<AlternateUdfpsTouchProvider>> alternateTouchProvider,
|
||||
@NonNull @BiometricsBackground Executor biometricsExecutor,
|
||||
@NonNull PrimaryBouncerInteractor primaryBouncerInteractor,
|
||||
@NonNull SinglePointerTouchProcessor singlePointerTouchProcessor) {
|
||||
@NonNull SinglePointerTouchProcessor singlePointerTouchProcessor,
|
||||
@NonNull AlternateBouncerInteractor alternateBouncerInteractor) {
|
||||
mContext = context;
|
||||
mExecution = execution;
|
||||
mVibrator = vibrator;
|
||||
@@ -759,6 +759,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
||||
|
||||
mBiometricExecutor = biometricsExecutor;
|
||||
mPrimaryBouncerInteractor = primaryBouncerInteractor;
|
||||
mAlternateBouncerInteractor = alternateBouncerInteractor;
|
||||
|
||||
mTouchProcessor = mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
|
||||
? singlePointerTouchProcessor : null;
|
||||
@@ -853,9 +854,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
||||
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");
|
||||
|
||||
@@ -50,6 +50,7 @@ import com.android.systemui.animation.ActivityLaunchAnimator
|
||||
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.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
|
||||
|
||||
private const val TAG = "UdfpsControllerOverlay"
|
||||
|
||||
@@ -86,7 +86,6 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
|
||||
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 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
|
||||
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 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
|
||||
dumpManager,
|
||||
transitionController,
|
||||
configurationController,
|
||||
systemClock,
|
||||
keyguardStateController,
|
||||
unlockedScreenOffAnimationController,
|
||||
dialogManager,
|
||||
controller,
|
||||
activityLaunchAnimator,
|
||||
featureFlags,
|
||||
primaryBouncerInteractor
|
||||
primaryBouncerInteractor,
|
||||
alternateBouncerInteractor,
|
||||
)
|
||||
}
|
||||
REASON_AUTH_BP -> {
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.keyguard.domain.interactor.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.notification.stack.StackStateAnimator
|
||||
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 @@ constructor(
|
||||
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 @@ constructor(
|
||||
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 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ constructor(
|
||||
|
||||
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 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
@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 @@ constructor(
|
||||
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 @@ constructor(
|
||||
|
||||
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 @@ constructor(
|
||||
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")
|
||||
@@ -384,9 +399,6 @@ constructor(
|
||||
}
|
||||
val udfpsAffordanceWasNotShowing = shouldPauseAuth()
|
||||
showingUdfpsBouncer = show
|
||||
if (showingUdfpsBouncer) {
|
||||
lastUdfpsBouncerShowTime = systemClock.uptimeMillis()
|
||||
}
|
||||
if (showingUdfpsBouncer) {
|
||||
if (udfpsAffordanceWasNotShowing) {
|
||||
view.animateInUdfpsBouncer(null)
|
||||
@@ -452,7 +464,7 @@ constructor(
|
||||
return if (isModernBouncerEnabled) {
|
||||
inputBouncerExpansion == 1f
|
||||
} else {
|
||||
keyguardViewManager.isBouncerShowing && !keyguardViewManager.isShowingAlternateBouncer
|
||||
keyguardViewManager.isBouncerShowing && !alternateBouncerInteractor.isVisibleState()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,30 +472,6 @@ constructor(
|
||||
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 @@ constructor(
|
||||
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 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -111,10 +111,6 @@ class UdfpsView(
|
||||
}
|
||||
}
|
||||
|
||||
fun onTouchOutsideView() {
|
||||
animationViewController?.onTouchOutsideView()
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
Log.v(TAG, "onAttachedToWindow")
|
||||
|
||||
@@ -180,6 +180,13 @@ object Flags {
|
||||
@JvmField
|
||||
val LIGHT_REVEAL_MIGRATION = unreleasedFlag(218, "light_reveal_migration", teamfood = false)
|
||||
|
||||
/**
|
||||
* 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")
|
||||
|
||||
/** Flag to control the migration of face auth to modern architecture. */
|
||||
// TODO(b/262838215): Tracking bug
|
||||
@JvmField val FACE_AUTH_REFACTOR = unreleasedFlag(220, "face_auth_refactor")
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
}
|
||||
@@ -26,9 +26,11 @@ import com.android.systemui.log.dagger.BouncerLog
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.log.table.logDiffsForTable
|
||||
import com.android.systemui.statusbar.phone.KeyguardBouncer
|
||||
import com.android.systemui.util.time.SystemClock
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@@ -44,6 +46,7 @@ class KeyguardBouncerRepository
|
||||
@Inject
|
||||
constructor(
|
||||
private val viewMediatorCallback: ViewMediatorCallback,
|
||||
private val clock: SystemClock,
|
||||
@Application private val applicationScope: CoroutineScope,
|
||||
@BouncerLog private val buffer: TableLogBuffer,
|
||||
) {
|
||||
@@ -94,6 +97,14 @@ constructor(
|
||||
setUpLogging()
|
||||
}
|
||||
|
||||
/** 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
|
||||
}
|
||||
@@ -102,6 +113,19 @@ constructor(
|
||||
_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
|
||||
}
|
||||
@@ -202,4 +226,8 @@ constructor(
|
||||
.logDiffsForTable(buffer, "", "ResourceUpdateRequests", false)
|
||||
.launchIn(applicationScope)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NOT_VISIBLE = -1L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,4 +30,6 @@ interface KeyguardRepositoryModule {
|
||||
|
||||
@Binds
|
||||
fun lightRevealScrimRepository(impl: LightRevealScrimRepositoryImpl): LightRevealScrimRepository
|
||||
|
||||
@Binds fun biometricRepository(impl: BiometricRepositoryImpl): BiometricRepository
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -138,6 +138,7 @@ import com.android.systemui.flags.Flags;
|
||||
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.domain.interactor.KeyguardTransitionInteractor;
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState;
|
||||
@@ -362,6 +363,7 @@ public final class NotificationPanelViewController implements Dumpable {
|
||||
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;
|
||||
@@ -807,6 +809,7 @@ public final class NotificationPanelViewController implements Dumpable {
|
||||
SystemClock systemClock,
|
||||
KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
|
||||
KeyguardBottomAreaInteractor keyguardBottomAreaInteractor,
|
||||
AlternateBouncerInteractor alternateBouncerInteractor,
|
||||
DreamingToLockscreenTransitionViewModel dreamingToLockscreenTransitionViewModel,
|
||||
OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel,
|
||||
LockscreenToDreamingTransitionViewModel lockscreenToDreamingTransitionViewModel,
|
||||
@@ -1002,6 +1005,7 @@ public final class NotificationPanelViewController implements Dumpable {
|
||||
unlockAnimationStarted(playingCannedAnimation, isWakeAndUnlock, startDelay);
|
||||
}
|
||||
});
|
||||
mAlternateBouncerInteractor = alternateBouncerInteractor;
|
||||
dumpManager.registerDumpable(this);
|
||||
}
|
||||
|
||||
@@ -4950,7 +4954,7 @@ public final class NotificationPanelViewController implements Dumpable {
|
||||
mUpdateFlingVelocity = vel;
|
||||
}
|
||||
} else if (!mCentralSurfaces.isBouncerShowing()
|
||||
&& !mStatusBarKeyguardViewManager.isShowingAlternateBouncer()
|
||||
&& !mAlternateBouncerInteractor.isVisibleState()
|
||||
&& !mKeyguardStateController.isKeyguardGoingAway()) {
|
||||
onEmptySpaceClick();
|
||||
onTrackingStopped(true);
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.android.systemui.dock.DockManager;
|
||||
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.domain.interactor.KeyguardTransitionInteractor;
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState;
|
||||
import com.android.systemui.keyguard.shared.model.TransitionStep;
|
||||
@@ -85,6 +86,7 @@ public class NotificationShadeWindowViewController {
|
||||
private final AmbientState mAmbientState;
|
||||
private final PulsingGestureListener mPulsingGestureListener;
|
||||
private final NotificationInsetsController mNotificationInsetsController;
|
||||
private final AlternateBouncerInteractor mAlternateBouncerInteractor;
|
||||
|
||||
private GestureDetector mPulsingWakeupGestureHandler;
|
||||
private View mBrightnessMirror;
|
||||
@@ -132,8 +134,9 @@ public class NotificationShadeWindowViewController {
|
||||
PulsingGestureListener pulsingGestureListener,
|
||||
FeatureFlags featureFlags,
|
||||
KeyguardBouncerViewModel keyguardBouncerViewModel,
|
||||
KeyguardTransitionInteractor keyguardTransitionInteractor,
|
||||
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory
|
||||
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
|
||||
AlternateBouncerInteractor alternateBouncerInteractor,
|
||||
KeyguardTransitionInteractor keyguardTransitionInteractor
|
||||
) {
|
||||
mLockscreenShadeTransitionController = transitionController;
|
||||
mFalsingCollector = falsingCollector;
|
||||
@@ -153,6 +156,7 @@ public class NotificationShadeWindowViewController {
|
||||
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);
|
||||
@@ -315,7 +319,7 @@ public class NotificationShadeWindowViewController {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) {
|
||||
if (mAlternateBouncerInteractor.isVisibleState()) {
|
||||
// capture all touches if the alt auth bouncer is showing
|
||||
return true;
|
||||
}
|
||||
@@ -353,7 +357,7 @@ public class NotificationShadeWindowViewController {
|
||||
handled = !mService.isPulsing();
|
||||
}
|
||||
|
||||
if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) {
|
||||
if (mAlternateBouncerInteractor.isVisibleState()) {
|
||||
// eat the touch
|
||||
handled = true;
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ public class CommandQueue extends IStatusBar.Stub implements
|
||||
/**
|
||||
* @see IStatusBar#setBiometicContextListener(IBiometricContextListener)
|
||||
*/
|
||||
default void setBiometicContextListener(IBiometricContextListener listener) {
|
||||
default void setBiometricContextListener(IBiometricContextListener listener) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1583,7 +1583,7 @@ public class CommandQueue extends IStatusBar.Stub implements
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -91,6 +91,7 @@ import com.android.systemui.dock.DockManager;
|
||||
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;
|
||||
@@ -156,6 +157,7 @@ public class KeyguardIndicationController {
|
||||
private final KeyguardBypassController mKeyguardBypassController;
|
||||
private final AccessibilityManager mAccessibilityManager;
|
||||
private final Handler mHandler;
|
||||
private final AlternateBouncerInteractor mAlternateBouncerInteractor;
|
||||
|
||||
@VisibleForTesting
|
||||
public KeyguardIndicationRotateTextViewController mRotateTextViewController;
|
||||
@@ -235,7 +237,8 @@ public class KeyguardIndicationController {
|
||||
KeyguardBypassController keyguardBypassController,
|
||||
AccessibilityManager accessibilityManager,
|
||||
FaceHelpMessageDeferral faceHelpMessageDeferral,
|
||||
KeyguardLogger keyguardLogger) {
|
||||
KeyguardLogger keyguardLogger,
|
||||
AlternateBouncerInteractor alternateBouncerInteractor) {
|
||||
mContext = context;
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mDevicePolicyManager = devicePolicyManager;
|
||||
@@ -257,6 +260,7 @@ public class KeyguardIndicationController {
|
||||
mScreenLifecycle = screenLifecycle;
|
||||
mKeyguardLogger = keyguardLogger;
|
||||
mScreenLifecycle.addObserver(mScreenObserver);
|
||||
mAlternateBouncerInteractor = alternateBouncerInteractor;
|
||||
|
||||
mFaceAcquiredMessageDeferral = faceHelpMessageDeferral;
|
||||
mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
|
||||
@@ -929,7 +933,7 @@ public class KeyguardIndicationController {
|
||||
}
|
||||
|
||||
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()
|
||||
&& !mKeyguardUpdateMonitor.getIsFaceAuthenticated()) {
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.android.systemui.dagger.SysUISingleton;
|
||||
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.ManagedProfileControllerImpl;
|
||||
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 @@ public interface CentralSurfacesDependenciesModule {
|
||||
@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 @@ public interface CentralSurfacesDependenciesModule {
|
||||
|
||||
@Override
|
||||
public boolean isShowingAlternateAuthOnUnlock() {
|
||||
return statusBarKeyguardViewManager.get().canShowAlternateBouncer();
|
||||
return alternateBouncerInteractor.get().canShowAlternateBouncerForFingerprint();
|
||||
}
|
||||
};
|
||||
return new DialogLaunchAnimator(callback, interactionJankMonitor);
|
||||
|
||||
@@ -162,6 +162,7 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
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;
|
||||
@@ -485,6 +486,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
|
||||
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;
|
||||
@@ -763,7 +765,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
|
||||
WiredChargingRippleController wiredChargingRippleController,
|
||||
IDreamManager dreamManager,
|
||||
Lazy<CameraLauncher> cameraLauncherLazy,
|
||||
Lazy<LightRevealScrimViewModel> lightRevealScrimViewModelLazy) {
|
||||
Lazy<LightRevealScrimViewModel> lightRevealScrimViewModelLazy,
|
||||
AlternateBouncerInteractor alternateBouncerInteractor
|
||||
) {
|
||||
mContext = context;
|
||||
mNotificationsController = notificationsController;
|
||||
mFragmentService = fragmentService;
|
||||
@@ -841,6 +845,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
|
||||
mWallpaperManager = wallpaperManager;
|
||||
mJankMonitor = jankMonitor;
|
||||
mCameraLauncherLazy = cameraLauncherLazy;
|
||||
mAlternateBouncerInteractor = alternateBouncerInteractor;
|
||||
|
||||
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
|
||||
mStartingSurfaceOptional = startingSurfaceOptional;
|
||||
@@ -3257,8 +3262,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
|
||||
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
|
||||
@@ -3738,7 +3742,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
|
||||
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);
|
||||
|
||||
@@ -58,6 +58,7 @@ import com.android.systemui.dreams.DreamOverlayStateController;
|
||||
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 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
private KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController;
|
||||
private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
|
||||
private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
|
||||
private final AlternateBouncerInteractor mAlternateBouncerInteractor;
|
||||
private final BouncerView mPrimaryBouncerView;
|
||||
private final Lazy<ShadeController> mShadeController;
|
||||
|
||||
@@ -253,6 +255,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
|
||||
private boolean mIsModernBouncerEnabled;
|
||||
private boolean mIsUnoccludeTransitionFlagEnabled;
|
||||
private boolean mIsModernAlternateBouncerEnabled;
|
||||
|
||||
private OnDismissAction mAfterKeyguardGoneAction;
|
||||
private Runnable mKeyguardGoneCancelAction;
|
||||
@@ -269,7 +272,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
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() {
|
||||
@@ -306,7 +309,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
FeatureFlags featureFlags,
|
||||
PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor,
|
||||
PrimaryBouncerInteractor primaryBouncerInteractor,
|
||||
BouncerView primaryBouncerView) {
|
||||
BouncerView primaryBouncerView,
|
||||
AlternateBouncerInteractor alternateBouncerInteractor) {
|
||||
mContext = context;
|
||||
mViewMediatorCallback = callback;
|
||||
mLockPatternUtils = lockPatternUtils;
|
||||
@@ -331,6 +335,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
.map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
|
||||
mIsModernBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_BOUNCER);
|
||||
mIsUnoccludeTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
|
||||
mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER);
|
||||
mAlternateBouncerInteractor = alternateBouncerInteractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -363,23 +369,51 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,18 +600,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
* {@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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -641,9 +668,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
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,
|
||||
@@ -656,7 +683,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
mKeyguardGoneCancelAction = null;
|
||||
}
|
||||
|
||||
updateAlternateBouncerShowing(mAlternateBouncer.showAlternateBouncer());
|
||||
updateAlternateBouncerShowing(mAlternateBouncerInteractor.show());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -725,10 +752,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
|
||||
@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) {
|
||||
@@ -738,7 +762,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isShowingAlternateBouncer = isShowingAlternateBouncer();
|
||||
final boolean isShowingAlternateBouncer = mAlternateBouncerInteractor.isVisibleState();
|
||||
if (mKeyguardMessageAreaController != null) {
|
||||
mKeyguardMessageAreaController.setIsVisible(isShowingAlternateBouncer);
|
||||
mKeyguardMessageAreaController.setMessage("");
|
||||
@@ -1095,7 +1119,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
|
||||
@Override
|
||||
public boolean isBouncerShowing() {
|
||||
return primaryBouncerIsShowing() || isShowingAlternateBouncer();
|
||||
return primaryBouncerIsShowing() || mAlternateBouncerInteractor.isVisibleState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1339,7 +1363,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
|
||||
}
|
||||
|
||||
if (mAlternateBouncer != null && isShowingAlternateBouncer()) {
|
||||
if (mAlternateBouncerInteractor.isVisibleState()) {
|
||||
hideAlternateBouncer(false);
|
||||
executeAfterKeyguardGoneAction();
|
||||
}
|
||||
@@ -1347,7 +1371,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
|
||||
/** Display security message to relevant KeyguardMessageArea. */
|
||||
public void setKeyguardMessage(String message, ColorStateList colorState) {
|
||||
if (isShowingAlternateBouncer()) {
|
||||
if (mAlternateBouncerInteractor.isVisibleState()) {
|
||||
if (mKeyguardMessageAreaController != null) {
|
||||
mKeyguardMessageAreaController.setMessage(message);
|
||||
}
|
||||
@@ -1421,6 +1445,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.println("StatusBarKeyguardViewManager:");
|
||||
pw.println(" mIsModernAlternateBouncerEnabled: " + mIsModernAlternateBouncerEnabled);
|
||||
pw.println(" mRemoteInputActive: " + mRemoteInputActive);
|
||||
pw.println(" mDozing: " + mDozing);
|
||||
pw.println(" mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction);
|
||||
@@ -1438,9 +1463,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
mPrimaryBouncer.dump(pw);
|
||||
}
|
||||
|
||||
if (mAlternateBouncer != null) {
|
||||
pw.println("AlternateBouncer:");
|
||||
mAlternateBouncer.dump(pw);
|
||||
if (mOccludingAppBiometricUI != null) {
|
||||
pw.println("mOccludingAppBiometricUI:");
|
||||
mOccludingAppBiometricUI.dump(pw);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1492,14 +1517,17 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
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);
|
||||
}
|
||||
@@ -1542,8 +1570,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
*/
|
||||
public void requestFp(boolean request, int udfpsColor) {
|
||||
mKeyguardUpdateManager.requestFingerprintAuthOnOccludingApp(request);
|
||||
if (mAlternateBouncer != null) {
|
||||
mAlternateBouncer.requestUdfps(request, udfpsColor);
|
||||
if (mOccludingAppBiometricUI != null) {
|
||||
mOccludingAppBiometricUI.requestUdfps(request, udfpsColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1614,10 +1642,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -1634,7 +1661,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
* @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.
|
||||
|
||||
@@ -739,7 +739,7 @@ public class AuthControllerTest extends SysuiTestCase {
|
||||
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);
|
||||
@@ -754,7 +754,7 @@ public class AuthControllerTest extends SysuiTestCase {
|
||||
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();
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.keyguard.domain.interactor.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.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 com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
@@ -95,7 +95,6 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
|
||||
@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 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
|
||||
@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 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ import com.android.systemui.dump.DumpManager;
|
||||
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;
|
||||
@@ -202,6 +203,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
|
||||
@Mock
|
||||
private SinglePointerTouchProcessor mSinglePointerTouchProcessor;
|
||||
@Mock
|
||||
private AlternateBouncerInteractor mAlternateBouncerInteractor;
|
||||
|
||||
// Capture listeners so that they can be used to send events
|
||||
@Captor
|
||||
@@ -292,7 +295,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
mDisplayManager, mHandler, mConfigurationController, mSystemClock,
|
||||
mUnlockedScreenOffAnimationController, mSystemUIDialogManager, mLatencyTracker,
|
||||
mActivityLaunchAnimator, alternateTouchProvider, mBiometricExecutor,
|
||||
mPrimaryBouncerInteractor, mSinglePointerTouchProcessor);
|
||||
mPrimaryBouncerInteractor, mSinglePointerTouchProcessor,
|
||||
mAlternateBouncerInteractor);
|
||||
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
|
||||
mOverlayController = mOverlayCaptor.getValue();
|
||||
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
|
||||
@@ -406,7 +410,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
// 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);
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FakeFeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.keyguard.domain.interactor.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.phone.UnlockedScreenOffAnimationController
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -73,9 +73,9 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase {
|
||||
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 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase {
|
||||
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 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
protected void captureAltAuthInterceptor() {
|
||||
verify(mStatusBarKeyguardViewManager).setAlternateBouncer(
|
||||
mAlternateBouncerCaptor.capture());
|
||||
mAlternateBouncer = mAlternateBouncerCaptor.getValue();
|
||||
}
|
||||
|
||||
protected void captureKeyguardStateControllerCallback() {
|
||||
verify(mKeyguardStateController).addCallback(
|
||||
mKeyguardStateControllerCallbackCaptor.capture());
|
||||
@@ -160,6 +150,7 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase {
|
||||
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 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase {
|
||||
mDumpManager,
|
||||
mLockscreenShadeTransitionController,
|
||||
mConfigurationController,
|
||||
mSystemClock,
|
||||
mKeyguardStateController,
|
||||
mUnlockedScreenOffAnimationController,
|
||||
mDialogManager,
|
||||
mUdfpsController,
|
||||
mActivityLaunchAnimator,
|
||||
mFeatureFlags,
|
||||
mPrimaryBouncerInteractor);
|
||||
mPrimaryBouncerInteractor,
|
||||
mAlternateBouncerInteractor);
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,18 +19,15 @@ package com.android.systemui.biometrics;
|
||||
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 @@ import org.mockito.Captor;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper
|
||||
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest {
|
||||
private @Captor ArgumentCaptor<KeyguardBouncer.PrimaryBouncerExpansionCallback>
|
||||
mBouncerExpansionCallbackCaptor;
|
||||
@@ -72,8 +70,6 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController
|
||||
assertTrue(mController.shouldPauseAuth());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testRegistersExpansionChangedListenerOnAttached() {
|
||||
mController.onViewAttached();
|
||||
@@ -237,85 +233,9 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController
|
||||
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
|
||||
@@ -333,25 +253,6 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController
|
||||
verify(mView).setUnpausedAlpha(0);
|
||||
}
|
||||
|
||||
@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
|
||||
@@ -369,24 +270,6 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController
|
||||
verify(mView).setUnpausedAlpha((int) ((1f - transitionProgress) * 255));
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
@@ -21,26 +21,35 @@ import android.testing.AndroidTestingRunner
|
||||
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.log.table.TableLogBuffer
|
||||
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.test.TestCoroutineScope
|
||||
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.Mock
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@@ -57,6 +66,7 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle
|
||||
keyguardBouncerRepository =
|
||||
KeyguardBouncerRepository(
|
||||
mock(com.android.keyguard.ViewMediatorCallback::class.java),
|
||||
FakeSystemClock(),
|
||||
TestCoroutineScope(),
|
||||
bouncerLogger,
|
||||
)
|
||||
@@ -77,15 +87,43 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle
|
||||
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()
|
||||
|
||||
@@ -79,15 +79,6 @@ class UdfpsViewTest : SysuiTestCase() {
|
||||
ViewUtils.detachView(view)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun forwardsEvents() {
|
||||
view.dozeTimeTick()
|
||||
verify(animationViewController).dozeTimeTick()
|
||||
|
||||
view.onTouchOutsideView()
|
||||
verify(animationViewController).onTouchOutsideView()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun layoutSizeFitsSensor() {
|
||||
val params = withArgCaptor<RectF> {
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import androidx.test.filters.SmallTest
|
||||
import com.android.keyguard.ViewMediatorCallback
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.util.time.SystemClock
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.TestCoroutineScope
|
||||
import org.junit.Before
|
||||
@@ -34,6 +35,7 @@ import org.mockito.MockitoAnnotations
|
||||
@RunWith(JUnit4::class)
|
||||
class KeyguardBouncerRepositoryTest : SysuiTestCase() {
|
||||
|
||||
@Mock private lateinit var systemClock: SystemClock
|
||||
@Mock private lateinit var viewMediatorCallback: ViewMediatorCallback
|
||||
@Mock private lateinit var bouncerLogger: TableLogBuffer
|
||||
lateinit var underTest: KeyguardBouncerRepository
|
||||
@@ -43,7 +45,12 @@ class KeyguardBouncerRepositoryTest : SysuiTestCase() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
val testCoroutineScope = TestCoroutineScope()
|
||||
underTest =
|
||||
KeyguardBouncerRepository(viewMediatorCallback, testCoroutineScope, bouncerLogger)
|
||||
KeyguardBouncerRepository(
|
||||
viewMediatorCallback,
|
||||
systemClock,
|
||||
testCoroutineScope,
|
||||
bouncerLogger,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.log.table.TableLogBuffer
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.android.systemui.util.time.SystemClock
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestCoroutineScope
|
||||
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
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@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
|
||||
@Mock private lateinit var bouncerLogger: TableLogBuffer
|
||||
private lateinit var featureFlags: FakeFeatureFlags
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
bouncerRepository =
|
||||
KeyguardBouncerRepository(
|
||||
mock(ViewMediatorCallback::class.java),
|
||||
FakeSystemClock(),
|
||||
TestCoroutineScope(),
|
||||
bouncerLogger,
|
||||
)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,7 @@ import com.android.systemui.flags.FeatureFlags;
|
||||
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.domain.interactor.KeyguardTransitionInteractor;
|
||||
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
|
||||
@@ -300,6 +301,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
|
||||
|
||||
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
|
||||
@Mock private CoroutineDispatcher mMainDispatcher;
|
||||
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
|
||||
@Mock private MotionEvent mDownMotionEvent;
|
||||
@Captor
|
||||
private ArgumentCaptor<NotificationStackScrollLayout.OnEmptySpaceClickListener>
|
||||
@@ -516,6 +518,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
|
||||
systemClock,
|
||||
mKeyguardBottomAreaViewModel,
|
||||
mKeyguardBottomAreaInteractor,
|
||||
mAlternateBouncerInteractor,
|
||||
mDreamingToLockscreenTransitionViewModel,
|
||||
mOccludedToLockscreenTransitionViewModel,
|
||||
mLockscreenToDreamingTransitionViewModel,
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.android.systemui.classifier.FalsingCollectorFake
|
||||
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.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
|
||||
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
|
||||
@@ -98,6 +99,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
|
||||
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
|
||||
@@ -134,8 +137,9 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
|
||||
pulsingGestureListener,
|
||||
featureFlags,
|
||||
keyguardBouncerViewModel,
|
||||
keyguardTransitionInteractor,
|
||||
keyguardBouncerComponentFactory,
|
||||
alternateBouncerInteractor,
|
||||
keyguardTransitionInteractor,
|
||||
)
|
||||
underTest.setupExpandedStatusBar()
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.android.systemui.classifier.FalsingCollectorFake;
|
||||
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.domain.interactor.KeyguardTransitionInteractor;
|
||||
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
|
||||
import com.android.systemui.statusbar.DragDownHelper;
|
||||
@@ -94,6 +95,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
|
||||
@Mock private KeyguardBouncerViewModel mKeyguardBouncerViewModel;
|
||||
@Mock private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
|
||||
@Mock private NotificationInsetsController mNotificationInsetsController;
|
||||
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
|
||||
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
|
||||
|
||||
@Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
|
||||
@@ -134,8 +136,9 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
|
||||
mPulsingGestureListener,
|
||||
mFeatureFlags,
|
||||
mKeyguardBouncerViewModel,
|
||||
mKeyguardTransitionInteractor,
|
||||
mKeyguardBouncerComponentFactory
|
||||
mKeyguardBouncerComponentFactory,
|
||||
mAlternateBouncerInteractor,
|
||||
mKeyguardTransitionInteractor
|
||||
);
|
||||
mController.setupExpandedStatusBar();
|
||||
mController.setDragDownHelper(mDragDownHelper);
|
||||
@@ -158,7 +161,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
|
||||
|
||||
// WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(true);
|
||||
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
|
||||
when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
|
||||
|
||||
// THEN we should intercept touch
|
||||
@@ -171,7 +174,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
|
||||
|
||||
// WHEN not showing alt auth, not dozing, drag down helper doesn't want to intercept
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(false);
|
||||
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
|
||||
when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
|
||||
|
||||
// THEN we shouldn't intercept touch
|
||||
@@ -184,7 +187,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
|
||||
|
||||
// WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(true);
|
||||
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
|
||||
when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
|
||||
|
||||
// THEN we should handle the touch
|
||||
|
||||
@@ -99,6 +99,7 @@ import com.android.systemui.dock.DockManager;
|
||||
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 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private FaceHelpMessageDeferral mFaceHelpMessageDeferral;
|
||||
@Mock
|
||||
private AlternateBouncerInteractor mAlternateBouncerInteractor;
|
||||
@Mock
|
||||
private ScreenLifecycle mScreenLifecycle;
|
||||
@Mock
|
||||
private AuthController mAuthController;
|
||||
@@ -273,7 +276,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
|
||||
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());
|
||||
|
||||
@@ -110,6 +110,7 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
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;
|
||||
@@ -177,8 +178,6 @@ import com.android.systemui.volume.VolumeComponent;
|
||||
import com.android.wm.shell.bubbles.Bubbles;
|
||||
import com.android.wm.shell.startingsurface.StartingSurface;
|
||||
|
||||
import dagger.Lazy;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -191,6 +190,8 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Optional;
|
||||
|
||||
import dagger.Lazy;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper(setAsMainLooper = true)
|
||||
@@ -297,6 +298,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
|
||||
@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.
|
||||
@@ -504,7 +506,9 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
|
||||
mWiredChargingRippleController,
|
||||
mDreamManager,
|
||||
mCameraLauncherLazy,
|
||||
() -> mLightRevealScrimViewModel) {
|
||||
() -> mLightRevealScrimViewModel,
|
||||
mAlternateBouncerInteractor
|
||||
) {
|
||||
@Override
|
||||
protected ViewRootImpl getViewRootImpl() {
|
||||
return mViewRootImpl;
|
||||
|
||||
@@ -56,6 +56,7 @@ import com.android.systemui.dreams.DreamOverlayStateController;
|
||||
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 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
||||
@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 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
||||
@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 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
||||
mFeatureFlags,
|
||||
mPrimaryBouncerCallbackInteractor,
|
||||
mPrimaryBouncerInteractor,
|
||||
mBouncerView) {
|
||||
mBouncerView,
|
||||
mAlternateBouncerInteractor) {
|
||||
@Override
|
||||
public ViewRootImpl getViewRootImpl() {
|
||||
return mViewRootImpl;
|
||||
@@ -434,37 +436,35 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
||||
|
||||
@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 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
||||
|
||||
@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 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
||||
|
||||
// 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 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
|
||||
mFeatureFlags,
|
||||
mPrimaryBouncerCallbackInteractor,
|
||||
mPrimaryBouncerInteractor,
|
||||
mBouncerView) {
|
||||
mBouncerView,
|
||||
mAlternateBouncerInteractor) {
|
||||
@Override
|
||||
public ViewRootImpl getViewRootImpl() {
|
||||
return mViewRootImpl;
|
||||
|
||||
@@ -56,6 +56,7 @@ import com.android.systemui.dreams.DreamOverlayStateController;
|
||||
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 @@ public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
|
||||
@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 @@ public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
|
||||
@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 @@ public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
|
||||
mFeatureFlags,
|
||||
mPrimaryBouncerCallbackInteractor,
|
||||
mPrimaryBouncerInteractor,
|
||||
mBouncerView) {
|
||||
mBouncerView,
|
||||
mAlternateBouncerInteractor) {
|
||||
@Override
|
||||
public ViewRootImpl getViewRootImpl() {
|
||||
return mViewRootImpl;
|
||||
@@ -438,41 +440,6 @@ public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
|
||||
verify(cancelAction, never()).run();
|
||||
}
|
||||
|
||||
@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);
|
||||
@@ -483,38 +450,6 @@ public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
|
||||
mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing());
|
||||
}
|
||||
|
||||
@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 @@ public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
|
||||
mFeatureFlags,
|
||||
mPrimaryBouncerCallbackInteractor,
|
||||
mPrimaryBouncerInteractor,
|
||||
mBouncerView) {
|
||||
mBouncerView,
|
||||
mAlternateBouncerInteractor) {
|
||||
@Override
|
||||
public ViewRootImpl getViewRootImpl() {
|
||||
return mViewRootImpl;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user