Merge "[flexiglass] Use transitionState instead of currentScene." into udc-qpr-dev

This commit is contained in:
Ale Nijamkin
2023-08-07 18:46:14 +00:00
committed by Android (Google) Code Review
22 changed files with 649 additions and 389 deletions

View File

@@ -77,7 +77,7 @@ fun SceneContainer(
SceneTransitionLayout(
currentScene = currentSceneKey.toTransitionSceneKey(),
onChangeScene = { sceneKey -> viewModel.setCurrentScene(sceneKey.toModel()) },
onChangeScene = viewModel::onSceneChanged,
transitions = transitions {},
state = state,
modifier = modifier.fillMaxSize(),
@@ -154,3 +154,7 @@ private fun UserAction.toTransitionUserAction(): SceneTransitionUserAction {
is UserAction.Back -> Back
}
}
private fun SceneContainerViewModel.onSceneChanged(sceneKey: SceneTransitionSceneKey) {
onSceneChanged(sceneKey.toModel())
}

View File

@@ -476,18 +476,16 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
// When the scene framework transitions from bouncer to gone, we dismiss the keyguard.
mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow(
mSceneInteractor.get().getTransitions(),
sceneTransitionModel -> {
if (sceneTransitionModel != null
&& sceneTransitionModel.getFrom() == SceneKey.Bouncer.INSTANCE
&& sceneTransitionModel.getTo() == SceneKey.Gone.INSTANCE) {
final int selectedUserId = mUserInteractor.getSelectedUserId();
showNextSecurityScreenOrFinish(
/* authenticated= */ true,
selectedUserId,
/* bypassSecondaryLockScreen= */ true,
mSecurityModel.getSecurityMode(selectedUserId));
}
mSceneInteractor.get().finishedSceneTransitions(
/* from= */ SceneKey.Bouncer.INSTANCE,
/* to= */ SceneKey.Gone.INSTANCE),
unused -> {
final int selectedUserId = mUserInteractor.getSelectedUserId();
showNextSecurityScreenOrFinish(
/* authenticated= */ true,
selectedUserId,
/* bypassSecondaryLockScreen= */ true,
mSecurityModel.getSecurityMode(selectedUserId));
});
}
}

View File

