Do not separate flow into two.

In the logs of the bug report, bouncershow(true) and bouncershow(hide)
is called 50 ms apart. The theory is that the ordering of the flow
collection is not deterministic because bouncershow is separated into
two separate flows with a map.

Also added a log in the bouncer repository when the bouncer is
showing/hiding.

Fixes: 274608304
Test: Open and close bouncer from occluded state.
Change-Id: I57595b76af9385bb83ab007f25347a5566e9903a
This commit is contained in:
Aaron Liu
2023-03-21 13:38:52 -07:00
parent bb208e4159
commit 1834a6bd73
5 changed files with 53 additions and 31 deletions

View File

@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.repository
import android.os.Build
import android.util.Log
import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -34,6 +35,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
/**
* Encapsulates app state for the lock screen primary and alternate bouncer.
@@ -231,6 +233,7 @@ constructor(
primaryBouncerShow
.logDiffsForTable(buffer, "", "PrimaryBouncerShow", false)
.onEach { Log.d(TAG, "Keyguard Bouncer is ${if (it) "showing" else "hiding."}") }
.launchIn(applicationScope)
primaryBouncerShowingSoon
.logDiffsForTable(buffer, "", "PrimaryBouncerShowingSoon", false)
@@ -274,5 +277,6 @@ constructor(
companion object {
private const val NOT_VISIBLE = -1L
private const val TAG = "KeyguardBouncerRepositoryImpl"
}
}

View File

@@ -95,8 +95,7 @@ constructor(
}
val keyguardAuthenticated: Flow<Boolean> = repository.keyguardAuthenticated.filterNotNull()
val show: Flow<Unit> = repository.primaryBouncerShow.filter { it }.map {}
val hide: Flow<Unit> = repository.primaryBouncerShow.filter { !it }.map {}
val isShowing: Flow<Boolean> = repository.primaryBouncerShow
val startingToHide: Flow<Unit> = repository.primaryBouncerStartingToHide.filter { it }.map {}
val isBackButtonEnabled: Flow<Boolean> = repository.isBackButtonEnabled.filterNotNull()
val showMessage: Flow<BouncerShowMessageModel> = repository.showMessage.filterNotNull()

View File

@@ -109,35 +109,35 @@ object KeyguardBouncerViewBinder {
try {
viewModel.setBouncerViewDelegate(delegate)
launch {
viewModel.show.collect {
// Reset Security Container entirely.
securityContainerController.reinflateViewFlipper {
viewModel.isShowing.collect { isShowing ->
if (isShowing) {
// Reset Security Container entirely.
view.visibility = View.VISIBLE
securityContainerController.reinflateViewFlipper {
// Reset Security Container entirely.
view.visibility = View.VISIBLE
securityContainerController.onBouncerVisibilityChanged(
/* isVisible= */ true
)
securityContainerController.showPrimarySecurityScreen(
/* turningOff= */ false
)
securityContainerController.appear()
securityContainerController.onResume(
KeyguardSecurityView.SCREEN_ON
)
}
} else {
view.visibility = View.INVISIBLE
securityContainerController.onBouncerVisibilityChanged(
/* isVisible= */ true
/* isVisible= */ false
)
securityContainerController.showPrimarySecurityScreen(
/* turningOff= */ false
)
securityContainerController.appear()
securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
securityContainerController.cancelDismissAction()
securityContainerController.reset()
securityContainerController.onPause()
}
}
}
launch {
viewModel.hide.collect {
view.visibility = View.INVISIBLE
securityContainerController.onBouncerVisibilityChanged(
/* isVisible= */ false
)
securityContainerController.cancelDismissAction()
securityContainerController.reset()
securityContainerController.onPause()
}
}
launch {
viewModel.startingToHide.collect {
securityContainerController.onStartingToHide()

View File

@@ -40,11 +40,8 @@ constructor(
/** Can the user interact with the view? */
val isInteractable: Flow<Boolean> = interactor.isInteractable
/** Observe whether bouncer is showing. */
val show: Flow<Unit> = interactor.show
/** Observe whether bouncer is hiding. */
val hide: Flow<Unit> = interactor.hide
/** Observe whether bouncer is showing or not. */
val isShowing: Flow<Boolean> = interactor.isShowing
/** Observe whether bouncer is starting to hide. */
val startingToHide: Flow<Unit> = interactor.startingToHide
@@ -70,8 +67,8 @@ constructor(
/** Observe whether we should update fps is showing. */
val shouldUpdateSideFps: Flow<Unit> =
merge(
interactor.hide,
interactor.show,
interactor.isShowing.map {},
interactor.startingToHide,
interactor.startingDisappearAnimation.filterNotNull().map {}
)

View File

@@ -125,4 +125,26 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() {
assertThat(sideFpsIsShowing).isEqualTo(true)
job.cancel()
}
@Test
fun isShowing() = runTest {
var isShowing: Boolean? = null
val job = underTest.isShowing.onEach { isShowing = it }.launchIn(this)
repository.setPrimaryShow(true)
// Run the tasks that are pending at this point of virtual time.
runCurrent()
assertThat(isShowing).isEqualTo(true)
job.cancel()
}
@Test
fun isNotShowing() = runTest {
var isShowing: Boolean? = null
val job = underTest.isShowing.onEach { isShowing = it }.launchIn(this)
repository.setPrimaryShow(false)
// Run the tasks that are pending at this point of virtual time.
runCurrent()
assertThat(isShowing).isEqualTo(false)
job.cancel()
}
}