Merge "Update media carousel visibility for glanceable hub." into main
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.