[flexiglass] Add a DeviceEntry module.
This module hosts business logic and state related to device entry, i.e.
when the user successfully dismisses (or bypasses) the lockscreen. This
is distinct from the authentication module, which is specifically
concerned with determining a user's identity.
The names of certain state variables have changed, too:
* `isLockscreenDismissed` is now `isDeviceEntered`
* `canSwipeToDismiss` is now `canSwipeToEnter`
* `isLockscreenEnabled` is now `isInsecureLockscreenEnabled`
Bug: 301253588
Test: Existing unit tests still pass.
Test: Added new unit tests.
Test: Manually tested the 3 different bouncer auth methods, lockscreen
bypass and swipe, and verified they still work as expected.
Change-Id: I9596513b4319eb0a9b9a25bee3a1c1726396e4ca
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index b2287d87..51dafac 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -18,6 +18,7 @@
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS;
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY;
@@ -68,8 +69,6 @@
import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.Gefingerpoken;
-import com.android.systemui.res.R;
-import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor;
import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate;
import com.android.systemui.biometrics.SideFpsController;
import com.android.systemui.biometrics.SideFpsUiRequestSource;
@@ -77,6 +76,7 @@
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
@@ -84,6 +84,7 @@
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.res.R;
import com.android.systemui.scene.shared.flag.SceneContainerFlags;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -420,7 +421,7 @@
}
};
private final UserInteractor mUserInteractor;
- private final Provider<AuthenticationInteractor> mAuthenticationInteractor;
+ private final Provider<DeviceEntryInteractor> mDeviceEntryInteractor;
private final Provider<JavaAdapter> mJavaAdapter;
private final DeviceProvisionedController mDeviceProvisionedController;
private final Lazy<PrimaryBouncerInteractor> mPrimaryBouncerInteractor;
@@ -457,7 +458,7 @@
FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate,
KeyguardTransitionInteractor keyguardTransitionInteractor,
Lazy<PrimaryBouncerInteractor> primaryBouncerInteractor,
- Provider<AuthenticationInteractor> authenticationInteractor
+ Provider<DeviceEntryInteractor> deviceEntryInteractor
) {
super(view);
view.setAccessibilityDelegate(faceAuthAccessibilityDelegate);
@@ -487,7 +488,7 @@
mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
mBouncerMessageInteractor = bouncerMessageInteractor;
mUserInteractor = userInteractor;
- mAuthenticationInteractor = authenticationInteractor;
+ mDeviceEntryInteractor = deviceEntryInteractor;
mJavaAdapter = javaAdapter;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mDeviceProvisionedController = deviceProvisionedController;
@@ -519,9 +520,9 @@
// When the scene framework says that the lockscreen has been dismissed, dismiss the
// keyguard here, revealing the underlying app or launcher:
mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow(
- mAuthenticationInteractor.get().isLockscreenDismissed(),
- isLockscreenDismissed -> {
- if (isLockscreenDismissed) {
+ mDeviceEntryInteractor.get().isDeviceEntered(),
+ isDeviceEntered -> {
+ if (isDeviceEntered) {
final int selectedUserId = mUserInteractor.getSelectedUserId();
showNextSecurityScreenOrFinish(
/* authenticated= */ true,
@@ -1081,15 +1082,11 @@
* one side).
*/
private boolean canUseOneHandedBouncer() {
- switch(mCurrentSecurityMode) {
- case PIN:
- case Pattern:
- case SimPin:
- case SimPuk:
- return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
- default:
- return false;
- }
+ return switch (mCurrentSecurityMode) {
+ case PIN, Pattern, SimPin, SimPuk -> getResources().getBoolean(
+ R.bool.can_use_one_handed_bouncer);
+ default -> false;
+ };
}
private boolean canDisplayUserSwitcher() {
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index b2433d4..80be008 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -29,9 +29,9 @@
import com.android.systemui.authentication.shared.model.AuthenticationResultModel
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.time.SystemClock
@@ -59,18 +59,6 @@
/** Defines interface for classes that can access authentication-related application state. */
interface AuthenticationRepository {
-
- /**
- * Whether the device is unlocked.
- *
- * A device that is not yet unlocked requires unlocking by completing an authentication
- * challenge according to the current authentication method, unless in cases when the current
- * authentication method is not "secure" (for example, None); in such cases, the value of this
- * flow will always be `true`, even if the lockscreen is showing and still needs to be dismissed
- * by the user to proceed.
- */
- val isUnlocked: StateFlow<Boolean>
-
/**
* Whether the auto confirm feature is enabled for the currently-selected user.
*
@@ -129,14 +117,6 @@
/** Returns the length of the PIN or `0` if the current auth method is not PIN. */
suspend fun getPinLength(): Int
- /**
- * Returns whether the lockscreen is enabled.
- *
- * When the lockscreen is not enabled, it shouldn't show in cases when the authentication method
- * is considered not secure (for example, "swipe" is considered to be "none").
- */
- suspend fun isLockscreenEnabled(): Boolean
-
/** Reports an authentication attempt. */
suspend fun reportAuthenticationAttempt(isSuccessful: Boolean)
@@ -167,6 +147,7 @@
suspend fun checkCredential(credential: LockscreenCredential): AuthenticationResultModel
}
+@SysUISingleton
class AuthenticationRepositoryImpl
@Inject
constructor(
@@ -174,20 +155,10 @@
private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val userRepository: UserRepository,
- keyguardRepository: KeyguardRepository,
private val lockPatternUtils: LockPatternUtils,
broadcastDispatcher: BroadcastDispatcher,
) : AuthenticationRepository {
- override val isUnlocked = keyguardRepository.isKeyguardUnlocked
-
- override suspend fun isLockscreenEnabled(): Boolean {
- return withContext(backgroundDispatcher) {
- val selectedUserId = userRepository.selectedUserId
- !lockPatternUtils.isLockScreenDisabled(selectedUserId)
- }
- }
-
override val isAutoConfirmEnabled: StateFlow<Boolean> =
refreshingFlow(
initialValue = false,
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 4cfc6aa..453a7a6 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -26,9 +26,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
@@ -42,15 +40,19 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-/** Hosts application business logic related to authentication. */
+/**
+ * Hosts application business logic related to user authentication.
+ *
+ * Note: there is a distinction between authentication (determining a user's identity) and device
+ * entry (dismissing the lockscreen). For logic that is specific to device entry, please use
+ * `DeviceEntryInteractor` instead.
+ */
@SysUISingleton
class AuthenticationInteractor
@Inject
@@ -59,8 +61,7 @@
private val repository: AuthenticationRepository,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val userRepository: UserRepository,
- private val keyguardRepository: KeyguardRepository,
- sceneInteractor: SceneInteractor,
+ private val deviceEntryRepository: DeviceEntryRepository,
private val clock: SystemClock,
) {
/**
@@ -77,76 +78,13 @@
* Note: this layer adds the synthetic authentication method of "swipe" which is special. When
* the current authentication method is "swipe", the user does not need to complete any
* authentication challenge to unlock the device; they just need to dismiss the lockscreen to
- * get past it. This also means that the value of [isUnlocked] remains `false` even when the
- * lockscreen is showing and still needs to be dismissed by the user to proceed.
+ * get past it. This also means that the value of `DeviceEntryInteractor#isUnlocked` remains
+ * `true` even when the lockscreen is showing and still needs to be dismissed by the user to
+ * proceed.
*/
val authenticationMethod: Flow<DomainLayerAuthenticationMethodModel> =
repository.authenticationMethod.map { rawModel -> rawModel.toDomainLayer() }
- /**
- * Whether the device is unlocked.
- *
- * A device that is not yet unlocked requires unlocking by completing an authentication
- * challenge according to the current authentication method, unless in cases when the current
- * authentication method is not "secure" (for example, None and Swipe); in such cases, the value
- * of this flow will always be `true`, even if the lockscreen is showing and still needs to be
- * dismissed by the user to proceed.
- */
- val isUnlocked: StateFlow<Boolean> =
- combine(
- repository.isUnlocked,
- authenticationMethod,
- ) { isUnlocked, authenticationMethod ->
- !authenticationMethod.isSecure || isUnlocked
- }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = false,
- )
-
- /**
- * Whether the lockscreen has been dismissed (by any method). This can be false even when the
- * device is unlocked, e.g. when swipe to unlock is enabled.
- *
- * Note:
- * - `false` doesn't mean the lockscreen is visible (it may be occluded or covered by other UI).
- * - `true` doesn't mean the lockscreen is invisible (since this state changes before the
- * transition occurs).
- */
- val isLockscreenDismissed: StateFlow<Boolean> =
- sceneInteractor.desiredScene
- .map { it.key }
- .filter { currentScene ->
- currentScene == SceneKey.Gone || currentScene == SceneKey.Lockscreen
- }
- .map { it == SceneKey.Gone }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false,
- )
-
- /**
- * Whether it's currently possible to swipe up to dismiss the lockscreen without requiring
- * authentication. This returns false whenever the lockscreen has been dismissed.
- *
- * Note: `true` doesn't mean the lockscreen is visible. It may be occluded or covered by other
- * UI.
- */
- val canSwipeToDismiss =
- combine(authenticationMethod, isLockscreenDismissed) {
- authenticationMethod,
- isLockscreenDismissed ->
- authenticationMethod is DomainLayerAuthenticationMethodModel.Swipe &&
- !isLockscreenDismissed
- }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false,
- )
-
/** The current authentication throttling state, only meaningful if [isThrottled] is `true`. */
val throttling: StateFlow<AuthenticationThrottlingModel> = repository.throttling
@@ -211,32 +149,15 @@
* Note: this layer adds the synthetic authentication method of "swipe" which is special. When
* the current authentication method is "swipe", the user does not need to complete any
* authentication challenge to unlock the device; they just need to dismiss the lockscreen to
- * get past it. This also means that the value of [isUnlocked] remains `false` even when the
- * lockscreen is showing and still needs to be dismissed by the user to proceed.
+ * get past it. This also means that the value of `DeviceEntryInteractor#isUnlocked` remains
+ * `true` even when the lockscreen is showing and still needs to be dismissed by the user to
+ * proceed.
*/
suspend fun getAuthenticationMethod(): DomainLayerAuthenticationMethodModel {
return repository.getAuthenticationMethod().toDomainLayer()
}
/**
- * Returns `true` if the device currently requires authentication before content can be viewed;
- * `false` if content can be displayed without unlocking first.
- */
- suspend fun isAuthenticationRequired(): Boolean {
- return !isUnlocked.value && getAuthenticationMethod().isSecure
- }
-
- /**
- * Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically
- * dismisses once the authentication challenge is completed. For example, completing a biometric
- * authentication challenge via face unlock or fingerprint sensor can automatically bypass the
- * lock screen.
- */
- fun isBypassEnabled(): Boolean {
- return keyguardRepository.isBypassEnabled()
- }
-
- /**
* Attempts to authenticate the user and unlock the device.
*
* If [tryAutoConfirm] is `true`, authentication is attempted if and only if the auth method
@@ -312,7 +233,7 @@
/** Starts refreshing the throttling state every second. */
private suspend fun startThrottlingCountdown() {
- cancelCountdown()
+ cancelThrottlingCountdown()
throttlingCountdownJob =
applicationScope.launch {
while (refreshThrottling() > 0) {
@@ -322,14 +243,14 @@
}
/** Cancels any throttling state countdown started in [startThrottlingCountdown]. */
- private fun cancelCountdown() {
+ private fun cancelThrottlingCountdown() {
throttlingCountdownJob?.cancel()
throttlingCountdownJob = null
}
/** Notifies that the currently-selected user has changed. */
private suspend fun onSelectedUserChanged() {
- cancelCountdown()
+ cancelThrottlingCountdown()
if (refreshThrottling() > 0) {
startThrottlingCountdown()
}
@@ -378,7 +299,7 @@
DomainLayerAuthenticationMethodModel {
return when (this) {
is DataLayerAuthenticationMethodModel.None ->
- if (repository.isLockscreenEnabled()) {
+ if (deviceEntryRepository.isInsecureLockscreenEnabled()) {
DomainLayerAuthenticationMethodModel.Swipe
} else {
DomainLayerAuthenticationMethodModel.None
@@ -394,13 +315,10 @@
/** Result of a user authentication attempt. */
enum class AuthenticationResult {
- /** Authentication succeeded and the device is now unlocked. */
+ /** Authentication succeeded. */
SUCCEEDED,
- /** Authentication failed and the device remains unlocked. */
+ /** Authentication failed. */
FAILED,
- /**
- * Authentication was not performed, e.g. due to insufficient input, and the device remains
- * unlocked.
- */
+ /** Authentication was not performed, e.g. due to insufficient input. */
SKIPPED,
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index f3a463b..0c02369 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -26,6 +26,7 @@
import com.android.systemui.classifier.domain.interactor.FalsingInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlags
@@ -50,6 +51,7 @@
@Application private val applicationScope: CoroutineScope,
@Application private val applicationContext: Context,
private val repository: BouncerRepository,
+ private val deviceEntryInteractor: DeviceEntryInteractor,
private val authenticationInteractor: AuthenticationInteractor,
private val sceneInteractor: SceneInteractor,
flags: SceneContainerFlags,
@@ -144,7 +146,7 @@
message: String? = null,
) {
applicationScope.launch {
- if (authenticationInteractor.isAuthenticationRequired()) {
+ if (deviceEntryInteractor.isAuthenticationRequired()) {
repository.setMessage(
message ?: promptMessage(authenticationInteractor.getAuthenticationMethod())
)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 283a07b..4b6ad6d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -48,6 +48,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.SystemUser;
import com.android.systemui.demomode.dagger.DemoModeModule;
+import com.android.systemui.deviceentry.DeviceEntryModule;
import com.android.systemui.display.DisplayModule;
import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.dreams.dagger.DreamModule;
@@ -173,6 +174,7 @@
ControlsModule.class,
CoroutinesModule.class,
DemoModeModule.class,
+ DeviceEntryModule.class,
DisableFlagsModule.class,
DisplayModule.class,
DreamModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
new file mode 100644
index 0000000..e7f835f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
@@ -0,0 +1,12 @@
+package com.android.systemui.deviceentry
+
+import com.android.systemui.deviceentry.data.repository.DeviceEntryRepositoryModule
+import dagger.Module
+
+@Module(
+ includes =
+ [
+ DeviceEntryRepositoryModule::class,
+ ],
+)
+object DeviceEntryModule
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt
new file mode 100644
index 0000000..5b85ad0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt
@@ -0,0 +1,125 @@
+package com.android.systemui.deviceentry.data.repository
+
+import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.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.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.user.data.repository.UserRepository
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
+
+/** Interface for classes that can access device-entry-related application state. */
+interface DeviceEntryRepository {
+ /**
+ * Whether the device is unlocked.
+ *
+ * A device that is not yet unlocked requires unlocking by completing an authentication
+ * challenge according to the current authentication method, unless in cases when the current
+ * authentication method is not "secure" (for example, None); in such cases, the value of this
+ * flow will always be `true`, even if the lockscreen is showing and still needs to be dismissed
+ * by the user to proceed.
+ */
+ val isUnlocked: StateFlow<Boolean>
+
+ /**
+ * Whether the lockscreen should be shown when the authentication method is not secure (e.g.
+ * `None` or `Swipe`).
+ */
+ suspend fun isInsecureLockscreenEnabled(): Boolean
+
+ /**
+ * Whether lockscreen bypass is enabled. When enabled, the lockscreen will be automatically
+ * dismissed once the authentication challenge is completed.
+ *
+ * This is a setting that is specific to the face unlock authentication method, because the user
+ * intent to unlock is not known. On devices that don't support face unlock, this always returns
+ * `true`.
+ *
+ * When this is `false`, an automatically-triggered face unlock shouldn't automatically dismiss
+ * the lockscreen.
+ */
+ fun isBypassEnabled(): Boolean
+}
+
+/** Encapsulates application state for device entry. */
+@SysUISingleton
+class DeviceEntryRepositoryImpl
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val userRepository: UserRepository,
+ private val lockPatternUtils: LockPatternUtils,
+ private val keyguardBypassController: KeyguardBypassController,
+ keyguardStateController: KeyguardStateController,
+) : DeviceEntryRepository {
+
+ override val isUnlocked =
+ ConflatedCallbackFlow.conflatedCallbackFlow {
+ val callback =
+ object : KeyguardStateController.Callback {
+ override fun onUnlockedChanged() {
+ trySendWithFailureLogging(
+ keyguardStateController.isUnlocked,
+ TAG,
+ "updated isUnlocked due to onUnlockedChanged"
+ )
+ }
+
+ override fun onKeyguardShowingChanged() {
+ trySendWithFailureLogging(
+ keyguardStateController.isUnlocked,
+ TAG,
+ "updated isUnlocked due to onKeyguardShowingChanged"
+ )
+ }
+ }
+
+ keyguardStateController.addCallback(callback)
+ // Adding the callback does not send an initial update.
+ trySendWithFailureLogging(
+ keyguardStateController.isUnlocked,
+ TAG,
+ "initial isKeyguardUnlocked"
+ )
+
+ awaitClose { keyguardStateController.removeCallback(callback) }
+ }
+ .distinctUntilChanged()
+ .stateIn(
+ applicationScope,
+ SharingStarted.Eagerly,
+ initialValue = false,
+ )
+
+ override suspend fun isInsecureLockscreenEnabled(): Boolean {
+ return withContext(backgroundDispatcher) {
+ val selectedUserId = userRepository.getSelectedUserInfo().id
+ !lockPatternUtils.isLockScreenDisabled(selectedUserId)
+ }
+ }
+
+ override fun isBypassEnabled() = keyguardBypassController.bypassEnabled
+
+ companion object {
+ private const val TAG = "DeviceEntryRepositoryImpl"
+ }
+}
+
+@Module
+interface DeviceEntryRepositoryModule {
+ @Binds fun repository(impl: DeviceEntryRepositoryImpl): DeviceEntryRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
new file mode 100644
index 0000000..5612c9a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -0,0 +1,110 @@
+package com.android.systemui.deviceentry.domain.interactor
+
+import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.SceneKey
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Hosts application business logic related to device entry.
+ *
+ * Device entry occurs when the user successfully dismisses (or bypasses) the lockscreen, regardless
+ * of the authentication method used.
+ */
+@SysUISingleton
+class DeviceEntryInteractor
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val repository: DeviceEntryRepository,
+ private val authenticationInteractor: AuthenticationInteractor,
+ sceneInteractor: SceneInteractor,
+) {
+ /**
+ * Whether the device is unlocked.
+ *
+ * A device that is not yet unlocked requires unlocking by completing an authentication
+ * challenge according to the current authentication method, unless in cases when the current
+ * authentication method is not "secure" (for example, None and Swipe); in such cases, the value
+ * of this flow will always be `true`, even if the lockscreen is showing and still needs to be
+ * dismissed by the user to proceed.
+ */
+ val isUnlocked: StateFlow<Boolean> =
+ combine(
+ repository.isUnlocked,
+ authenticationInteractor.authenticationMethod,
+ ) { isUnlocked, authenticationMethod ->
+ !authenticationMethod.isSecure || isUnlocked
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = false,
+ )
+
+ /**
+ * Whether the device has been entered (i.e. the lockscreen has been dismissed, by any method).
+ * This can be `false` when the device is unlocked, e.g. when the user still needs to swipe away
+ * the non-secure lockscreen, even though they've already authenticated.
+ *
+ * Note: This does not imply that the lockscreen is visible or not.
+ */
+ val isDeviceEntered: StateFlow<Boolean> =
+ sceneInteractor.desiredScene
+ .map { it.key }
+ .filter { currentScene ->
+ currentScene == SceneKey.Gone || currentScene == SceneKey.Lockscreen
+ }
+ .map { it == SceneKey.Gone }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
+
+ /**
+ * Whether it's currently possible to swipe up to enter the device without requiring
+ * authentication. This returns `false` whenever the lockscreen has been dismissed.
+ *
+ * Note: `true` doesn't mean the lockscreen is visible. It may be occluded or covered by other
+ * UI.
+ */
+ val canSwipeToEnter =
+ combine(authenticationInteractor.authenticationMethod, isDeviceEntered) {
+ authenticationMethod,
+ isDeviceEntered ->
+ authenticationMethod is AuthenticationMethodModel.Swipe && !isDeviceEntered
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
+
+ /**
+ * Returns `true` if the device currently requires authentication before entry is granted;
+ * `false` if the device can be entered without authenticating first.
+ */
+ suspend fun isAuthenticationRequired(): Boolean {
+ return !isUnlocked.value && authenticationInteractor.getAuthenticationMethod().isSecure
+ }
+
+ /**
+ * Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically
+ * dismissed once the authentication challenge is completed. For example, completing a biometric
+ * authentication challenge via face unlock or fingerprint sensor can automatically bypass the
+ * lock screen.
+ */
+ fun isBypassEnabled() = repository.isBypassEnabled()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 2557e81..36b93cd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -47,7 +47,6 @@
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.BiometricUnlockController.WakeAndUnlockMode
import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
@@ -97,9 +96,6 @@
*/
val isKeyguardShowing: Flow<Boolean>
- /** Is the keyguard in a unlocked state? */
- val isKeyguardUnlocked: StateFlow<Boolean>
-
/** Is an activity showing over the keyguard? */
val isKeyguardOccluded: Flow<Boolean>
@@ -206,14 +202,6 @@
*/
fun isKeyguardShowing(): Boolean
- /**
- * Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically
- * dismissed once the authentication challenge is completed. For example, completing a biometric
- * authentication challenge via face unlock or fingerprint sensor can automatically bypass the
- * lock screen.
- */
- fun isBypassEnabled(): Boolean
-
/** Sets whether the bottom area UI should animate the transition out of doze state. */
fun setAnimateDozingTransitions(animate: Boolean)
@@ -265,7 +253,6 @@
screenLifecycle: ScreenLifecycle,
biometricUnlockController: BiometricUnlockController,
private val keyguardStateController: KeyguardStateController,
- private val keyguardBypassController: KeyguardBypassController,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val dozeTransitionListener: DozeTransitionListener,
private val dozeParameters: DozeParameters,
@@ -370,44 +357,6 @@
}
.distinctUntilChanged()
- override val isKeyguardUnlocked: StateFlow<Boolean> =
- conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onUnlockedChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "updated isKeyguardUnlocked due to onUnlockedChanged"
- )
- }
-
- override fun onKeyguardShowingChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "updated isKeyguardUnlocked due to onKeyguardShowingChanged"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "initial isKeyguardUnlocked"
- )
-
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
- .distinctUntilChanged()
- .stateIn(
- scope,
- SharingStarted.Eagerly,
- initialValue = false,
- )
-
override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow {
val callback =
object : KeyguardStateController.Callback {
@@ -543,10 +492,6 @@
return keyguardStateController.isShowing
}
- override fun isBypassEnabled(): Boolean {
- return keyguardBypassController.bypassEnabled
- }
-
// TODO(b/297345631): Expose this at the interactor level instead so that it can be powered by
// [SceneInteractor] when scenes are ready.
override val statusBarState: StateFlow<StatusBarState> =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 338f994..8063468 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -23,7 +23,6 @@
import android.graphics.Point
import android.util.MathUtils
import com.android.app.animation.Interpolators
-import com.android.systemui.res.R
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -31,6 +30,7 @@
import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.KeyguardRepository
@@ -40,10 +40,10 @@
import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.KeyguardRootViewVisibilityState
-import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.ScreenModel
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.scene.shared.model.SceneKey
@@ -79,6 +79,7 @@
private val commandQueue: CommandQueue,
featureFlags: FeatureFlags,
sceneContainerFlags: SceneContainerFlags,
+ deviceEntryRepository: DeviceEntryRepository,
bouncerRepository: KeyguardBouncerRepository,
configurationRepository: ConfigurationRepository,
shadeRepository: ShadeRepository,
@@ -168,7 +169,7 @@
val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
/** Whether the keyguard is unlocked or not. */
- val isKeyguardUnlocked: Flow<Boolean> = repository.isKeyguardUnlocked
+ val isKeyguardUnlocked: Flow<Boolean> = deviceEntryRepository.isUnlocked
/** Whether the keyguard is occluded (covered by an activity). */
val isKeyguardOccluded: Flow<Boolean> = repository.isKeyguardOccluded
@@ -323,26 +324,7 @@
repository.setAnimateDozingTransitions(animate)
}
- fun isKeyguardDismissable(): Boolean {
- return repository.isKeyguardUnlocked.value
- }
-
companion object {
private const val TAG = "KeyguardInteractor"
-
- fun isKeyguardVisibleInState(state: KeyguardState): Boolean {
- return when (state) {
- KeyguardState.OFF -> true
- KeyguardState.DOZING -> true
- KeyguardState.DREAMING -> true
- KeyguardState.AOD -> true
- KeyguardState.ALTERNATE_BOUNCER -> true
- KeyguardState.PRIMARY_BOUNCER -> true
- KeyguardState.LOCKSCREEN -> true
- KeyguardState.GONE -> false
- KeyguardState.OCCLUDED -> true
- KeyguardState.DREAMING_LOCKSCREEN_HOSTED -> false
- }
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index 91b3357..c03e4d9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -16,10 +16,10 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.scene.shared.model.SceneKey
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -34,26 +34,22 @@
@Inject
constructor(
@Application applicationScope: CoroutineScope,
- authenticationInteractor: AuthenticationInteractor,
+ deviceEntryInteractor: DeviceEntryInteractor,
communalInteractor: CommunalInteractor,
val longPress: KeyguardLongPressViewModel,
) {
/** The key of the scene we should switch to when swiping up. */
val upDestinationSceneKey: StateFlow<SceneKey> =
- authenticationInteractor.isUnlocked
+ deviceEntryInteractor.isUnlocked
.map { isUnlocked -> upDestinationSceneKey(isUnlocked) }
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = upDestinationSceneKey(authenticationInteractor.isUnlocked.value),
+ initialValue = upDestinationSceneKey(deviceEntryInteractor.isUnlocked.value),
)
private fun upDestinationSceneKey(isUnlocked: Boolean): SceneKey {
- return if (isUnlocked) {
- SceneKey.Gone
- } else {
- SceneKey.Bouncer
- }
+ return if (isUnlocked) SceneKey.Gone else SceneKey.Bouncer
}
/** The key of the scene we should switch to when swiping left. */
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 722d366..a3499bd 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -26,6 +26,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.DisplayId
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.model.SysUiState
@@ -63,6 +64,7 @@
constructor(
@Application private val applicationScope: CoroutineScope,
private val sceneInteractor: SceneInteractor,
+ private val deviceEntryInteractor: DeviceEntryInteractor,
private val authenticationInteractor: AuthenticationInteractor,
private val keyguardInteractor: KeyguardInteractor,
private val flags: SceneContainerFlags,
@@ -119,7 +121,7 @@
/** Switches between scenes based on ever-changing application state. */
private fun automaticallySwitchScenes() {
applicationScope.launch {
- authenticationInteractor.isUnlocked
+ deviceEntryInteractor.isUnlocked
.mapNotNull { isUnlocked ->
val renderedScenes =
when (val transitionState = sceneInteractor.transitionState.value) {
@@ -130,7 +132,6 @@
transitionState.toScene,
)
}
- val isBypassEnabled = authenticationInteractor.isBypassEnabled()
when {
isUnlocked ->
when {
@@ -141,7 +142,7 @@
// When the device becomes unlocked in Lockscreen, go to Gone if
// bypass is enabled.
renderedScenes.contains(SceneKey.Lockscreen) ->
- if (isBypassEnabled) {
+ if (deviceEntryInteractor.isBypassEnabled()) {
SceneKey.Gone to
"device unlocked in Lockscreen scene with bypass"
} else {
@@ -191,7 +192,7 @@
}
WakefulnessState.STARTING_TO_WAKE -> {
val authMethod = authenticationInteractor.getAuthenticationMethod()
- val isUnlocked = authenticationInteractor.isUnlocked.value
+ val isUnlocked = deviceEntryInteractor.isUnlocked.value
when {
authMethod == AuthenticationMethodModel.None -> {
switchToScene(
@@ -241,7 +242,7 @@
/** Collects and reports signals into the falsing system. */
private fun collectFalsingSignals() {
applicationScope.launch {
- authenticationInteractor.isLockscreenDismissed.collect { isLockscreenDismissed ->
+ deviceEntryInteractor.isDeviceEntered.collect { isLockscreenDismissed ->
if (isLockscreenDismissed) {
falsingCollector.onSuccessfulUnlock()
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
index 068d5a5..9c5a201 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
@@ -16,10 +16,10 @@
package com.android.systemui.shade.ui.viewmodel
-import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.scene.shared.model.SceneKey
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -34,15 +34,15 @@
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- authenticationInteractor: AuthenticationInteractor,
+ deviceEntryInteractor: DeviceEntryInteractor,
private val bouncerInteractor: BouncerInteractor,
val shadeHeaderViewModel: ShadeHeaderViewModel,
) {
/** The key of the scene we should switch to when swiping up. */
val upDestinationSceneKey: StateFlow<SceneKey> =
combine(
- authenticationInteractor.isUnlocked,
- authenticationInteractor.canSwipeToDismiss,
+ deviceEntryInteractor.isUnlocked,
+ deviceEntryInteractor.canSwipeToEnter,
) { isUnlocked, canSwipeToDismiss ->
upDestinationSceneKey(
isUnlocked = isUnlocked,
@@ -54,8 +54,8 @@
started = SharingStarted.WhileSubscribed(),
initialValue =
upDestinationSceneKey(
- isUnlocked = authenticationInteractor.isUnlocked.value,
- canSwipeToDismiss = authenticationInteractor.canSwipeToDismiss.value,
+ isUnlocked = deviceEntryInteractor.isUnlocked.value,
+ canSwipeToDismiss = deviceEntryInteractor.canSwipeToEnter.value,
),
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 8d86d72..eedf35f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import static android.view.WindowInsets.Type.navigationBars;
+
import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
@@ -66,7 +67,6 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor;
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
import com.android.systemui.keyguard.shared.model.DismissAction;
@@ -134,7 +134,7 @@
// dranw its first frame.
private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
- private static String TAG = "StatusBarKeyguardViewManager";
+ private static final String TAG = "StatusBarKeyguardViewManager";
private static final boolean DEBUG = false;
protected final Context mContext;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index f6649bd..d54843d3 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -36,10 +36,8 @@
import com.android.internal.widget.LockPatternUtils
import com.android.keyguard.KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback
import com.android.keyguard.KeyguardSecurityModel.SecurityMode
-import com.android.systemui.res.R
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate
import com.android.systemui.biometrics.SideFpsController
import com.android.systemui.biometrics.SideFpsUiRequestSource
@@ -47,6 +45,7 @@
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.classifier.FalsingA11yDelegate
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -54,6 +53,7 @@
import com.android.systemui.log.SessionTracker
import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.res.R
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.ObservableTransitionState
@@ -157,7 +157,7 @@
private lateinit var sceneTestUtils: SceneTestUtils
private lateinit var sceneInteractor: SceneInteractor
private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
- private lateinit var authenticationInteractor: AuthenticationInteractor
+ private lateinit var deviceEntryInteractor: DeviceEntryInteractor
@Mock private lateinit var primaryBouncerInteractor: Lazy<PrimaryBouncerInteractor>
private lateinit var sceneTransitionStateFlow: MutableStateFlow<ObservableTransitionState>
@@ -229,10 +229,10 @@
sceneTransitionStateFlow =
MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Lockscreen))
sceneInteractor.setTransitionState(sceneTransitionStateFlow)
- authenticationInteractor =
- sceneTestUtils.authenticationInteractor(
- repository = sceneTestUtils.authenticationRepository(),
- sceneInteractor = sceneInteractor
+ deviceEntryInteractor =
+ sceneTestUtils.deviceEntryInteractor(
+ authenticationInteractor = sceneTestUtils.authenticationInteractor(),
+ sceneInteractor = sceneInteractor,
)
underTest =
@@ -268,7 +268,7 @@
keyguardTransitionInteractor,
primaryBouncerInteractor,
) {
- authenticationInteractor
+ deviceEntryInteractor
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
index d3a2a73..0283382 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
@@ -74,7 +74,6 @@
getSecurityMode = getSecurityMode,
backgroundDispatcher = testUtils.testDispatcher,
userRepository = userRepository,
- keyguardRepository = testUtils.keyguardRepository,
lockPatternUtils = lockPatternUtils,
broadcastDispatcher = fakeBroadcastDispatcher,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index 874053a..a102890 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -20,15 +20,12 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel
-import com.android.systemui.authentication.data.repository.AuthenticationRepository
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainLayerAuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
@@ -47,13 +44,7 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
- private val repository: AuthenticationRepository = utils.authenticationRepository()
- private val sceneInteractor = utils.sceneInteractor()
- private val underTest =
- utils.authenticationInteractor(
- repository = repository,
- sceneInteractor = sceneInteractor,
- )
+ private val underTest = utils.authenticationInteractor()
@Test
fun authenticationMethod() =
@@ -79,10 +70,10 @@
val authMethod by collectLastValue(underTest.authenticationMethod)
runCurrent()
- utils.authenticationRepository.apply {
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
- setLockscreenEnabled(true)
- }
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.None
+ )
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
assertThat(authMethod).isEqualTo(DomainLayerAuthenticationMethodModel.Swipe)
assertThat(underTest.getAuthenticationMethod())
@@ -95,10 +86,10 @@
val authMethod by collectLastValue(underTest.authenticationMethod)
runCurrent()
- utils.authenticationRepository.apply {
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
- setLockscreenEnabled(false)
- }
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.None
+ )
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(false)
assertThat(authMethod).isEqualTo(DomainLayerAuthenticationMethodModel.None)
assertThat(underTest.getAuthenticationMethod())
@@ -106,130 +97,6 @@
}
@Test
- fun isUnlocked_whenAuthMethodIsNoneAndLockscreenDisabled_isTrue() =
- testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- utils.authenticationRepository.apply {
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
- setLockscreenEnabled(false)
- // Toggle isUnlocked, twice.
- //
- // This is done because the underTest.isUnlocked flow doesn't receive values from
- // just changing the state above; the actual isUnlocked state needs to change to
- // cause the logic under test to "pick up" the current state again.
- //
- // It is done twice to make sure that we don't actually change the isUnlocked state
- // from what it originally was.
- setUnlocked(!utils.authenticationRepository.isUnlocked.value)
- runCurrent()
- setUnlocked(!utils.authenticationRepository.isUnlocked.value)
- runCurrent()
- }
-
- assertThat(isUnlocked).isTrue()
- }
-
- @Test
- fun isUnlocked_whenAuthMethodIsNoneAndLockscreenEnabled_isTrue() =
- testScope.runTest {
- utils.authenticationRepository.apply {
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
- setLockscreenEnabled(true)
- }
-
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- assertThat(isUnlocked).isTrue()
- }
-
- @Test
- fun canSwipeToDismiss_onLockscreenWithSwipe_isTrue() =
- testScope.runTest {
- utils.authenticationRepository.apply {
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
- setLockscreenEnabled(true)
- }
- switchToScene(SceneKey.Lockscreen)
-
- val canSwipeToDismiss by collectLastValue(underTest.canSwipeToDismiss)
- assertThat(canSwipeToDismiss).isTrue()
- }
-
- @Test
- fun canSwipeToDismiss_onLockscreenWithPin_isFalse() =
- testScope.runTest {
- utils.authenticationRepository.apply {
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
- setLockscreenEnabled(true)
- }
- switchToScene(SceneKey.Lockscreen)
-
- val canSwipeToDismiss by collectLastValue(underTest.canSwipeToDismiss)
- assertThat(canSwipeToDismiss).isFalse()
- }
-
- @Test
- fun canSwipeToDismiss_afterLockscreenDismissedInSwipeMode_isFalse() =
- testScope.runTest {
- utils.authenticationRepository.apply {
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
- setLockscreenEnabled(true)
- }
- switchToScene(SceneKey.Lockscreen)
- switchToScene(SceneKey.Gone)
-
- val canSwipeToDismiss by collectLastValue(underTest.canSwipeToDismiss)
- assertThat(canSwipeToDismiss).isFalse()
- }
-
- @Test
- fun isAuthenticationRequired_lockedAndSecured_true() =
- testScope.runTest {
- utils.authenticationRepository.apply {
- setUnlocked(false)
- runCurrent()
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.Password)
- }
-
- assertThat(underTest.isAuthenticationRequired()).isTrue()
- }
-
- @Test
- fun isAuthenticationRequired_lockedAndNotSecured_false() =
- testScope.runTest {
- utils.authenticationRepository.apply {
- setUnlocked(false)
- runCurrent()
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
- }
-
- assertThat(underTest.isAuthenticationRequired()).isFalse()
- }
-
- @Test
- fun isAuthenticationRequired_unlockedAndSecured_false() =
- testScope.runTest {
- utils.authenticationRepository.apply {
- setUnlocked(true)
- runCurrent()
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.Password)
- }
-
- assertThat(underTest.isAuthenticationRequired()).isFalse()
- }
-
- @Test
- fun isAuthenticationRequired_unlockedAndNotSecured_false() =
- testScope.runTest {
- utils.authenticationRepository.apply {
- setUnlocked(true)
- runCurrent()
- setAuthenticationMethod(DataLayerAuthenticationMethodModel.None)
- }
-
- assertThat(underTest.isAuthenticationRequired()).isFalse()
- }
-
- @Test
fun authenticate_withCorrectPin_returnsTrue() =
testScope.runTest {
val isThrottled by collectLastValue(underTest.isThrottled)
@@ -366,7 +233,6 @@
@Test
fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() =
testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
utils.authenticationRepository.apply {
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
setAutoConfirmEnabled(true)
@@ -378,13 +244,13 @@
)
)
.isEqualTo(AuthenticationResult.FAILED)
+ val isUnlocked by collectLastValue(utils.deviceEntryRepository.isUnlocked)
assertThat(isUnlocked).isFalse()
}
@Test
fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() =
testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
utils.authenticationRepository.apply {
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
setAutoConfirmEnabled(true)
@@ -396,13 +262,13 @@
)
)
.isEqualTo(AuthenticationResult.FAILED)
+ val isUnlocked by collectLastValue(utils.deviceEntryRepository.isUnlocked)
assertThat(isUnlocked).isFalse()
}
@Test
fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() =
testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
utils.authenticationRepository.apply {
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
setAutoConfirmEnabled(true)
@@ -414,13 +280,13 @@
)
)
.isEqualTo(AuthenticationResult.SUCCEEDED)
+ val isUnlocked by collectLastValue(utils.deviceEntryRepository.isUnlocked)
assertThat(isUnlocked).isTrue()
}
@Test
fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() =
testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
utils.authenticationRepository.apply {
setAuthenticationMethod(DataLayerAuthenticationMethodModel.Pin)
setAutoConfirmEnabled(false)
@@ -432,26 +298,27 @@
)
)
.isEqualTo(AuthenticationResult.SKIPPED)
+ val isUnlocked by collectLastValue(utils.deviceEntryRepository.isUnlocked)
assertThat(isUnlocked).isFalse()
}
@Test
fun tryAutoConfirm_withoutCorrectPassword_returnsNullAndHasNoEffects() =
testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
utils.authenticationRepository.setAuthenticationMethod(
DataLayerAuthenticationMethodModel.Password
)
assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true))
.isEqualTo(AuthenticationResult.SKIPPED)
+ val isUnlocked by collectLastValue(utils.deviceEntryRepository.isUnlocked)
assertThat(isUnlocked).isFalse()
}
@Test
fun throttling() =
testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
+ val isUnlocked by collectLastValue(utils.deviceEntryRepository.isUnlocked)
val throttling by collectLastValue(underTest.throttling)
val isThrottled by collectLastValue(underTest.isThrottled)
utils.authenticationRepository.setAuthenticationMethod(
@@ -462,7 +329,7 @@
assertThat(isThrottled).isFalse()
assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
assertThat(isUnlocked).isFalse()
assertThat(isThrottled).isFalse()
assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
@@ -605,8 +472,4 @@
assertThat(hintedPinLength).isNull()
}
-
- private fun switchToScene(sceneKey: SceneKey) {
- sceneInteractor.changeScene(SceneModel(sceneKey), "reason")
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index 92c8a39..a9ba36a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -47,13 +47,16 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = utils.authenticationRepository(),
- )
+ private val authenticationInteractor = utils.authenticationInteractor()
private val sceneInteractor = utils.sceneInteractor()
+ private val deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = authenticationInteractor,
+ sceneInteractor = sceneInteractor,
+ )
private val underTest =
utils.bouncerInteractor(
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
)
@@ -76,7 +79,7 @@
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
runCurrent()
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
@@ -111,7 +114,7 @@
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
runCurrent()
utils.authenticationRepository.setAutoConfirmEnabled(true)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
@@ -148,7 +151,7 @@
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
runCurrent()
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.clearMessage()
@@ -180,7 +183,7 @@
AuthenticationMethodModel.Password
)
runCurrent()
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PASSWORD)
@@ -215,7 +218,7 @@
AuthenticationMethodModel.Pattern
)
runCurrent()
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
@@ -268,7 +271,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(true)
+ utils.deviceEntryRepository.setUnlocked(true)
runCurrent()
underTest.showOrUnlockDevice()
@@ -281,8 +284,8 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
- utils.authenticationRepository.setLockscreenEnabled(true)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+ utils.deviceEntryRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
@@ -298,7 +301,7 @@
AuthenticationMethodModel.Password
)
runCurrent()
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
val customMessage = "Hello there!"
underTest.showOrUnlockDevice(customMessage)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index 2f7dde0..b5177e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -37,17 +37,20 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
- private val authenticationInteractor =
- utils.authenticationInteractor(
- utils.authenticationRepository(),
- )
+ private val authenticationInteractor = utils.authenticationInteractor()
private val sceneInteractor = utils.sceneInteractor()
+ private val deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = authenticationInteractor,
+ sceneInteractor = sceneInteractor,
+ )
private val underTest =
PinBouncerViewModel(
applicationContext = context,
viewModelScope = testScope.backgroundScope,
interactor =
utils.bouncerInteractor(
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index da2534d6..b75355a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
@@ -44,12 +44,15 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = utils.authenticationRepository,
+ private val authenticationInteractor = utils.authenticationInteractor()
+ private val deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = authenticationInteractor,
+ sceneInteractor = utils.sceneInteractor(),
)
private val bouncerInteractor =
utils.bouncerInteractor(
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
sceneInteractor = utils.sceneInteractor(),
)
@@ -223,6 +226,8 @@
DataLayerAuthenticationMethodModel.Pattern
}
)
- setLockscreenEnabled(model !is DomainLayerAuthenticationMethodModel.None)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(
+ model !is DomainLayerAuthenticationMethodModel.None
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index c1b3354..0926399 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -44,13 +44,16 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = utils.authenticationRepository(),
- )
+ private val authenticationInteractor = utils.authenticationInteractor()
private val sceneInteractor = utils.sceneInteractor()
+ private val deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = authenticationInteractor,
+ sceneInteractor = utils.sceneInteractor(),
+ )
private val bouncerInteractor =
utils.bouncerInteractor(
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
)
@@ -139,7 +142,7 @@
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -207,7 +210,7 @@
private fun TestScope.lockDeviceAndOpenPasswordBouncer() {
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Password)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index bf109d9..2e7c9aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -47,13 +47,16 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = utils.authenticationRepository(),
- )
+ private val authenticationInteractor = utils.authenticationInteractor()
private val sceneInteractor = utils.sceneInteractor()
+ private val deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = authenticationInteractor,
+ sceneInteractor = utils.sceneInteractor(),
+ )
private val bouncerInteractor =
utils.bouncerInteractor(
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
)
@@ -378,7 +381,7 @@
private fun TestScope.lockDeviceAndOpenPatternBouncer() {
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pattern)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(collectLastValue(sceneInteractor.desiredScene).invoke())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 2576204..255bbe3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -47,12 +47,15 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = utils.authenticationRepository(),
+ private val authenticationInteractor = utils.authenticationInteractor()
+ private val deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = authenticationInteractor,
+ sceneInteractor = utils.sceneInteractor(),
)
private val bouncerInteractor =
utils.bouncerInteractor(
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
)
@@ -81,7 +84,7 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
@@ -103,7 +106,7 @@
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
@@ -358,7 +361,7 @@
private fun TestScope.lockDeviceAndOpenPinBouncer() {
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt
new file mode 100644
index 0000000..8e8cbe4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt
@@ -0,0 +1,127 @@
+package com.android.systemui.deviceentry.data.repository
+
+import android.content.pm.UserInfo
+import androidx.test.filters.SmallTest
+import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+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.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
+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.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class DeviceEntryRepositoryTest : SysuiTestCase() {
+
+ @Mock private lateinit var lockPatternUtils: LockPatternUtils
+ @Mock private lateinit var keyguardBypassController: KeyguardBypassController
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+
+ private val testUtils = SceneTestUtils(this)
+ private val testScope = testUtils.testScope
+ private val userRepository = FakeUserRepository()
+
+ private lateinit var underTest: DeviceEntryRepository
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ userRepository.setUserInfos(USER_INFOS)
+ runBlocking { userRepository.setSelectedUserInfo(USER_INFOS[0]) }
+
+ underTest =
+ DeviceEntryRepositoryImpl(
+ applicationScope = testScope.backgroundScope,
+ backgroundDispatcher = testUtils.testDispatcher,
+ userRepository = userRepository,
+ lockPatternUtils = lockPatternUtils,
+ keyguardBypassController = keyguardBypassController,
+ keyguardStateController = keyguardStateController,
+ )
+ }
+
+ @Test
+ fun isUnlocked() =
+ testScope.runTest {
+ whenever(keyguardStateController.isUnlocked).thenReturn(false)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+
+ runCurrent()
+ assertThat(isUnlocked).isFalse()
+
+ val captor = argumentCaptor<KeyguardStateController.Callback>()
+ Mockito.verify(keyguardStateController, Mockito.atLeastOnce())
+ .addCallback(captor.capture())
+
+ whenever(keyguardStateController.isUnlocked).thenReturn(true)
+ captor.value.onUnlockedChanged()
+ runCurrent()
+ assertThat(isUnlocked).isTrue()
+
+ whenever(keyguardStateController.isUnlocked).thenReturn(false)
+ captor.value.onKeyguardShowingChanged()
+ runCurrent()
+ assertThat(isUnlocked).isFalse()
+ }
+
+ @Test
+ fun isInsecureLockscreenEnabled() =
+ testScope.runTest {
+ whenever(lockPatternUtils.isLockScreenDisabled(USER_INFOS[0].id)).thenReturn(false)
+ whenever(lockPatternUtils.isLockScreenDisabled(USER_INFOS[1].id)).thenReturn(true)
+
+ userRepository.setSelectedUserInfo(USER_INFOS[0])
+ assertThat(underTest.isInsecureLockscreenEnabled()).isTrue()
+
+ userRepository.setSelectedUserInfo(USER_INFOS[1])
+ assertThat(underTest.isInsecureLockscreenEnabled()).isFalse()
+ }
+
+ @Test
+ fun isBypassEnabled_disabledInController() =
+ testScope.runTest {
+ whenever(keyguardBypassController.isBypassEnabled).thenAnswer { false }
+ whenever(keyguardBypassController.bypassEnabled).thenAnswer { false }
+ assertThat(underTest.isBypassEnabled()).isFalse()
+ }
+
+ @Test
+ fun isBypassEnabled_enabledInController() =
+ testScope.runTest {
+ whenever(keyguardBypassController.isBypassEnabled).thenAnswer { true }
+ whenever(keyguardBypassController.bypassEnabled).thenAnswer { true }
+ assertThat(underTest.isBypassEnabled()).isTrue()
+ }
+
+ companion object {
+ private val USER_INFOS =
+ listOf(
+ UserInfo(
+ /* id= */ 100,
+ /* name= */ "First user",
+ /* flags= */ 0,
+ ),
+ UserInfo(
+ /* id= */ 101,
+ /* name= */ "Second user",
+ /* flags= */ 0,
+ ),
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
new file mode 100644
index 0000000..55582e1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
@@ -0,0 +1,234 @@
+package com.android.systemui.deviceentry.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
+import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.SceneModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class DeviceEntryInteractorTest : SysuiTestCase() {
+
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
+ private val repository: FakeDeviceEntryRepository = utils.deviceEntryRepository
+ private val sceneInteractor = utils.sceneInteractor()
+ private val authenticationInteractor = utils.authenticationInteractor()
+ private val underTest =
+ utils.deviceEntryInteractor(
+ repository = repository,
+ authenticationInteractor = authenticationInteractor,
+ sceneInteractor = sceneInteractor,
+ )
+
+ @Test
+ fun isUnlocked_whenAuthMethodIsNoneAndLockscreenDisabled_isTrue() =
+ testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.deviceEntryRepository.apply {
+ setInsecureLockscreenEnabled(false)
+
+ // Toggle isUnlocked, twice.
+ //
+ // This is done because the underTest.isUnlocked flow doesn't receive values from
+ // just changing the state above; the actual isUnlocked state needs to change to
+ // cause the logic under test to "pick up" the current state again.
+ //
+ // It is done twice to make sure that we don't actually change the isUnlocked state
+ // from what it originally was.
+ setUnlocked(!isUnlocked.value)
+ runCurrent()
+ setUnlocked(!isUnlocked.value)
+ runCurrent()
+ }
+
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ assertThat(isUnlocked).isTrue()
+ }
+
+ @Test
+ fun isUnlocked_whenAuthMethodIsNoneAndLockscreenEnabled_isTrue() =
+ testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ assertThat(isUnlocked).isTrue()
+ }
+
+ @Test
+ fun isDeviceEntered_onLockscreenWithSwipe_isFalse() =
+ testScope.runTest {
+ val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+ switchToScene(SceneKey.Lockscreen)
+
+ assertThat(isDeviceEntered).isFalse()
+ }
+
+ @Test
+ fun isDeviceEntered_onShadeBeforeDismissingLockscreenWithSwipe_isFalse() =
+ testScope.runTest {
+ val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+ switchToScene(SceneKey.Lockscreen)
+ runCurrent()
+ switchToScene(SceneKey.Shade)
+
+ assertThat(isDeviceEntered).isFalse()
+ }
+
+ @Test
+ fun isDeviceEntered_afterDismissingLockscreenWithSwipe_isTrue() =
+ testScope.runTest {
+ val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+ switchToScene(SceneKey.Lockscreen)
+ runCurrent()
+ switchToScene(SceneKey.Gone)
+
+ assertThat(isDeviceEntered).isTrue()
+ }
+
+ @Test
+ fun isDeviceEntered_onShadeAfterDismissingLockscreenWithSwipe_isTrue() =
+ testScope.runTest {
+ val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+ switchToScene(SceneKey.Lockscreen)
+ runCurrent()
+ switchToScene(SceneKey.Gone)
+ runCurrent()
+ switchToScene(SceneKey.Shade)
+
+ assertThat(isDeviceEntered).isTrue()
+ }
+
+ @Test
+ fun isDeviceEntered_onBouncer_isFalse() =
+ testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pattern
+ )
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+ switchToScene(SceneKey.Lockscreen)
+ runCurrent()
+ switchToScene(SceneKey.Bouncer)
+
+ val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
+ assertThat(isDeviceEntered).isFalse()
+ }
+
+ @Test
+ fun canSwipeToEnter_onLockscreenWithSwipe_isTrue() =
+ testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+ switchToScene(SceneKey.Lockscreen)
+
+ val canSwipeToEnter by collectLastValue(underTest.canSwipeToEnter)
+ assertThat(canSwipeToEnter).isTrue()
+ }
+
+ @Test
+ fun canSwipeToEnter_onLockscreenWithPin_isFalse() =
+ testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+ switchToScene(SceneKey.Lockscreen)
+
+ val canSwipeToEnter by collectLastValue(underTest.canSwipeToEnter)
+ assertThat(canSwipeToEnter).isFalse()
+ }
+
+ @Test
+ fun canSwipeToEnter_afterLockscreenDismissedInSwipeMode_isFalse() =
+ testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+ switchToScene(SceneKey.Lockscreen)
+ runCurrent()
+ switchToScene(SceneKey.Gone)
+
+ val canSwipeToEnter by collectLastValue(underTest.canSwipeToEnter)
+ assertThat(canSwipeToEnter).isFalse()
+ }
+
+ @Test
+ fun isAuthenticationRequired_lockedAndSecured_true() =
+ testScope.runTest {
+ utils.deviceEntryRepository.setUnlocked(false)
+ runCurrent()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password
+ )
+
+ assertThat(underTest.isAuthenticationRequired()).isTrue()
+ }
+
+ @Test
+ fun isAuthenticationRequired_lockedAndNotSecured_false() =
+ testScope.runTest {
+ utils.deviceEntryRepository.setUnlocked(false)
+ runCurrent()
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+
+ assertThat(underTest.isAuthenticationRequired()).isFalse()
+ }
+
+ @Test
+ fun isAuthenticationRequired_unlockedAndSecured_false() =
+ testScope.runTest {
+ utils.deviceEntryRepository.setUnlocked(true)
+ runCurrent()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password
+ )
+
+ assertThat(underTest.isAuthenticationRequired()).isFalse()
+ }
+
+ @Test
+ fun isAuthenticationRequired_unlockedAndNotSecured_false() =
+ testScope.runTest {
+ utils.deviceEntryRepository.setUnlocked(true)
+ runCurrent()
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+
+ assertThat(underTest.isAuthenticationRequired()).isFalse()
+ }
+
+ @Test
+ fun isBypassEnabled_enabledInRepository_true() =
+ testScope.runTest {
+ utils.deviceEntryRepository.setBypassEnabled(true)
+ assertThat(underTest.isBypassEnabled()).isTrue()
+ }
+
+ @Test
+ fun isBypassEnabled_disabledInRepository_false() =
+ testScope.runTest {
+ utils.deviceEntryRepository.setBypassEnabled(false)
+ assertThat(underTest.isBypassEnabled()).isFalse()
+ }
+
+ private fun switchToScene(sceneKey: SceneKey) {
+ sceneInteractor.changeScene(SceneModel(sceneKey), "reason")
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 2691860..f93051c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -44,7 +44,6 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
@@ -81,7 +80,6 @@
@Mock private lateinit var biometricUnlockController: BiometricUnlockController
@Mock private lateinit var dozeTransitionListener: DozeTransitionListener
@Mock private lateinit var authController: AuthController
- @Mock private lateinit var keyguardBypassController: KeyguardBypassController
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var dreamOverlayCallbackController: DreamOverlayCallbackController
@Mock private lateinit var dozeParameters: DozeParameters
@@ -103,7 +101,6 @@
screenLifecycle,
biometricUnlockController,
keyguardStateController,
- keyguardBypassController,
keyguardUpdateMonitor,
dozeTransitionListener,
dozeParameters,
@@ -213,23 +210,9 @@
}
@Test
- fun isBypassEnabled_disabledInController() {
- whenever(keyguardBypassController.isBypassEnabled).thenReturn(false)
- whenever(keyguardBypassController.bypassEnabled).thenReturn(false)
- assertThat(underTest.isBypassEnabled()).isFalse()
- }
-
- @Test
- fun isBypassEnabled_enabledInController() {
- whenever(keyguardBypassController.isBypassEnabled).thenReturn(true)
- whenever(keyguardBypassController.bypassEnabled).thenReturn(true)
- assertThat(underTest.isBypassEnabled()).isTrue()
- }
-
- @Test
fun isAodAvailable() = runTest {
val flow = underTest.isAodAvailable
- var isAodAvailable = collectLastValue(flow)
+ val isAodAvailable = collectLastValue(flow)
runCurrent()
val callback =
@@ -273,29 +256,6 @@
}
@Test
- fun isKeyguardUnlocked() =
- testScope.runTest {
- whenever(keyguardStateController.isUnlocked).thenReturn(false)
- val isKeyguardUnlocked by collectLastValue(underTest.isKeyguardUnlocked)
-
- runCurrent()
- assertThat(isKeyguardUnlocked).isFalse()
-
- val captor = argumentCaptor<KeyguardStateController.Callback>()
- verify(keyguardStateController, atLeastOnce()).addCallback(captor.capture())
-
- whenever(keyguardStateController.isUnlocked).thenReturn(true)
- captor.value.onUnlockedChanged()
- runCurrent()
- assertThat(isKeyguardUnlocked).isTrue()
-
- whenever(keyguardStateController.isUnlocked).thenReturn(false)
- captor.value.onKeyguardShowingChanged()
- runCurrent()
- assertThat(isKeyguardUnlocked).isFalse()
- }
-
- @Test
fun isDozing() =
testScope.runTest {
underTest.setIsDozing(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 90e217f..82c7fa4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -15,8 +15,6 @@
*
*/
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
package com.android.systemui.keyguard.domain.interactor
import android.app.StatusBarManager
@@ -27,13 +25,11 @@
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.shade.data.repository.FakeShadeRepository
@@ -42,62 +38,53 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.onCompletion
-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.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RoboPilotTest
@RunWith(AndroidJUnit4::class)
class KeyguardInteractorTest : SysuiTestCase() {
- private lateinit var commandQueue: FakeCommandQueue
- private lateinit var featureFlags: FakeFeatureFlags
- private lateinit var testScope: TestScope
- private lateinit var underTest: KeyguardInteractor
- private lateinit var repository: FakeKeyguardRepository
- private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
- private lateinit var configurationRepository: FakeConfigurationRepository
- private lateinit var shadeRepository: FakeShadeRepository
- private lateinit var sceneInteractor: SceneInteractor
- private lateinit var transitionState: MutableStateFlow<ObservableTransitionState>
+ private val testUtils = SceneTestUtils(this)
+ private val testScope = testUtils.testScope
+ private val repository = testUtils.keyguardRepository
+ private val sceneInteractor = testUtils.sceneInteractor()
+ private val commandQueue = FakeCommandQueue()
+ private val featureFlags = FakeFeatureFlagsClassic().apply { set(FACE_AUTH_REFACTOR, true) }
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val configurationRepository = FakeConfigurationRepository()
+ private val shadeRepository = FakeShadeRepository()
+ private val transitionState: MutableStateFlow<ObservableTransitionState> =
+ MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Gone))
+
+ private val underTest =
+ KeyguardInteractor(
+ repository = repository,
+ commandQueue = commandQueue,
+ featureFlags = featureFlags,
+ sceneContainerFlags = testUtils.sceneContainerFlags,
+ deviceEntryRepository = testUtils.deviceEntryRepository,
+ bouncerRepository = bouncerRepository,
+ configurationRepository = configurationRepository,
+ shadeRepository = shadeRepository,
+ sceneInteractorProvider = { sceneInteractor },
+ )
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
- featureFlags = FakeFeatureFlags().apply { set(FACE_AUTH_REFACTOR, true) }
- commandQueue = FakeCommandQueue()
- val sceneTestUtils = SceneTestUtils(this)
- testScope = sceneTestUtils.testScope
- repository = sceneTestUtils.keyguardRepository
- bouncerRepository = FakeKeyguardBouncerRepository()
- configurationRepository = FakeConfigurationRepository()
- shadeRepository = FakeShadeRepository()
- sceneInteractor = sceneTestUtils.sceneInteractor()
- transitionState = MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Gone))
sceneInteractor.setTransitionState(transitionState)
- underTest =
- KeyguardInteractor(
- repository = repository,
- commandQueue = commandQueue,
- featureFlags = featureFlags,
- sceneContainerFlags = sceneTestUtils.sceneContainerFlags,
- bouncerRepository = bouncerRepository,
- configurationRepository = configurationRepository,
- shadeRepository = shadeRepository,
- sceneInteractorProvider = { sceneInteractor },
- )
}
@Test
fun onCameraLaunchDetected() =
testScope.runTest {
val flow = underTest.onCameraLaunchDetected
- var cameraLaunchSource = collectLastValue(flow)
+ val cameraLaunchSource = collectLastValue(flow)
runCurrent()
commandQueue.doForEachCallback {
@@ -175,7 +162,7 @@
@Test
fun keyguardVisibilityIsDefinedAsKeyguardShowingButNotOccluded() = runTest {
- var isVisible = collectLastValue(underTest.isKeyguardVisible)
+ val isVisible = collectLastValue(underTest.isKeyguardVisible)
repository.setKeyguardShowing(true)
repository.setKeyguardOccluded(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index f2636c5..591653e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -1226,7 +1226,6 @@
// GIVEN the keyguard is showing locked
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
- keyguardRepository.setKeyguardUnlocked(false)
runCurrent()
shadeRepository.setShadeModel(
ShadeModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index 1681cfd..6e94691 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -37,10 +37,6 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = utils.authenticationRepository(),
- )
private val underTest = createLockscreenSceneViewModel()
@@ -49,8 +45,8 @@
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
- utils.authenticationRepository.setLockscreenEnabled(true)
- utils.authenticationRepository.setUnlocked(true)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
+ utils.deviceEntryRepository.setUnlocked(true)
sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen), "reason")
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
@@ -61,7 +57,7 @@
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen), "reason")
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
@@ -88,7 +84,11 @@
private fun createLockscreenSceneViewModel(): LockscreenSceneViewModel {
return LockscreenSceneViewModel(
applicationScope = testScope.backgroundScope,
- authenticationInteractor = authenticationInteractor,
+ deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = utils.authenticationInteractor(),
+ sceneInteractor = utils.sceneInteractor(),
+ ),
communalInteractor = utils.communalInteractor(),
longPress =
KeyguardLongPressViewModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index 8ae8930..f1c99d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -48,11 +48,6 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = utils.authenticationRepository(),
- )
-
private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
private var mobileIconsViewModel: MobileIconsViewModel =
@@ -85,10 +80,17 @@
broadcastDispatcher = fakeBroadcastDispatcher,
)
+ val authenticationInteractor = utils.authenticationInteractor()
+
underTest =
QuickSettingsSceneViewModel(
bouncerInteractor =
utils.bouncerInteractor(
+ deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = authenticationInteractor,
+ sceneInteractor = sceneInteractor,
+ ),
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
),
@@ -101,7 +103,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(true)
+ utils.deviceEntryRepository.setUnlocked(true)
runCurrent()
underTest.onContentClicked()
@@ -114,7 +116,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
runCurrent()
underTest.onContentClicked()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 85bd92b..5259013 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -83,7 +83,6 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
-
private val sceneContainerConfig = utils.fakeSceneContainerConfig()
private val sceneRepository =
utils.fakeSceneContainerRepository(
@@ -93,14 +92,12 @@
utils.sceneInteractor(
repository = sceneRepository,
)
-
- private val authenticationRepository = utils.authenticationRepository()
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = authenticationRepository,
+ private val authenticationInteractor = utils.authenticationInteractor()
+ private val deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
)
-
private val communalInteractor = utils.communalInteractor()
private val transitionState =
@@ -116,6 +113,7 @@
private val bouncerInteractor =
utils.bouncerInteractor(
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
)
@@ -128,7 +126,7 @@
private val lockscreenSceneViewModel =
LockscreenSceneViewModel(
applicationScope = testScope.backgroundScope,
- authenticationInteractor = authenticationInteractor,
+ deviceEntryInteractor = deviceEntryInteractor,
communalInteractor = communalInteractor,
longPress =
KeyguardLongPressViewModel(
@@ -178,12 +176,12 @@
shadeSceneViewModel =
ShadeSceneViewModel(
applicationScope = testScope.backgroundScope,
- authenticationInteractor = authenticationInteractor,
+ deviceEntryInteractor = deviceEntryInteractor,
bouncerInteractor = bouncerInteractor,
shadeHeaderViewModel = shadeHeaderViewModel,
)
- authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
val displayTracker = FakeDisplayTracker(context)
val sysUiState = SysUiState(displayTracker)
@@ -191,6 +189,7 @@
SceneContainerStartable(
applicationScope = testScope.backgroundScope,
sceneInteractor = sceneInteractor,
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
keyguardInteractor = keyguardInteractor,
flags = utils.sceneContainerFlags,
@@ -417,13 +416,13 @@
// Set the lockscreen enabled bit _before_ set the auth method as the code picks up on the
// lockscreen enabled bit _after_ the auth method is changed and the lockscreen enabled bit
// is not an observable that can trigger a new evaluation.
- authenticationRepository.setLockscreenEnabled(
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(
authMethod !is DomainLayerAuthenticationMethodModel.None
)
- authenticationRepository.setAuthenticationMethod(authMethod.toDataLayer())
+ utils.authenticationRepository.setAuthenticationMethod(authMethod.toDataLayer())
if (!authMethod.isSecure) {
// When the auth method is not secure, the device is never considered locked.
- authenticationRepository.setUnlocked(true)
+ utils.deviceEntryRepository.setUnlocked(true)
}
runCurrent()
}
@@ -528,14 +527,14 @@
.that(authMethod.isSecure)
.isTrue()
- authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
runCurrent()
}
/** Unlocks the device by entering the correct PIN. Ends up in the Gone scene. */
private fun TestScope.unlockDevice() {
assertWithMessage("Cannot unlock a device that's already unlocked!")
- .that(authenticationInteractor.isUnlocked.value)
+ .that(deviceEntryInteractor.isUnlocked.value)
.isFalse()
emulateUserDrivenTransition(SceneKey.Bouncer)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 16fdf8e..00a20cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -59,17 +59,13 @@
private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val sceneContainerFlags = utils.sceneContainerFlags
- private val authenticationRepository = utils.authenticationRepository()
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = authenticationRepository,
+ private val authenticationInteractor = utils.authenticationInteractor()
+ private val deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
)
- private val keyguardRepository = utils.keyguardRepository
- private val keyguardInteractor =
- utils.keyguardInteractor(
- repository = keyguardRepository,
- )
+ private val keyguardInteractor = utils.keyguardInteractor()
private val sysUiState: SysUiState = mock()
private val falsingCollector: FalsingCollector = mock()
@@ -77,6 +73,7 @@
SceneContainerStartable(
applicationScope = testScope.backgroundScope,
sceneInteractor = sceneInteractor,
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
keyguardInteractor = keyguardInteractor,
flags = sceneContainerFlags,
@@ -141,7 +138,7 @@
assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
underTest.start()
- authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
}
@@ -157,7 +154,7 @@
assertThat(currentSceneKey).isEqualTo(SceneKey.Bouncer)
underTest.start()
- authenticationRepository.setUnlocked(true)
+ utils.deviceEntryRepository.setUnlocked(true)
assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
}
@@ -173,7 +170,7 @@
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
underTest.start()
- authenticationRepository.setUnlocked(true)
+ utils.deviceEntryRepository.setUnlocked(true)
assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
}
@@ -189,7 +186,7 @@
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
underTest.start()
- authenticationRepository.setUnlocked(true)
+ utils.deviceEntryRepository.setUnlocked(true)
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
}
@@ -205,7 +202,7 @@
assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
underTest.start()
- keyguardRepository.setWakefulnessModel(STARTING_TO_SLEEP)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_SLEEP)
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
}
@@ -251,7 +248,7 @@
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
underTest.start()
- keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
}
@@ -267,7 +264,7 @@
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
underTest.start()
- keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
}
@@ -283,7 +280,7 @@
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
underTest.start()
- keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
}
@@ -300,9 +297,9 @@
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
underTest.start()
- authenticationRepository.setUnlocked(true)
+ utils.deviceEntryRepository.setUnlocked(true)
runCurrent()
- keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
}
@@ -389,11 +386,11 @@
runCurrent()
verify(falsingCollector).setShowingAod(false)
- keyguardRepository.setIsDozing(true)
+ utils.keyguardRepository.setIsDozing(true)
runCurrent()
verify(falsingCollector).setShowingAod(true)
- keyguardRepository.setIsDozing(false)
+ utils.keyguardRepository.setIsDozing(false)
runCurrent()
verify(falsingCollector, times(2)).setShowingAod(false)
}
@@ -401,7 +398,7 @@
@Test
fun collectFalsingSignals_screenOnAndOff_aodUnavailable() =
testScope.runTest {
- keyguardRepository.setAodAvailable(false)
+ utils.keyguardRepository.setAodAvailable(false)
runCurrent()
prepareState(
initialSceneKey = SceneKey.Lockscreen,
@@ -414,31 +411,31 @@
verify(falsingCollector, never()).onScreenOnFromTouch()
verify(falsingCollector, never()).onScreenOff()
- keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
runCurrent()
verify(falsingCollector, times(1)).onScreenTurningOn()
verify(falsingCollector, never()).onScreenOnFromTouch()
verify(falsingCollector, never()).onScreenOff()
- keyguardRepository.setWakefulnessModel(ASLEEP)
+ utils.keyguardRepository.setWakefulnessModel(ASLEEP)
runCurrent()
verify(falsingCollector, times(1)).onScreenTurningOn()
verify(falsingCollector, never()).onScreenOnFromTouch()
verify(falsingCollector, times(1)).onScreenOff()
- keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_TAP)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_TAP)
runCurrent()
verify(falsingCollector, times(1)).onScreenTurningOn()
verify(falsingCollector, times(1)).onScreenOnFromTouch()
verify(falsingCollector, times(1)).onScreenOff()
- keyguardRepository.setWakefulnessModel(ASLEEP)
+ utils.keyguardRepository.setWakefulnessModel(ASLEEP)
runCurrent()
verify(falsingCollector, times(1)).onScreenTurningOn()
verify(falsingCollector, times(1)).onScreenOnFromTouch()
verify(falsingCollector, times(2)).onScreenOff()
- keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
runCurrent()
verify(falsingCollector, times(2)).onScreenTurningOn()
verify(falsingCollector, times(1)).onScreenOnFromTouch()
@@ -448,7 +445,7 @@
@Test
fun collectFalsingSignals_screenOnAndOff_aodAvailable() =
testScope.runTest {
- keyguardRepository.setAodAvailable(true)
+ utils.keyguardRepository.setAodAvailable(true)
runCurrent()
prepareState(
initialSceneKey = SceneKey.Lockscreen,
@@ -461,31 +458,31 @@
verify(falsingCollector, never()).onScreenOnFromTouch()
verify(falsingCollector, never()).onScreenOff()
- keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
runCurrent()
verify(falsingCollector, never()).onScreenTurningOn()
verify(falsingCollector, never()).onScreenOnFromTouch()
verify(falsingCollector, never()).onScreenOff()
- keyguardRepository.setWakefulnessModel(ASLEEP)
+ utils.keyguardRepository.setWakefulnessModel(ASLEEP)
runCurrent()
verify(falsingCollector, never()).onScreenTurningOn()
verify(falsingCollector, never()).onScreenOnFromTouch()
verify(falsingCollector, never()).onScreenOff()
- keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_TAP)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_TAP)
runCurrent()
verify(falsingCollector, never()).onScreenTurningOn()
verify(falsingCollector, never()).onScreenOnFromTouch()
verify(falsingCollector, never()).onScreenOff()
- keyguardRepository.setWakefulnessModel(ASLEEP)
+ utils.keyguardRepository.setWakefulnessModel(ASLEEP)
runCurrent()
verify(falsingCollector, never()).onScreenTurningOn()
verify(falsingCollector, never()).onScreenOnFromTouch()
verify(falsingCollector, never()).onScreenOff()
- keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+ utils.keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
runCurrent()
verify(falsingCollector, never()).onScreenTurningOn()
verify(falsingCollector, never()).onScreenOnFromTouch()
@@ -521,8 +518,8 @@
): MutableStateFlow<ObservableTransitionState> {
assumeTrue(Flags.SCENE_CONTAINER_ENABLED)
sceneContainerFlags.enabled = true
- authenticationRepository.setUnlocked(isDeviceUnlocked)
- keyguardRepository.setBypassEnabled(isBypassEnabled)
+ utils.deviceEntryRepository.setUnlocked(isDeviceUnlocked)
+ utils.deviceEntryRepository.setBypassEnabled(isBypassEnabled)
val transitionStateFlow =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(SceneKey.Lockscreen)
@@ -534,8 +531,10 @@
sceneInteractor.onSceneChanged(SceneModel(it), "reason")
}
authenticationMethod?.let {
- authenticationRepository.setAuthenticationMethod(authenticationMethod.toDataLayer())
- authenticationRepository.setLockscreenEnabled(
+ utils.authenticationRepository.setAuthenticationMethod(
+ authenticationMethod.toDataLayer()
+ )
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(
authenticationMethod != AuthenticationMethodModel.None
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 5c75d9c..602bd5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -47,9 +47,10 @@
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = utils.authenticationRepository(),
+ private val authenticationInteractor = utils.authenticationInteractor()
+ private val deviceEntryInteractor =
+ utils.deviceEntryInteractor(
+ authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
)
@@ -88,9 +89,10 @@
underTest =
ShadeSceneViewModel(
applicationScope = testScope.backgroundScope,
- authenticationInteractor = authenticationInteractor,
+ deviceEntryInteractor = deviceEntryInteractor,
bouncerInteractor =
utils.bouncerInteractor(
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
),
@@ -103,7 +105,7 @@
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
}
@@ -113,7 +115,7 @@
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(true)
+ utils.deviceEntryRepository.setUnlocked(true)
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
}
@@ -122,7 +124,7 @@
fun upTransitionSceneKey_authMethodSwipe_lockscreenNotDismissed_goesToLockscreen() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- utils.authenticationRepository.setLockscreenEnabled(true)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen), "reason")
@@ -134,7 +136,7 @@
fun upTransitionSceneKey_authMethodSwipe_lockscreenDismissed_goesToGone() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- utils.authenticationRepository.setLockscreenEnabled(true)
+ utils.deviceEntryRepository.setInsecureLockscreenEnabled(true)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
sceneInteractor.changeScene(SceneModel(SceneKey.Gone), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone), "reason")
@@ -147,7 +149,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(true)
+ utils.deviceEntryRepository.setUnlocked(true)
runCurrent()
underTest.onContentClicked()
@@ -160,7 +162,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
+ utils.deviceEntryRepository.setUnlocked(false)
runCurrent()
underTest.onContentClicked()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
index f2e4528..4fc3e3f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
@@ -24,20 +24,19 @@
import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
import com.android.systemui.authentication.shared.model.AuthenticationResultModel
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
class FakeAuthenticationRepository(
+ private val deviceEntryRepository: FakeDeviceEntryRepository,
private val currentTime: () -> Long,
) : AuthenticationRepository {
private val _isAutoConfirmEnabled = MutableStateFlow(false)
override val isAutoConfirmEnabled: StateFlow<Boolean> = _isAutoConfirmEnabled.asStateFlow()
- private val _isUnlocked = MutableStateFlow(false)
- override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
-
override val hintedPinLength: Int = HINTING_PIN_LENGTH
private val _isPatternVisible = MutableStateFlow(true)
@@ -53,7 +52,6 @@
override val minPatternLength: Int = 4
- private var isLockscreenEnabled = true
private var failedAttemptCount = 0
private var throttlingEndTimestamp = 0L
private var credentialOverride: List<Any>? = null
@@ -72,13 +70,9 @@
credentialOverride = pin
}
- override suspend fun isLockscreenEnabled(): Boolean {
- return isLockscreenEnabled
- }
-
override suspend fun reportAuthenticationAttempt(isSuccessful: Boolean) {
failedAttemptCount = if (isSuccessful) 0 else failedAttemptCount + 1
- _isUnlocked.value = isSuccessful
+ deviceEntryRepository.setUnlocked(isSuccessful)
}
override suspend fun getPinLength(): Int {
@@ -97,18 +91,10 @@
_throttling.value = throttlingModel
}
- fun setUnlocked(isUnlocked: Boolean) {
- _isUnlocked.value = isUnlocked
- }
-
fun setAutoConfirmEnabled(isEnabled: Boolean) {
_isAutoConfirmEnabled.value = isEnabled
}
- fun setLockscreenEnabled(isLockscreenEnabled: Boolean) {
- this.isLockscreenEnabled = isLockscreenEnabled
- }
-
override suspend fun setThrottleDuration(durationMs: Int) {
throttlingEndTimestamp = if (durationMs > 0) currentTime() + durationMs else 0
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
new file mode 100644
index 0000000..5e60a09
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
@@ -0,0 +1,35 @@
+package com.android.systemui.deviceentry.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+/** Fake implementation of [DeviceEntryRepository] */
+class FakeDeviceEntryRepository : DeviceEntryRepository {
+
+ private var isInsecureLockscreenEnabled = true
+ private var isBypassEnabled = false
+
+ private val _isUnlocked = MutableStateFlow(false)
+ override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
+
+ override fun isBypassEnabled(): Boolean {
+ return isBypassEnabled
+ }
+
+ override suspend fun isInsecureLockscreenEnabled(): Boolean {
+ return isInsecureLockscreenEnabled
+ }
+
+ fun setUnlocked(isUnlocked: Boolean) {
+ _isUnlocked.value = isUnlocked
+ }
+
+ fun setInsecureLockscreenEnabled(isLockscreenEnabled: Boolean) {
+ this.isInsecureLockscreenEnabled = isLockscreenEnabled
+ }
+
+ fun setBypassEnabled(isBypassEnabled: Boolean) {
+ this.isBypassEnabled = isBypassEnabled
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index a5f5d52..aa52609 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -63,9 +63,6 @@
private val _isKeyguardShowing = MutableStateFlow(false)
override val isKeyguardShowing: Flow<Boolean> = _isKeyguardShowing
- private val _isKeyguardUnlocked = MutableStateFlow(false)
- override val isKeyguardUnlocked: StateFlow<Boolean> = _isKeyguardUnlocked.asStateFlow()
-
private val _isKeyguardOccluded = MutableStateFlow(false)
override val isKeyguardOccluded: Flow<Boolean> = _isKeyguardOccluded
@@ -150,11 +147,6 @@
return _isKeyguardShowing.value
}
- private var _isBypassEnabled = false
- override fun isBypassEnabled(): Boolean {
- return _isBypassEnabled
- }
-
override fun setAnimateDozingTransitions(animate: Boolean) {
_animateBottomAreaDozingTransitions.tryEmit(animate)
}
@@ -252,14 +244,6 @@
_statusBarState.value = state
}
- fun setKeyguardUnlocked(isUnlocked: Boolean) {
- _isKeyguardUnlocked.value = isUnlocked
- }
-
- fun setBypassEnabled(isEnabled: Boolean) {
- _isBypassEnabled = isEnabled
- }
-
fun setScreenModel(screenModel: ScreenModel) {
_screenModel.value = screenModel
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index 2e3bb2b..1cae09b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -19,6 +19,7 @@
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
@@ -42,6 +43,7 @@
sceneContainerFlags: SceneContainerFlags = FakeSceneContainerFlags(),
repository: FakeKeyguardRepository = FakeKeyguardRepository(),
commandQueue: FakeCommandQueue = FakeCommandQueue(),
+ deviceEntryRepository: FakeDeviceEntryRepository = FakeDeviceEntryRepository(),
bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
configurationRepository: FakeConfigurationRepository = FakeConfigurationRepository(),
shadeRepository: FakeShadeRepository = FakeShadeRepository(),
@@ -52,6 +54,7 @@
commandQueue = commandQueue,
featureFlags = featureFlags,
sceneContainerFlags = sceneContainerFlags,
+ deviceEntryRepository = deviceEntryRepository,
bouncerRepository = bouncerRepository,
configurationRepository = configurationRepository,
shadeRepository = shadeRepository,
@@ -60,6 +63,7 @@
commandQueue = commandQueue,
featureFlags = featureFlags,
sceneContainerFlags = sceneContainerFlags,
+ deviceEntryRepository = deviceEntryRepository,
bouncerRepository = bouncerRepository,
configurationRepository = configurationRepository,
shadeRepository = shadeRepository,
@@ -69,7 +73,7 @@
}
/** Provide defaults, otherwise tests will throw an error */
- fun createFakeFeatureFlags(): FakeFeatureFlags {
+ private fun createFakeFeatureFlags(): FakeFeatureFlags {
return FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
}
@@ -78,6 +82,7 @@
val commandQueue: FakeCommandQueue,
val featureFlags: FakeFeatureFlags,
val sceneContainerFlags: SceneContainerFlags,
+ val deviceEntryRepository: FakeDeviceEntryRepository,
val bouncerRepository: FakeKeyguardBouncerRepository,
val configurationRepository: FakeConfigurationRepository,
val shadeRepository: FakeShadeRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 69c89e8..179206f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -34,6 +34,9 @@
import com.android.systemui.communal.data.repository.FakeCommunalRepository
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
@@ -73,16 +76,10 @@
val testScope = TestScope(testDispatcher)
val featureFlags = FakeFeatureFlagsClassic().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
val sceneContainerFlags = FakeSceneContainerFlags().apply { enabled = true }
- private val userRepository: UserRepository by lazy {
- FakeUserRepository().apply {
- val users = listOf(UserInfo(/* id= */ 0, "name", /* flags= */ 0))
- setUserInfos(users)
- runBlocking { setSelectedUserInfo(users.first()) }
- }
- }
-
+ val deviceEntryRepository: FakeDeviceEntryRepository by lazy { FakeDeviceEntryRepository() }
val authenticationRepository: FakeAuthenticationRepository by lazy {
FakeAuthenticationRepository(
+ deviceEntryRepository = deviceEntryRepository,
currentTime = { testScope.currentTime },
)
}
@@ -103,6 +100,14 @@
}
val powerRepository: FakePowerRepository by lazy { FakePowerRepository() }
+ private val userRepository: UserRepository by lazy {
+ FakeUserRepository().apply {
+ val users = listOf(UserInfo(/* id= */ 0, "name", /* flags= */ 0))
+ setUserInfos(users)
+ runBlocking { setSelectedUserInfo(users.first()) }
+ }
+ }
+
private val context = test.context
private val falsingCollectorFake: FalsingCollector by lazy { FalsingCollectorFake() }
@@ -145,31 +150,41 @@
)
}
- fun authenticationRepository(): FakeAuthenticationRepository {
- return authenticationRepository
+ fun deviceEntryInteractor(
+ repository: DeviceEntryRepository = deviceEntryRepository,
+ authenticationInteractor: AuthenticationInteractor,
+ sceneInteractor: SceneInteractor,
+ ): DeviceEntryInteractor {
+ return DeviceEntryInteractor(
+ applicationScope = applicationScope(),
+ repository = repository,
+ authenticationInteractor = authenticationInteractor,
+ sceneInteractor = sceneInteractor,
+ )
}
fun authenticationInteractor(
- repository: AuthenticationRepository,
- sceneInteractor: SceneInteractor = sceneInteractor(),
+ repository: AuthenticationRepository = authenticationRepository,
): AuthenticationInteractor {
return AuthenticationInteractor(
applicationScope = applicationScope(),
repository = repository,
backgroundDispatcher = testDispatcher,
userRepository = userRepository,
- keyguardRepository = keyguardRepository,
- sceneInteractor = sceneInteractor,
+ deviceEntryRepository = deviceEntryRepository,
clock = mock { whenever(elapsedRealtime()).thenAnswer { testScope.currentTime } }
)
}
- fun keyguardInteractor(repository: KeyguardRepository): KeyguardInteractor {
+ fun keyguardInteractor(
+ repository: KeyguardRepository = keyguardRepository
+ ): KeyguardInteractor {
return KeyguardInteractor(
repository = repository,
commandQueue = FakeCommandQueue(),
featureFlags = featureFlags,
sceneContainerFlags = sceneContainerFlags,
+ deviceEntryRepository = FakeDeviceEntryRepository(),
bouncerRepository = FakeKeyguardBouncerRepository(),
configurationRepository = FakeConfigurationRepository(),
shadeRepository = FakeShadeRepository(),
@@ -185,6 +200,7 @@
}
fun bouncerInteractor(
+ deviceEntryInteractor: DeviceEntryInteractor,
authenticationInteractor: AuthenticationInteractor,
sceneInteractor: SceneInteractor,
): BouncerInteractor {
@@ -192,6 +208,7 @@
applicationScope = applicationScope(),
applicationContext = context,
repository = BouncerRepository(),
+ deviceEntryInteractor = deviceEntryInteractor,
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
flags = sceneContainerFlags,