summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt39
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt98
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt1
6 files changed, 96 insertions, 116 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 9e83cc12d198..4553a56f599c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -68,6 +68,7 @@ import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.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;
@@ -81,8 +82,6 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.scene.domain.interactor.SceneInteractor;
-import com.android.systemui.scene.shared.model.SceneKey;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -400,7 +399,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
};
private final UserInteractor mUserInteractor;
- private final Provider<SceneInteractor> mSceneInteractor;
+ private final Provider<AuthenticationInteractor> mAuthenticationInteractor;
private final Provider<JavaAdapter> mJavaAdapter;
@Nullable private Job mSceneTransitionCollectionJob;
@@ -431,8 +430,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
Provider<JavaAdapter> javaAdapter,
UserInteractor userInteractor,
FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate,
- Provider<SceneInteractor> sceneInteractor,
- KeyguardTransitionInteractor keyguardTransitionInteractor
+ KeyguardTransitionInteractor keyguardTransitionInteractor,
+ Provider<AuthenticationInteractor> authenticationInteractor
) {
super(view);
view.setAccessibilityDelegate(faceAuthAccessibilityDelegate);
@@ -461,7 +460,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
mBouncerMessageInteractor = bouncerMessageInteractor;
mUserInteractor = userInteractor;
- mSceneInteractor = sceneInteractor;
+ mAuthenticationInteractor = authenticationInteractor;
mJavaAdapter = javaAdapter;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
}
@@ -488,19 +487,21 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
showPrimarySecurityScreen(false);
if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
- // When the scene framework transitions from bouncer to gone, we dismiss the keyguard.
+ // 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(
- mSceneInteractor.get().finishedSceneTransitions(
- /* from= */ SceneKey.Bouncer.INSTANCE,
- /* to= */ SceneKey.Gone.INSTANCE),
- unused -> {
- final int selectedUserId = mUserInteractor.getSelectedUserId();
- showNextSecurityScreenOrFinish(
+ mAuthenticationInteractor.get().isLockscreenDismissed(),
+ isLockscreenDismissed -> {
+ if (isLockscreenDismissed) {
+ final int selectedUserId = mUserInteractor.getSelectedUserId();
+ showNextSecurityScreenOrFinish(
/* authenticated= */ true,
selectedUserId,
/* bypassSecondaryLockScreen= */ true,
mSecurityModel.getSecurityMode(selectedUserId));
- });
+ }
+ }
+ );
}
}
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 e121790f07b0..5dec485a339a 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
@@ -114,14 +114,18 @@ constructor(
* - `true` doesn't mean the lockscreen is invisible (since this state changes before the
* transition occurs).
*/
- private val isLockscreenDismissed =
+ val isLockscreenDismissed: StateFlow<Boolean> =
sceneInteractor.desiredScene
.map { it.key }
.filter { currentScene ->
currentScene == SceneKey.Gone || currentScene == SceneKey.Lockscreen
}
.map { it == SceneKey.Gone }
- .distinctUntilChanged()
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
/**
* Whether it's currently possible to swipe up to dismiss the lockscreen without requiring
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index cf7abdd34b70..76d9b039e112 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -17,21 +17,22 @@
package com.android.systemui.scene.domain.interactor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.RemoteUserInput
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
-import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.mapNotNull
+import kotlinx.coroutines.flow.stateIn
/**
* Generic business logic and app state accessors for the scene framework.
@@ -44,6 +45,7 @@ import kotlinx.coroutines.flow.mapNotNull
class SceneInteractor
@Inject
constructor(
+ @Application applicationScope: CoroutineScope,
private val repository: SceneContainerRepository,
private val logger: SceneLogger,
) {
@@ -88,6 +90,22 @@ constructor(
*/
val transitionState: StateFlow<ObservableTransitionState> = repository.transitionState
+ /**
+ * The key of the scene that the UI is currently transitioning to or `null` if there is no
+ * active transition at the moment.
+ *
+ * This is a convenience wrapper around [transitionState], meant for flow-challenged consumers
+ * like Java code.
+ */
+ val transitioningTo: StateFlow<SceneKey?> =
+ transitionState
+ .map { state -> (state as? ObservableTransitionState.Transition)?.toScene }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = null,
+ )
+
/** Whether the scene container is visible. */
val isVisible: StateFlow<Boolean> = repository.isVisible
@@ -142,21 +160,6 @@ constructor(
repository.setTransitionState(transitionState)
}
- /**
- * Returns a stream of events that emits one [Unit] every time the framework transitions from
- * [from] to [to].
- */
- fun finishedSceneTransitions(from: SceneKey, to: SceneKey): Flow<Unit> {
- return transitionState
- .mapNotNull { it as? ObservableTransitionState.Idle }
- .map { idleState -> idleState.scene }
- .distinctUntilChanged()
- .pairwise()
- .mapNotNull { (previousSceneKey, currentSceneKey) ->
- Unit.takeIf { previousSceneKey == from && currentSceneKey == to }
- }
- }
-
/** Handles a remote user input. */
fun onRemoteUserInput(input: RemoteUserInput) {
_remoteUserInput.value = input
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 1a98c1242e4b..e7483ad71b9d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -38,6 +38,7 @@ import com.android.keyguard.KeyguardSecurityContainer.UserSwitcherViewMode.UserS
import com.android.keyguard.KeyguardSecurityModel.SecurityMode
import com.android.systemui.R
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
@@ -147,6 +148,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
private lateinit var sceneTestUtils: SceneTestUtils
private lateinit var sceneInteractor: SceneInteractor
private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+ private lateinit var authenticationInteractor: AuthenticationInteractor
private lateinit var sceneTransitionStateFlow: MutableStateFlow<ObservableTransitionState>
private lateinit var underTest: KeyguardSecurityContainerController
@@ -214,6 +216,11 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
sceneTransitionStateFlow =
MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Lockscreen))
sceneInteractor.setTransitionState(sceneTransitionStateFlow)
+ authenticationInteractor =
+ sceneTestUtils.authenticationInteractor(
+ repository = sceneTestUtils.authenticationRepository(),
+ sceneInteractor = sceneInteractor
+ )
underTest =
KeyguardSecurityContainerController(
@@ -243,9 +250,10 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
{ JavaAdapter(sceneTestUtils.testScope.backgroundScope) },
userInteractor,
faceAuthAccessibilityDelegate,
- { sceneInteractor },
keyguardTransitionInteractor
- )
+ ) {
+ authenticationInteractor
+ }
}
@Test
@@ -760,7 +768,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
}
@Test
- fun dismissesKeyguard_whenSceneChangesFromBouncerToGone() =
+ fun dismissesKeyguard_whenSceneChangesToGone() =
sceneTestUtils.testScope.runTest {
featureFlags.set(Flags.SCENE_CONTAINER, true)
@@ -822,23 +830,30 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
- // While not listening, moving back to the bouncer does not dismiss the keyguard.
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer, null), "reason")
+ // While not listening, moving to the lockscreen does not dismiss the keyguard.
+ sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen, null), "reason")
sceneTransitionStateFlow.value =
- ObservableTransitionState.Transition(SceneKey.Gone, SceneKey.Bouncer, flowOf(.5f))
+ ObservableTransitionState.Transition(
+ SceneKey.Gone,
+ SceneKey.Lockscreen,
+ flowOf(.5f)
+ )
runCurrent()
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
- sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Bouncer)
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen, null), "reason")
+ sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Lockscreen)
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
// Reattaching the view starts listening again so moving from the bouncer scene to the
- // gone
- // scene now does dismiss the keyguard again.
+ // gone scene now does dismiss the keyguard again, this time from lockscreen.
underTest.onViewAttached()
sceneInteractor.changeScene(SceneModel(SceneKey.Gone, null), "reason")
sceneTransitionStateFlow.value =
- ObservableTransitionState.Transition(SceneKey.Bouncer, SceneKey.Gone, flowOf(.5f))
+ ObservableTransitionState.Transition(
+ SceneKey.Lockscreen,
+ SceneKey.Gone,
+ flowOf(.5f)
+ )
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 0a93a7ca465f..16cc924b5754 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -28,9 +28,6 @@ import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -105,91 +102,50 @@ class SceneInteractorTest : SysuiTestCase() {
}
@Test
- fun isVisible() =
- testScope.runTest {
- val isVisible by collectLastValue(underTest.isVisible)
- assertThat(isVisible).isTrue()
-
- underTest.setVisible(false, "reason")
- assertThat(isVisible).isFalse()
-
- underTest.setVisible(true, "reason")
- assertThat(isVisible).isTrue()
- }
-
- @Test
- fun finishedSceneTransitions() =
+ fun transitioningTo() =
testScope.runTest {
val transitionState =
MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(SceneKey.Lockscreen)
+ ObservableTransitionState.Idle(underTest.desiredScene.value.key)
)
underTest.setTransitionState(transitionState)
- var transitionCount = 0
- val job = launch {
- underTest
- .finishedSceneTransitions(
- from = SceneKey.Shade,
- to = SceneKey.QuickSettings,
- )
- .collect { transitionCount++ }
- }
- assertThat(transitionCount).isEqualTo(0)
+ val transitionTo by collectLastValue(underTest.transitioningTo)
+ assertThat(transitionTo).isNull()
underTest.changeScene(SceneModel(SceneKey.Shade), "reason")
+ assertThat(transitionTo).isNull()
+
+ val progress = MutableStateFlow(0f)
transitionState.value =
ObservableTransitionState.Transition(
- fromScene = SceneKey.Lockscreen,
+ fromScene = underTest.desiredScene.value.key,
toScene = SceneKey.Shade,
- progress = flowOf(0.5f),
+ progress = progress,
)
- runCurrent()
- underTest.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
- transitionState.value = ObservableTransitionState.Idle(SceneKey.Shade)
- runCurrent()
- assertThat(transitionCount).isEqualTo(0)
+ assertThat(transitionTo).isEqualTo(SceneKey.Shade)
- underTest.changeScene(SceneModel(SceneKey.QuickSettings), "reason")
- transitionState.value =
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Shade,
- toScene = SceneKey.QuickSettings,
- progress = flowOf(0.5f),
- )
- runCurrent()
- underTest.onSceneChanged(SceneModel(SceneKey.QuickSettings), "reason")
- transitionState.value = ObservableTransitionState.Idle(SceneKey.QuickSettings)
- runCurrent()
- assertThat(transitionCount).isEqualTo(1)
+ progress.value = 0.5f
+ assertThat(transitionTo).isEqualTo(SceneKey.Shade)
+
+ progress.value = 1f
+ assertThat(transitionTo).isEqualTo(SceneKey.Shade)
- underTest.changeScene(SceneModel(SceneKey.Shade), "reason")
- transitionState.value =
- ObservableTransitionState.Transition(
- fromScene = SceneKey.QuickSettings,
- toScene = SceneKey.Shade,
- progress = flowOf(0.5f),
- )
- runCurrent()
- underTest.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
transitionState.value = ObservableTransitionState.Idle(SceneKey.Shade)
- runCurrent()
- assertThat(transitionCount).isEqualTo(1)
+ assertThat(transitionTo).isNull()
+ }
- underTest.changeScene(SceneModel(SceneKey.QuickSettings), "reason")
- transitionState.value =
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Shade,
- toScene = SceneKey.QuickSettings,
- progress = flowOf(0.5f),
- )
- runCurrent()
- underTest.onSceneChanged(SceneModel(SceneKey.QuickSettings), "reason")
- transitionState.value = ObservableTransitionState.Idle(SceneKey.QuickSettings)
- runCurrent()
- assertThat(transitionCount).isEqualTo(2)
+ @Test
+ fun isVisible() =
+ testScope.runTest {
+ val isVisible by collectLastValue(underTest.isVisible)
+ assertThat(isVisible).isTrue()
- job.cancel()
+ underTest.setVisible(false, "reason")
+ assertThat(isVisible).isFalse()
+
+ underTest.setVisible(true, "reason")
+ assertThat(isVisible).isTrue()
}
@Test
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 0829f31e3890..df7f44770658 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
@@ -123,6 +123,7 @@ class SceneTestUtils(
repository: SceneContainerRepository = fakeSceneContainerRepository()
): SceneInteractor {
return SceneInteractor(
+ applicationScope = applicationScope(),
repository = repository,
logger = mock(),
)