Merge "[flexiglass] Use transitionState instead of currentScene." into udc-qpr-dev
This commit is contained in:
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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" },
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -97,7 +97,7 @@ class SceneTestUtils(
|
||||
fun fakeSceneContainerRepository(
|
||||
containerConfig: SceneContainerConfig = fakeSceneContainerConfig(),
|
||||
): SceneContainerRepository {
|
||||
return SceneContainerRepository(containerConfig)
|
||||
return SceneContainerRepository(applicationScope(), containerConfig)
|
||||
}
|
||||
|
||||
fun fakeSceneKeys(): List<SceneKey> {
|
||||
|
||||
Reference in New Issue
Block a user