@@ -116,12 +116,12 @@ constructor(
repository.setMessage(
message ?: promptMessage(authenticationInteractor.getAuthenticationMethod())
)
sceneInteractor.setCurrentScene(
sceneInteractor.changeScene(
scene = SceneModel(SceneKey.Bouncer),
loggingReason = "request to unlock device while authentication required",
)
} else {
sceneInteractor.setCurrentScene(
sceneInteractor.changeScene(
scene = SceneModel(SceneKey.Gone),
loggingReason = "request to unlock device while authentication isn't required",
)
@@ -169,7 +169,7 @@ constructor(
authenticationInteractor.authenticate(input, tryAutoConfirm) ?: return null
if (isAuthenticated) {
sceneInteractor.setCurrentScene(
sceneInteractor.changeScene(
scene = SceneModel(SceneKey.Gone),
loggingReason = "successful authentication",
)

View File

@@ -18,50 +18,49 @@
package com.android.systemui.scene.data.repository
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.SceneTransitionModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
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.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
/** Source of truth for scene framework application state. */
class SceneContainerRepository
@Inject
constructor(
@Application applicationScope: CoroutineScope,
private val config: SceneContainerConfig,
) {
private val _desiredScene = MutableStateFlow(SceneModel(config.initialSceneKey))
val desiredScene: StateFlow<SceneModel> = _desiredScene.asStateFlow()
private val _isVisible = MutableStateFlow(true)
val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()
private val _currentScene = MutableStateFlow(SceneModel(config.initialSceneKey))
val currentScene: StateFlow<SceneModel> = _currentScene.asStateFlow()
private val transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
val transitionProgress: Flow<Float> =
transitionState.flatMapLatest { observableTransitionStateFlow ->
observableTransitionStateFlow?.flatMapLatest { observableTransitionState ->
when (observableTransitionState) {
is ObservableTransitionState.Idle -> flowOf(1f)
is ObservableTransitionState.Transition -> observableTransitionState.progress
}
}
?: flowOf(1f)
}
private val _transitions = MutableStateFlow<SceneTransitionModel?>(null)
val transitions: StateFlow<SceneTransitionModel?> = _transitions.asStateFlow()
private val defaultTransitionState = ObservableTransitionState.Idle(config.initialSceneKey)
private val _transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
val transitionState: StateFlow<ObservableTransitionState> =
_transitionState
.flatMapLatest { innerFlowOrNull -> innerFlowOrNull ?: flowOf(defaultTransitionState) }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
initialValue = defaultTransitionState,
)
/**
* Returns the keys to all scenes in the container with the given name.
* Returns the keys to all scenes in the container.
*
* The scenes will be sorted in z-order such that the last one is the one that should be
* rendered on top of all previous ones.
@@ -70,40 +69,19 @@ constructor(
return config.sceneKeys
}
/** Sets the current scene in the container with the given name. */
fun setCurrentScene(scene: SceneModel) {
fun setDesiredScene(scene: SceneModel) {
check(allSceneKeys().contains(scene.key)) {
"""
Cannot set current scene key to "${scene.key}". The configuration does not contain a
scene with that key.
Cannot set the desired scene key to "${scene.key}". The configuration does not
contain a scene with that key.
"""
.trimIndent()
}
_currentScene.value = scene
_desiredScene.value = scene
}
/** Sets the scene transition in the container with the given name. */
fun setSceneTransition(from: SceneKey, to: SceneKey) {
check(allSceneKeys().contains(from)) {
"""
Cannot set current scene key to "$from". The configuration does not contain a scene
with that key.
"""
.trimIndent()
}
check(allSceneKeys().contains(to)) {
"""
Cannot set current scene key to "$to". The configuration does not contain a scene
with that key.
"""
.trimIndent()
}
_transitions.value = SceneTransitionModel(from = from, to = to)
}
/** Sets whether the container with the given name is visible. */
/** Sets whether the container is visible. */
fun setVisible(isVisible: Boolean) {
_isVisible.value = isVisible
}
@@ -114,6 +92,6 @@ constructor(
* Note that you must call is with `null` when the UI is done or risk a memory leak.
*/
fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
this.transitionState.value = transitionState
_transitionState.value = transitionState
}
}

View File

@@ -23,12 +23,15 @@ 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.scene.shared.model.SceneTransitionModel
import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
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
/**
* Generic business logic and app state accessors for the scene framework.
@@ -46,7 +49,54 @@ constructor(
) {
/**
* Returns the keys of all scenes in the container with the given name.
* The currently *desired* scene.
*
* **Important:** this value will _commonly be different_ from what is being rendered in the UI,
* by design.
*
* There are two intended sources for this value:
* 1. Programmatic requests to transition to another scene (calls to [changeScene]).
* 2. Reports from the UI about completing a transition to another scene (calls to
* [onSceneChanged]).
*
* Both the sources above cause the value of this flow to change; however, they cause mismatches
* in different ways.
*
* **Updates from programmatic transitions**
*
* When an external bit of code asks the framework to switch to another scene, the value here
* will update immediately. Downstream, the UI will detect this change and initiate the
* transition animation. As the transition animation progresses, a threshold will be reached, at
* which point the UI and the state here will match each other.
*
* **Updates from the UI**
*
* When the user interacts with the UI, the UI runs a transition animation that tracks the user
* pointer (for example, the user's finger). During this time, the state value here and what the
* UI shows will likely not match. Once/if a threshold is met, the UI reports it and commits the
* change, making the value here match the UI again.
*/
val desiredScene: StateFlow<SceneModel> = repository.desiredScene
/**
* The current state of the transition.
*
* Consumers should use this state to know:
* 1. Whether there is an ongoing transition or if the system is at rest.
* 2. When transitioning, which scenes are being transitioned between.
* 3. When transitioning, what the progress of the transition is.
*/
val transitionState: StateFlow<ObservableTransitionState> = repository.transitionState
/** Whether the scene container is visible. */
val isVisible: StateFlow<Boolean> = repository.isVisible
private val _remoteUserInput: MutableStateFlow<RemoteUserInput?> = MutableStateFlow(null)
/** A flow of motion events originating from outside of the scene framework. */
val remoteUserInput: StateFlow<RemoteUserInput?> = _remoteUserInput.asStateFlow()
/**
* Returns the keys of all scenes in the container.
*
* The scenes will be sorted in z-order such that the last one is the one that should be
* rendered on top of all previous ones.
@@ -55,26 +105,20 @@ constructor(
return repository.allSceneKeys()
}
/** Sets the scene in the container with the given name. */
fun setCurrentScene(scene: SceneModel, loggingReason: String) {
val currentSceneKey = repository.currentScene.value.key
if (currentSceneKey == scene.key) {
return
}
logger.logSceneChange(
from = currentSceneKey,
to = scene.key,
reason = loggingReason,
)
repository.setCurrentScene(scene)
repository.setSceneTransition(from = currentSceneKey, to = scene.key)
/**
* Requests a scene change to the given scene.
*
* The change is animated. Therefore, while the value in [desiredScene] will update immediately,
* it will be some time before the UI will switch to the desired scene. The scene change
* requested is remembered here but served by the UI layer, which will start a transition
* animation. Once enough of the transition has occurred, the system will come into agreement
* between the [desiredScene] and the UI.
*/
fun changeScene(scene: SceneModel, loggingReason: String) {
updateDesiredScene(scene, loggingReason, logger::logSceneChangeRequested)
}
/** The current scene in the container with the given name. */
val currentScene: StateFlow<SceneModel> = repository.currentScene
/** Sets the visibility of the container with the given name. */
/** Sets the visibility of the container. */
fun setVisible(isVisible: Boolean, loggingReason: String) {
val wasVisible = repository.isVisible.value
if (wasVisible == isVisible) {
@@ -89,9 +133,6 @@ constructor(
return repository.setVisible(isVisible)
}
/** Whether the container with the given name is visible. */
val isVisible: StateFlow<Boolean> = repository.isVisible
/**
* Binds the given flow so the system remembers it.
*
@@ -101,23 +142,53 @@ constructor(
repository.setTransitionState(transitionState)
}
/** Progress of the transition into the current scene in the container with the given name. */
val transitionProgress: Flow<Float> = repository.transitionProgress
/**
* Scene transitions as pairs of keys. A new value is emitted exactly once, each time a scene
* transition occurs. The flow begins with a `null` value at first, because the initial scene is
* not something that we transition to from another scene.
* Returns a stream of events that emits one [Unit] every time the framework transitions from
* [from] to [to].
*/
val transitions: StateFlow<SceneTransitionModel?> = repository.transitions
private val _remoteUserInput: MutableStateFlow<RemoteUserInput?> = MutableStateFlow(null)
/** A flow of motion events originating from outside of the scene framework. */
val remoteUserInput: StateFlow<RemoteUserInput?> = _remoteUserInput.asStateFlow()
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
}
/**
* Notifies that the UI has transitioned sufficiently to the given scene.
*
* *Not intended for external use!*
*
* Once a transition between one scene and another passes a threshold, the UI invokes this
* method to report it, updating the value in [desiredScene] to match what the UI shows.
*/
internal fun onSceneChanged(scene: SceneModel, loggingReason: String) {
updateDesiredScene(scene, loggingReason, logger::logSceneChangeCommitted)
}
private fun updateDesiredScene(
scene: SceneModel,
loggingReason: String,
log: (from: SceneKey, to: SceneKey, loggingReason: String) -> Unit,
) {
val currentSceneKey = desiredScene.value.key
if (currentSceneKey == scene.key) {
return
}
log(
/* from= */ currentSceneKey,
/* to= */ scene.key,
/* loggingReason= */ loggingReason,
)
repository.setDesiredScene(scene)
}
}

View File

@@ -30,6 +30,7 @@ import com.android.systemui.model.SysUiState
import com.android.systemui.model.updateFlags
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
@@ -40,8 +41,8 @@ import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_B
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch
/**
@@ -73,14 +74,31 @@ constructor(
}
}
/** Updates the visibility of the scene container based on the current scene. */
/** Updates the visibility of the scene container. */
private fun hydrateVisibility() {
applicationScope.launch {
sceneInteractor.currentScene
.map { it.key }
sceneInteractor.transitionState
.mapNotNull { state ->
when (state) {
is ObservableTransitionState.Idle -> {
if (state.scene != SceneKey.Gone) {
true to "scene is not Gone"
} else {
false to "scene is Gone"
}
}
is ObservableTransitionState.Transition -> {
if (state.fromScene == SceneKey.Gone) {
true to "scene transitioning away from Gone"
} else {
null
}
}
}
}
.distinctUntilChanged()
.collect { sceneKey ->
sceneInteractor.setVisible(sceneKey != SceneKey.Gone, "scene is $sceneKey")
.collect { (isVisible, loggingReason) ->
sceneInteractor.setVisible(isVisible, loggingReason)
}
}
}
@@ -89,43 +107,55 @@ constructor(
private fun automaticallySwitchScenes() {
applicationScope.launch {
authenticationInteractor.isUnlocked
.map { isUnlocked ->
val currentSceneKey = sceneInteractor.currentScene.value.key
.mapNotNull { isUnlocked ->
val renderedScenes =
when (val transitionState = sceneInteractor.transitionState.value) {
is ObservableTransitionState.Idle -> setOf(transitionState.scene)
is ObservableTransitionState.Transition ->
setOf(
transitionState.progress,
transitionState.toScene,
)
}
val isBypassEnabled = authenticationInteractor.isBypassEnabled()
when {
isUnlocked ->
when (currentSceneKey) {
when {
// When the device becomes unlocked in Bouncer, go to Gone.
is SceneKey.Bouncer ->
renderedScenes.contains(SceneKey.Bouncer) ->
SceneKey.Gone to "device unlocked in Bouncer scene"
// When the device becomes unlocked in Lockscreen, go to Gone if
// bypass is enabled.
is SceneKey.Lockscreen ->
renderedScenes.contains(SceneKey.Lockscreen) ->
if (isBypassEnabled) {
SceneKey.Gone to
"device unlocked in Lockscreen scene with bypass"
} else {
null
}
// We got unlocked while on a scene that's not Lockscreen or
// Bouncer, no need to change scenes.
else -> null
}
// When the device becomes locked, to Lockscreen.
!isUnlocked ->
when (currentSceneKey) {
when {
// Already on lockscreen or bouncer, no need to change scenes.
is SceneKey.Lockscreen,
is SceneKey.Bouncer -> null
renderedScenes.contains(SceneKey.Lockscreen) ||
renderedScenes.contains(SceneKey.Bouncer) -> null
// We got locked while on a scene that's not Lockscreen or Bouncer,
// go to Lockscreen.
else ->
SceneKey.Lockscreen to "device locked in $currentSceneKey scene"
SceneKey.Lockscreen to
"device locked in non-Lockscreen and non-Bouncer scene"
}
else -> null
}
}
.filterNotNull()
.collect { (targetSceneKey, loggingReason) ->
switchToScene(
targetSceneKey = targetSceneKey,
@@ -143,7 +173,7 @@ constructor(
WakefulnessState.STARTING_TO_SLEEP -> {
switchToScene(
targetSceneKey = SceneKey.Lockscreen,
loggingReason = "device is asleep",
loggingReason = "device is starting to sleep",
)
}
WakefulnessState.STARTING_TO_WAKE -> {
@@ -165,8 +195,9 @@ constructor(
/** Keeps [SysUiState] up-to-date */
private fun hydrateSystemUiState() {
applicationScope.launch {
sceneInteractor.currentScene
.map { it.key }
sceneInteractor.transitionState
.mapNotNull { it as? ObservableTransitionState.Idle }
.map { it.scene }
.distinctUntilChanged()
.collect { sceneKey ->
sysUiState.updateFlags(
@@ -183,7 +214,7 @@ constructor(
}
private fun switchToScene(targetSceneKey: SceneKey, loggingReason: String) {
sceneInteractor.setCurrentScene(
sceneInteractor.changeScene(
scene = SceneModel(targetSceneKey),
loggingReason = loggingReason,
)

View File

@@ -37,7 +37,7 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer:
)
}
fun logSceneChange(
fun logSceneChangeRequested(
from: SceneKey,
to: SceneKey,
reason: String,
@@ -50,7 +50,24 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer:
str2 = to.toString()
str3 = reason
},
messagePrinter = { "$str1 → $str2, reason: $str3" },
messagePrinter = { "Scene change requested: $str1 → $str2, reason: $str3" },
)
}
fun logSceneChangeCommitted(
from: SceneKey,
to: SceneKey,
reason: String,
) {
logBuffer.log(
tag = TAG,
level = LogLevel.INFO,
messageInitializer = {
str1 = from.toString()
str2 = to.toString()
str3 = reason
},
messagePrinter = { "Scene change committed: $str1 → $str2, reason: $str3" },
)
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.scene.shared.model
/** Models a transition between two scenes. */
data class SceneTransitionModel(
/** The scene we transitioned away from. */
val from: SceneKey,
/** The scene we transitioned into. */
val to: SceneKey,
)

View File

@@ -45,15 +45,15 @@ constructor(
*/
val allSceneKeys: List<SceneKey> = interactor.allSceneKeys()
/** The current scene. */
val currentScene: StateFlow<SceneModel> = interactor.currentScene
/** The scene that should be rendered. */
val currentScene: StateFlow<SceneModel> = interactor.desiredScene
/** Whether the container is visible. */
val isVisible: StateFlow<Boolean> = interactor.isVisible
/** Requests a transition to the scene with the given key. */
fun setCurrentScene(scene: SceneModel) {
interactor.setCurrentScene(
/** Notifies that the UI has transitioned sufficiently to the given scene. */
fun onSceneChanged(scene: SceneModel) {
interactor.onSceneChanged(
scene = scene,
loggingReason = SCENE_TRANSITION_LOGGING_REASON,
)

View File

@@ -50,6 +50,7 @@ import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.plugins.FalsingManager
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.scene.shared.model.SceneModel
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -66,6 +67,8 @@ import com.google.common.truth.Truth
import java.util.Optional
import junit.framework.Assert
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -139,6 +142,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
private lateinit var testableResources: TestableResources
private lateinit var sceneTestUtils: SceneTestUtils
private lateinit var sceneInteractor: SceneInteractor
private lateinit var sceneTransitionStateFlow: MutableStateFlow<ObservableTransitionState>
private lateinit var underTest: KeyguardSecurityContainerController
@@ -198,6 +202,9 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
whenever(userInteractor.getSelectedUserId()).thenReturn(TARGET_USER_ID)
sceneTestUtils = SceneTestUtils(this)
sceneInteractor = sceneTestUtils.sceneInteractor()
sceneTransitionStateFlow =
MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Lockscreen))
sceneInteractor.setTransitionState(sceneTransitionStateFlow)
underTest =
KeyguardSecurityContainerController(
@@ -733,20 +740,39 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
// is
// not enough to trigger a dismissal of the keyguard.
underTest.onViewAttached()
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer, null), "reason")
sceneTransitionStateFlow.value =
ObservableTransitionState.Transition(
SceneKey.Lockscreen,
SceneKey.Bouncer,
flowOf(.5f)
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Bouncer)
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
// While listening, going from the bouncer scene to the gone scene, does dismiss the
// keyguard.
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Gone, null), "reason")
sceneTransitionStateFlow.value =
ObservableTransitionState.Transition(SceneKey.Bouncer, SceneKey.Gone, flowOf(.5f))
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
runCurrent()
verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
// While listening, moving back to the bouncer scene does not dismiss the keyguard
// again.
clearInvocations(viewMediatorCallback)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer, null), "reason")
sceneTransitionStateFlow.value =
ObservableTransitionState.Transition(SceneKey.Gone, SceneKey.Bouncer, flowOf(.5f))
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Bouncer)
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
@@ -754,12 +780,22 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
// scene
// does not dismiss the keyguard while we're not listening.
underTest.onViewDetached()
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Gone, null), "reason")
sceneTransitionStateFlow.value =
ObservableTransitionState.Transition(SceneKey.Bouncer, SceneKey.Gone, flowOf(.5f))
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
// While not listening, moving back to the bouncer does not dismiss the keyguard.
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer, null), "reason")
sceneTransitionStateFlow.value =
ObservableTransitionState.Transition(SceneKey.Gone, SceneKey.Bouncer, flowOf(.5f))
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Bouncer)
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
@@ -767,7 +803,12 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
// gone
// scene now does dismiss the keyguard again.
underTest.onViewAttached()
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Gone, null), "reason")
sceneTransitionStateFlow.value =
ObservableTransitionState.Transition(SceneKey.Bouncer, SceneKey.Gone, flowOf(.5f))
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
runCurrent()
verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
}

View File

@@ -70,7 +70,7 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun pinAuthMethod() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
@@ -102,7 +102,7 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun pinAuthMethod_tryAutoConfirm_withAutoConfirmPin() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
@@ -139,7 +139,7 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun pinAuthMethod_tryAutoConfirm_withoutAutoConfirmPin() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
@@ -169,7 +169,7 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun passwordAuthMethod() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
@@ -202,7 +202,7 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun patternAuthMethod() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern
@@ -236,7 +236,7 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun showOrUnlockDevice_notLocked_switchesToGoneScene() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -249,7 +249,7 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
utils.authenticationRepository.setLockscreenEnabled(true)
utils.authenticationRepository.setUnlocked(false)
@@ -262,7 +262,7 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun showOrUnlockDevice_customMessageShown() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
@@ -283,7 +283,7 @@ class BouncerInteractorTest : SysuiTestCase() {
val isThrottled by collectLastValue(underTest.isThrottled)
val throttling by collectLastValue(underTest.throttling)
val message by collectLastValue(underTest.message)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
runCurrent()
underTest.showOrUnlockDevice()

View File

@@ -73,14 +73,15 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onShown() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -93,14 +94,15 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onPasswordInputChanged() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -115,12 +117,13 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateKeyPressed_whenCorrect() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("password")
@@ -133,14 +136,15 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateKeyPressed_whenWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
@@ -155,14 +159,15 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateKeyPressed_correctAfterWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")

View File

@@ -76,7 +76,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onShown() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -84,7 +84,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -98,7 +99,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragStart() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -106,7 +107,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -122,14 +124,15 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragEnd_whenCorrect() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -169,7 +172,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragEnd_whenWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -177,7 +180,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -201,7 +205,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragEnd_correctAfterWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -209,7 +213,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()

View File

@@ -76,11 +76,13 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onShown() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
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)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -93,12 +95,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onPinButtonClicked() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -113,12 +117,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onBackspaceButtonClicked() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -135,11 +141,13 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onPinEdit() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -157,12 +165,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onBackspaceButtonLongPressed() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -181,10 +191,12 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateButtonClicked_whenCorrect() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
@@ -199,12 +211,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateButtonClicked_whenWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -223,12 +237,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateButtonClicked_correctAfterWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -255,11 +271,13 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAutoConfirm_whenCorrect() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAutoConfirmEnabled(true)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
@@ -272,13 +290,15 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAutoConfirm_whenWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
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.authenticationRepository.setAutoConfirmEnabled(true)
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.dropLast(1).forEach { digit ->

View File

@@ -107,7 +107,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
@@ -120,7 +120,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -133,7 +133,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
@@ -146,7 +146,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onLockButtonClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()

View File

@@ -56,7 +56,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -69,7 +69,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()

View File

@@ -25,7 +25,6 @@ import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.SceneTransitionModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -39,6 +38,7 @@ import org.junit.runners.JUnit4
class SceneContainerRepositoryTest : SysuiTestCase() {
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
@Test
fun allSceneKeys() {
@@ -56,97 +56,82 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
}
@Test
fun currentScene() = runTest {
val underTest = utils.fakeSceneContainerRepository()
val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
fun desiredScene() =
testScope.runTest {
val underTest = utils.fakeSceneContainerRepository()
val currentScene by collectLastValue(underTest.desiredScene)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.setCurrentScene(SceneModel(SceneKey.Shade))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}
underTest.setDesiredScene(SceneModel(SceneKey.Shade))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}
@Test(expected = IllegalStateException::class)
fun setCurrentScene_noSuchSceneInContainer_throws() {
fun setDesiredScene_noSuchSceneInContainer_throws() {
val underTest =
utils.fakeSceneContainerRepository(
utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)),
)
underTest.setCurrentScene(SceneModel(SceneKey.Shade))
underTest.setDesiredScene(SceneModel(SceneKey.Shade))
}
@Test
fun isVisible() = runTest {
val underTest = utils.fakeSceneContainerRepository()
val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isTrue()
fun isVisible() =
testScope.runTest {
val underTest = utils.fakeSceneContainerRepository()
val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isTrue()
underTest.setVisible(false)
assertThat(isVisible).isFalse()
underTest.setVisible(false)
assertThat(isVisible).isFalse()
underTest.setVisible(true)
assertThat(isVisible).isTrue()
}
underTest.setVisible(true)
assertThat(isVisible).isTrue()
}
@Test
fun transitionProgress() = runTest {
val underTest = utils.fakeSceneContainerRepository()
val sceneTransitionProgress by collectLastValue(underTest.transitionProgress)
assertThat(sceneTransitionProgress).isEqualTo(1f)
fun transitionState_defaultsToIdle() =
testScope.runTest {
val underTest = utils.fakeSceneContainerRepository()
val transitionState by collectLastValue(underTest.transitionState)
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(SceneKey.Lockscreen)
)
underTest.setTransitionState(transitionState)
assertThat(sceneTransitionProgress).isEqualTo(1f)
val progress = MutableStateFlow(1f)
transitionState.value =
ObservableTransitionState.Transition(
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = progress,
)
assertThat(sceneTransitionProgress).isEqualTo(1f)
progress.value = 0.1f
assertThat(sceneTransitionProgress).isEqualTo(0.1f)
progress.value = 0.9f
assertThat(sceneTransitionProgress).isEqualTo(0.9f)
underTest.setTransitionState(null)
assertThat(sceneTransitionProgress).isEqualTo(1f)
}
assertThat(transitionState)
.isEqualTo(
ObservableTransitionState.Idle(utils.fakeSceneContainerConfig().initialSceneKey)
)
}
@Test
fun setSceneTransition() = runTest {
val underTest = utils.fakeSceneContainerRepository()
val sceneTransition by collectLastValue(underTest.transitions)
assertThat(sceneTransition).isNull()
fun transitionState_reflectsUpdates() =
testScope.runTest {
val underTest = utils.fakeSceneContainerRepository()
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(SceneKey.Lockscreen)
)
underTest.setTransitionState(transitionState)
val reflectedTransitionState by collectLastValue(underTest.transitionState)
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
underTest.setSceneTransition(SceneKey.Lockscreen, SceneKey.QuickSettings)
assertThat(sceneTransition)
.isEqualTo(
SceneTransitionModel(from = SceneKey.Lockscreen, to = SceneKey.QuickSettings)
)
}
val progress = MutableStateFlow(1f)
transitionState.value =
ObservableTransitionState.Transition(
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = progress,
)
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
@Test(expected = IllegalStateException::class)
fun setSceneTransition_noFromSceneInContainer_throws() {
val underTest =
utils.fakeSceneContainerRepository(
utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)),
)
underTest.setSceneTransition(SceneKey.Shade, SceneKey.Lockscreen)
}
progress.value = 0.1f
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
@Test(expected = IllegalStateException::class)
fun setSceneTransition_noToSceneInContainer_throws() {
val underTest =
utils.fakeSceneContainerRepository(
utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)),
)
underTest.setSceneTransition(SceneKey.Shade, SceneKey.Lockscreen)
}
progress.value = 0.9f
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
underTest.setTransitionState(null)
assertThat(reflectedTransitionState)
.isEqualTo(
ObservableTransitionState.Idle(utils.fakeSceneContainerConfig().initialSceneKey)
)
}
}

View File

@@ -25,10 +25,12 @@ import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.SceneTransitionModel
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
@@ -39,6 +41,7 @@ import org.junit.runners.JUnit4
class SceneInteractorTest : SysuiTestCase() {
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
private val repository = utils.fakeSceneContainerRepository()
private val underTest = utils.sceneInteractor(repository = repository)
@@ -48,77 +51,156 @@ class SceneInteractorTest : SysuiTestCase() {
}
@Test
fun currentScene() = runTest {
val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
fun changeScene() =
testScope.runTest {
val desiredScene by collectLastValue(underTest.desiredScene)
assertThat(desiredScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}
underTest.changeScene(SceneModel(SceneKey.Shade), "reason")
assertThat(desiredScene).isEqualTo(SceneModel(SceneKey.Shade))
}
@Test
fun sceneTransitionProgress() = runTest {
val transitionProgress by collectLastValue(underTest.transitionProgress)
assertThat(transitionProgress).isEqualTo(1f)
fun onSceneChanged() =
testScope.runTest {
val desiredScene by collectLastValue(underTest.desiredScene)
assertThat(desiredScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
val progress = MutableStateFlow(0.55f)
repository.setTransitionState(
MutableStateFlow(
underTest.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
assertThat(desiredScene).isEqualTo(SceneModel(SceneKey.Shade))
}
@Test
fun transitionState() =
testScope.runTest {
val underTest = utils.fakeSceneContainerRepository()
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(SceneKey.Lockscreen)
)
underTest.setTransitionState(transitionState)
val reflectedTransitionState by collectLastValue(underTest.transitionState)
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
val progress = MutableStateFlow(1f)
transitionState.value =
ObservableTransitionState.Transition(
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = progress,
),
)
)
assertThat(transitionProgress).isEqualTo(0.55f)
}
@Test
fun isVisible() = 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 sceneTransitions() = runTest {
val transitions by collectLastValue(underTest.transitions)
assertThat(transitions).isNull()
val initialSceneKey = underTest.currentScene.value.key
underTest.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
assertThat(transitions)
.isEqualTo(
SceneTransitionModel(
from = initialSceneKey,
to = SceneKey.Shade,
)
)
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
underTest.setCurrentScene(SceneModel(SceneKey.QuickSettings), "reason")
assertThat(transitions)
.isEqualTo(
SceneTransitionModel(
from = SceneKey.Shade,
to = SceneKey.QuickSettings,
progress.value = 0.1f
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
progress.value = 0.9f
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
underTest.setTransitionState(null)
assertThat(reflectedTransitionState)
.isEqualTo(
ObservableTransitionState.Idle(utils.fakeSceneContainerConfig().initialSceneKey)
)
)
}
@Test
fun remoteUserInput() = runTest {
val remoteUserInput by collectLastValue(underTest.remoteUserInput)
assertThat(remoteUserInput).isNull()
for (input in SceneTestUtils.REMOTE_INPUT_DOWN_GESTURE) {
underTest.onRemoteUserInput(input)
assertThat(remoteUserInput).isEqualTo(input)
}
}
@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() =
testScope.runTest {
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(SceneKey.Lockscreen)
)
underTest.setTransitionState(transitionState)
var transitionCount = 0
val job = launch {
underTest
.finishedSceneTransitions(
from = SceneKey.Shade,
to = SceneKey.QuickSettings,
)
.collect { transitionCount++ }
}
assertThat(transitionCount).isEqualTo(0)
underTest.changeScene(SceneModel(SceneKey.Shade), "reason")
transitionState.value =
ObservableTransitionState.Transition(
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = flowOf(0.5f),
)
runCurrent()
underTest.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
transitionState.value = ObservableTransitionState.Idle(SceneKey.Shade)
runCurrent()
assertThat(transitionCount).isEqualTo(0)
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)
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)
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)
job.cancel()
}
@Test
fun remoteUserInput() =
testScope.runTest {
val remoteUserInput by collectLastValue(underTest.remoteUserInput)
assertThat(remoteUserInput).isNull()
for (input in SceneTestUtils.REMOTE_INPUT_DOWN_GESTURE) {
underTest.onRemoteUserInput(input)
assertThat(remoteUserInput).isEqualTo(input)
}
}
}

View File

@@ -29,15 +29,17 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.model.SysUiState
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
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
@@ -77,59 +79,86 @@ class SceneContainerStartableTest : SysuiTestCase() {
sceneLogger = mock(),
)
@Before
fun setUp() {
prepareState()
}
@Test
fun hydrateVisibility_featureEnabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentDesiredSceneKey by
collectLastValue(sceneInteractor.desiredScene.map { it.key })
val isVisible by collectLastValue(sceneInteractor.isVisible)
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = true,
initialSceneKey = SceneKey.Gone,
)
assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
val transitionStateFlow =
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = true,
initialSceneKey = SceneKey.Gone,
)
assertThat(currentDesiredSceneKey).isEqualTo(SceneKey.Gone)
assertThat(isVisible).isTrue()
underTest.start()
assertThat(isVisible).isFalse()
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Shade), "reason")
transitionStateFlow.value =
ObservableTransitionState.Transition(
fromScene = SceneKey.Gone,
toScene = SceneKey.Shade,
progress = flowOf(0.5f),
)
assertThat(isVisible).isTrue()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
transitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Shade)
assertThat(isVisible).isTrue()
sceneInteractor.changeScene(SceneModel(SceneKey.Gone), "reason")
transitionStateFlow.value =
ObservableTransitionState.Transition(
fromScene = SceneKey.Shade,
toScene = SceneKey.Gone,
progress = flowOf(0.5f),
)
assertThat(isVisible).isTrue()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone), "reason")
transitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
assertThat(isVisible).isFalse()
}
@Test
fun hydrateVisibility_featureDisabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentDesiredSceneKey by
collectLastValue(sceneInteractor.desiredScene.map { it.key })
val isVisible by collectLastValue(sceneInteractor.isVisible)
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = true,
initialSceneKey = SceneKey.Lockscreen,
)
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
val transitionStateFlow =
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = true,
initialSceneKey = SceneKey.Gone,
)
assertThat(currentDesiredSceneKey).isEqualTo(SceneKey.Gone)
assertThat(isVisible).isTrue()
underTest.start()
assertThat(isVisible).isTrue()
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone), "reason")
sceneInteractor.changeScene(SceneModel(SceneKey.Shade), "reason")
transitionStateFlow.value =
ObservableTransitionState.Transition(
fromScene = SceneKey.Gone,
toScene = SceneKey.Shade,
progress = flowOf(0.5f),
)
assertThat(isVisible).isTrue()
sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
transitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Shade)
assertThat(isVisible).isTrue()
}
@Test
fun switchToLockscreenWhenDeviceLocks_featureEnabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = true,
@@ -146,7 +175,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToLockscreenWhenDeviceLocks_featureDisabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = false,
@@ -163,7 +192,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromBouncerToGoneWhenDeviceUnlocked_featureEnabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = false,
@@ -180,7 +209,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromBouncerToGoneWhenDeviceUnlocked_featureDisabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = false,
@@ -197,7 +226,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOn_bypassOn() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isBypassEnabled = true,
@@ -214,7 +243,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOn_bypassOff() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isBypassEnabled = false,
@@ -231,7 +260,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOff_bypassOn() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isBypassEnabled = true,
@@ -248,7 +277,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToLockscreenWhenDeviceSleepsLocked_featureEnabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = false,
@@ -265,7 +294,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToLockscreenWhenDeviceSleepsLocked_featureDisabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = false,
@@ -282,6 +311,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun hydrateSystemUiState() =
testScope.runTest {
val transitionStateFlow = prepareState()
underTest.start()
runCurrent()
clearInvocations(sysUiState)
@@ -294,9 +324,16 @@ class SceneContainerStartableTest : SysuiTestCase() {
SceneKey.QuickSettings,
)
.forEachIndexed { index, sceneKey ->
sceneInteractor.setCurrentScene(SceneModel(sceneKey), "reason")
sceneInteractor.changeScene(SceneModel(sceneKey), "reason")
runCurrent()
verify(sysUiState, times(index)).commitUpdate(Display.DEFAULT_DISPLAY)
sceneInteractor.onSceneChanged(SceneModel(sceneKey), "reason")
runCurrent()
verify(sysUiState, times(index)).commitUpdate(Display.DEFAULT_DISPLAY)
transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey)
runCurrent()
verify(sysUiState, times(index + 1)).commitUpdate(Display.DEFAULT_DISPLAY)
}
}
@@ -304,7 +341,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToGoneWhenDeviceStartsToWakeUp_authMethodNone_featureEnabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
initialSceneKey = SceneKey.Lockscreen,
@@ -321,7 +358,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToGoneWhenDeviceStartsToWakeUp_authMethodNotNone_featureEnabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
initialSceneKey = SceneKey.Lockscreen,
@@ -338,7 +375,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToGoneWhenDeviceStartsToWakeUp_authMethodNone_featureDisabled() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = false,
initialSceneKey = SceneKey.Lockscreen,
@@ -358,17 +395,27 @@ class SceneContainerStartableTest : SysuiTestCase() {
isBypassEnabled: Boolean = false,
initialSceneKey: SceneKey? = null,
authenticationMethod: AuthenticationMethodModel? = null,
) {
): MutableStateFlow<ObservableTransitionState> {
featureFlags.set(Flags.SCENE_CONTAINER, isFeatureEnabled)
authenticationRepository.setUnlocked(isDeviceUnlocked)
keyguardRepository.setBypassEnabled(isBypassEnabled)
initialSceneKey?.let { sceneInteractor.setCurrentScene(SceneModel(it), "reason") }
val transitionStateFlow =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(SceneKey.Lockscreen)
)
sceneInteractor.setTransitionState(transitionStateFlow)
initialSceneKey?.let {
transitionStateFlow.value = ObservableTransitionState.Idle(it)
sceneInteractor.changeScene(SceneModel(it), "reason")
sceneInteractor.onSceneChanged(SceneModel(it), "reason")
}
authenticationMethod?.let {
authenticationRepository.setAuthenticationMethod(authenticationMethod)
authenticationRepository.setLockscreenEnabled(
authenticationMethod != AuthenticationMethodModel.None
)
}
return transitionStateFlow
}
companion object {

View File

@@ -69,7 +69,8 @@ class SceneContainerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.setCurrentScene(SceneModel(SceneKey.Shade))
underTest.onSceneChanged(SceneModel(SceneKey.Shade))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}

View File

@@ -78,7 +78,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -91,7 +91,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()

View File

@@ -97,7 +97,7 @@ class SceneTestUtils(
fun fakeSceneContainerRepository(
containerConfig: SceneContainerConfig = fakeSceneContainerConfig(),
): SceneContainerRepository {
return SceneContainerRepository(containerConfig)
return SceneContainerRepository(applicationScope(), containerConfig)
}
fun fakeSceneKeys(): List<SceneKey> {