Update media carousel visibility for glanceable hub.
This changelist accounts for the glanceable hub presence for determining
whether the media carousel is visible. The visibility state is
responsible for ensuring the carousel is properly configured when shown.
Test: atest testCommunalLocationVisibilityWithShadeShowing
Test: atest testCommunalLocationVisibilityWithPrimaryBouncerShowing
Flag: EXEMPT bugfix
Fixes: 364488347
Change-Id: I97a8e70bcdb68a8740eab15df2cb14f5a94b15f6
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
index a9d2a54..38cea5b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
@@ -64,6 +64,7 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -431,6 +432,12 @@
/** Is the communal UI showing */
private var isCommunalShowing: Boolean = false
+ /** Is the primary bouncer showing */
+ private var isPrimaryBouncerShowing: Boolean = false
+
+ /** Is either shade or QS fully expanded */
+ private var isAnyShadeFullyExpanded: Boolean = false
+
/** Is the communal UI showing and not dreaming */
private var onCommunalNotDreaming: Boolean = false
@@ -587,6 +594,20 @@
}
}
+ coroutineScope.launch {
+ shadeInteractor.isAnyFullyExpanded.collect {
+ isAnyShadeFullyExpanded = it
+ updateUserVisibility()
+ }
+ }
+
+ coroutineScope.launch {
+ keyguardInteractor.primaryBouncerShowing.collect {
+ isPrimaryBouncerShowing = it
+ updateUserVisibility()
+ }
+ }
+
if (mediaControlsLockscreenShadeBugFix()) {
coroutineScope.launch {
shadeInteractor.shadeExpansion.collect { expansion ->
@@ -638,6 +659,7 @@
communalShowing && isDreaming && isShadeExpanding
onCommunalNotDreaming = communalShowing && !isDreaming
updateDesiredLocation(forceNoAnimation = true)
+ updateUserVisibility()
}
}
}
@@ -1290,7 +1312,8 @@
val shadeVisible =
isLockScreenVisibleToUser() ||
isLockScreenShadeVisibleToUser() ||
- isHomeScreenShadeVisibleToUser()
+ isHomeScreenShadeVisibleToUser() ||
+ isGlanceableHubVisibleToUser()
val mediaVisible = qsExpanded || hasActiveMediaOrRecommendation
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
shadeVisible && mediaVisible
@@ -1318,6 +1341,10 @@
statusBarStateController.isExpanded
}
+ private fun isGlanceableHubVisibleToUser(): Boolean {
+ return isCommunalShowing && !isPrimaryBouncerShowing && !isAnyShadeFullyExpanded
+ }
+
companion object {
/** Attached in expanded quick settings */
const val LOCATION_QS = 0
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
index 2370bca..0508c2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
@@ -25,6 +25,7 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardViewController
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.ui.viewmodel.communalTransitionViewModel
@@ -34,6 +35,7 @@
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.kosmos.testScope
@@ -80,6 +82,8 @@
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.atLeastOnce
+import org.mockito.kotlin.lastValue
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -118,6 +122,7 @@
private lateinit var mediaHierarchyManager: MediaHierarchyManager
private lateinit var isQsBypassingShade: MutableStateFlow<Boolean>
private lateinit var shadeExpansion: MutableStateFlow<Float>
+ private lateinit var anyShadeExpanded: MutableStateFlow<Boolean>
private lateinit var mediaFrame: ViewGroup
private val configurationController = FakeConfigurationController()
private val settings = FakeSettings()
@@ -137,8 +142,10 @@
whenever(mediaCarouselController.mediaFrame).thenReturn(mediaFrame)
isQsBypassingShade = MutableStateFlow(false)
shadeExpansion = MutableStateFlow(0f)
+ anyShadeExpanded = MutableStateFlow(false)
whenever(shadeInteractor.isQsBypassingShade).thenReturn(isQsBypassingShade)
whenever(shadeInteractor.shadeExpansion).thenReturn(shadeExpansion)
+ whenever(shadeInteractor.isAnyFullyExpanded).thenReturn(anyShadeExpanded)
mediaHierarchyManager =
MediaHierarchyManager(
context,
@@ -574,6 +581,72 @@
}
@Test
+ fun testCommunalLocationVisibilityWithShadeShowing() =
+ testScope.runTest {
+ whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true)
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GLANCEABLE_HUB,
+ testScope = testScope,
+ )
+ kosmos.fakeCommunalSceneRepository.changeScene(CommunalScenes.Communal)
+ runCurrent()
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_COMMUNAL_HUB),
+ nullable(),
+ eq(false),
+ anyLong(),
+ anyLong()
+ )
+
+ val captor = ArgumentCaptor.forClass(Boolean::class.java)
+ verify(mediaCarouselScrollHandler, atLeastOnce()).visibleToUser = captor.capture()
+
+ assertThat(captor.lastValue).isTrue()
+
+ clearInvocations(mediaCarouselScrollHandler)
+ anyShadeExpanded.value = true
+ runCurrent()
+ verify(mediaCarouselScrollHandler, atLeastOnce()).visibleToUser = captor.capture()
+
+ assertThat(captor.lastValue).isFalse()
+ }
+
+ @Test
+ fun testCommunalLocationVisibilityWithPrimaryBouncerShowing() =
+ testScope.runTest {
+ whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true)
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GLANCEABLE_HUB,
+ testScope = testScope,
+ )
+ kosmos.fakeCommunalSceneRepository.changeScene(CommunalScenes.Communal)
+ runCurrent()
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_COMMUNAL_HUB),
+ nullable(),
+ eq(false),
+ anyLong(),
+ anyLong()
+ )
+
+ val captor = ArgumentCaptor.forClass(Boolean::class.java)
+ verify(mediaCarouselScrollHandler, atLeastOnce()).visibleToUser = captor.capture()
+
+ assertThat(captor.lastValue).isTrue()
+
+ clearInvocations(mediaCarouselScrollHandler)
+ kosmos.keyguardBouncerRepository.setPrimaryShow(true)
+ runCurrent()
+ verify(mediaCarouselScrollHandler, atLeastOnce()).visibleToUser = captor.capture()
+
+ assertThat(captor.lastValue).isFalse()
+ }
+
+ @Test
fun testCommunalLocation_showsOverLockscreen() =
testScope.runTest {
// Device is on lock screen.