summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author William Leshner <wleshner@google.com> 2024-09-13 16:18:59 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-09-13 16:18:59 +0000
commit2aa3af4aa5c3109ed6815d4939349ffc68601ee9 (patch)
tree17131f78acd78b8e3937cbabc5bdd13f05c22cad
parent61a577c01eca720a1f38cb07f1d5e65b3883beec (diff)
parent4bd9ef2ad5c7e0e3d6269a1fcd5191fe4579fde8 (diff)
Merge "Don't allow UMO to shrink to 1/3 size." into main
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt104
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt107
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt31
5 files changed, 208 insertions, 141 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 75ae4148d1df..b96e40f43318 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -244,10 +244,7 @@ class CommunalInteractorTest : SysuiTestCase() {
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
runCurrent()
// Widgets available.
@@ -267,21 +264,14 @@ class CommunalInteractorTest : SysuiTestCase() {
fun smartspaceDynamicSizing_oneCard_fullSize() =
testSmartspaceDynamicSizing(
totalTargets = 1,
- expectedSizes =
- listOf(
- CommunalContentSize.FULL,
- )
+ expectedSizes = listOf(CommunalContentSize.FULL),
)
@Test
fun smartspace_dynamicSizing_twoCards_halfSize() =
testSmartspaceDynamicSizing(
totalTargets = 2,
- expectedSizes =
- listOf(
- CommunalContentSize.HALF,
- CommunalContentSize.HALF,
- )
+ expectedSizes = listOf(CommunalContentSize.HALF, CommunalContentSize.HALF),
)
@Test
@@ -293,34 +283,34 @@ class CommunalInteractorTest : SysuiTestCase() {
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
- )
+ ),
)
@Test
- fun smartspace_dynamicSizing_fourCards_oneFullAndThreeThirdSize() =
+ fun smartspace_dynamicSizing_fourCards_threeThirdSizeAndOneFullSize() =
testSmartspaceDynamicSizing(
totalTargets = 4,
expectedSizes =
listOf(
- CommunalContentSize.FULL,
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
- )
+ CommunalContentSize.FULL,
+ ),
)
@Test
- fun smartspace_dynamicSizing_fiveCards_twoHalfAndThreeThirdSize() =
+ fun smartspace_dynamicSizing_fiveCards_threeThirdAndTwoHalfSize() =
testSmartspaceDynamicSizing(
totalTargets = 5,
expectedSizes =
listOf(
- CommunalContentSize.HALF,
- CommunalContentSize.HALF,
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
- )
+ CommunalContentSize.HALF,
+ CommunalContentSize.HALF,
+ ),
)
@Test
@@ -335,7 +325,7 @@ class CommunalInteractorTest : SysuiTestCase() {
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
- )
+ ),
)
private fun testSmartspaceDynamicSizing(
@@ -355,7 +345,7 @@ class CommunalInteractorTest : SysuiTestCase() {
smartspaceRepository.setTimers(targets)
- val smartspaceContent by collectLastValue(underTest.ongoingContent)
+ val smartspaceContent by collectLastValue(underTest.ongoingContent(false))
assertThat(smartspaceContent?.size).isEqualTo(totalTargets)
for (index in 0 until totalTargets) {
assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index])
@@ -371,7 +361,7 @@ class CommunalInteractorTest : SysuiTestCase() {
// Media is playing.
mediaRepository.mediaActive()
- val umoContent by collectLastValue(underTest.ongoingContent)
+ val umoContent by collectLastValue(underTest.ongoingContent(true))
assertThat(umoContent?.size).isEqualTo(1)
assertThat(umoContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java)
@@ -379,6 +369,19 @@ class CommunalInteractorTest : SysuiTestCase() {
}
@Test
+ fun umo_mediaPlaying_mediaHostNotVisible_hidesUmo() =
+ testScope.runTest {
+ // Tutorial completed.
+ tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+
+ // Media is playing.
+ mediaRepository.mediaActive()
+
+ val umoContent by collectLastValue(underTest.ongoingContent(false))
+ assertThat(umoContent?.size).isEqualTo(0)
+ }
+
+ @Test
fun ongoing_shouldOrderAndSizeByTimestamp() =
testScope.runTest {
// Keyguard showing, and tutorial completed.
@@ -401,19 +404,19 @@ class CommunalInteractorTest : SysuiTestCase() {
val timer3 = smartspaceTimer("timer3", timestamp = 4L)
smartspaceRepository.setTimers(listOf(timer1, timer2, timer3))
- val ongoingContent by collectLastValue(underTest.ongoingContent)
+ val ongoingContent by collectLastValue(underTest.ongoingContent(true))
assertThat(ongoingContent?.size).isEqualTo(4)
assertThat(ongoingContent?.get(0)?.key)
.isEqualTo(CommunalContentModel.KEY.smartspace("timer3"))
- assertThat(ongoingContent?.get(0)?.size).isEqualTo(CommunalContentSize.FULL)
+ assertThat(ongoingContent?.get(0)?.size).isEqualTo(CommunalContentSize.HALF)
assertThat(ongoingContent?.get(1)?.key)
.isEqualTo(CommunalContentModel.KEY.smartspace("timer2"))
- assertThat(ongoingContent?.get(1)?.size).isEqualTo(CommunalContentSize.THIRD)
+ assertThat(ongoingContent?.get(1)?.size).isEqualTo(CommunalContentSize.HALF)
assertThat(ongoingContent?.get(2)?.key).isEqualTo(CommunalContentModel.KEY.umo())
- assertThat(ongoingContent?.get(2)?.size).isEqualTo(CommunalContentSize.THIRD)
+ assertThat(ongoingContent?.get(2)?.size).isEqualTo(CommunalContentSize.HALF)
assertThat(ongoingContent?.get(3)?.key)
.isEqualTo(CommunalContentModel.KEY.smartspace("timer1"))
- assertThat(ongoingContent?.get(3)?.size).isEqualTo(CommunalContentSize.THIRD)
+ assertThat(ongoingContent?.get(3)?.size).isEqualTo(CommunalContentSize.HALF)
}
@Test
@@ -435,10 +438,7 @@ class CommunalInteractorTest : SysuiTestCase() {
testScope.runTest {
// Set to main user, so we can dismiss the tile for the main user.
val user = userRepository.asMainUser()
- userTracker.set(
- userInfos = listOf(user),
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = listOf(user), selectedUserIndex = 0)
runCurrent()
tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
@@ -816,10 +816,7 @@ class CommunalInteractorTest : SysuiTestCase() {
// Only main user exists.
val userInfos = listOf(MAIN_USER_INFO)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
runCurrent()
val widgetContent by collectLastValue(underTest.widgetContent)
@@ -853,10 +850,7 @@ class CommunalInteractorTest : SysuiTestCase() {
// Work profile is set up.
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
runCurrent()
// When work profile is paused.
@@ -899,10 +893,7 @@ class CommunalInteractorTest : SysuiTestCase() {
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
userRepository.setSelectedUserInfo(MAIN_USER_INFO)
runCurrent()
@@ -914,7 +905,7 @@ class CommunalInteractorTest : SysuiTestCase() {
setKeyguardFeaturesDisabled(
USER_INFO_WORK,
- DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
+ DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL,
)
// Widgets under work profile are filtered out. Only the regular widget remains.
@@ -932,10 +923,7 @@ class CommunalInteractorTest : SysuiTestCase() {
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
userRepository.setSelectedUserInfo(MAIN_USER_INFO)
runCurrent()
@@ -947,7 +935,7 @@ class CommunalInteractorTest : SysuiTestCase() {
setKeyguardFeaturesDisabled(
USER_INFO_WORK,
- DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE
+ DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE,
)
// Widgets under work profile are available.
@@ -967,7 +955,7 @@ class CommunalInteractorTest : SysuiTestCase() {
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isTrue()
@@ -983,7 +971,7 @@ class CommunalInteractorTest : SysuiTestCase() {
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isFalse()
@@ -999,7 +987,7 @@ class CommunalInteractorTest : SysuiTestCase() {
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
runCurrent()
kosmos.setCommunalAvailable(false)
@@ -1017,13 +1005,13 @@ class CommunalInteractorTest : SysuiTestCase() {
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
runCurrent()
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.OCCLUDED,
to = KeyguardState.PRIMARY_BOUNCER,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isTrue()
@@ -1039,7 +1027,7 @@ class CommunalInteractorTest : SysuiTestCase() {
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.DREAMING,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isTrue()
@@ -1049,7 +1037,7 @@ class CommunalInteractorTest : SysuiTestCase() {
return CommunalSmartspaceTimer(
smartspaceTargetId = id,
createdTimestampMillis = timestamp,
- remoteViews = mock(RemoteViews::class.java)
+ remoteViews = mock(RemoteViews::class.java),
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 780d3576c5e4..09daa51a3b37 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -43,6 +43,7 @@ import com.android.systemui.communal.domain.interactor.communalSettingsInteracto
import com.android.systemui.communal.domain.interactor.communalTutorialInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.log.CommunalMetricsLogger
+import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS
@@ -150,10 +151,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)
- kosmos.fakeUserTracker.set(
- userInfos = listOf(MAIN_USER_INFO),
- selectedUserIndex = 0,
- )
+ kosmos.fakeUserTracker.set(userInfos = listOf(MAIN_USER_INFO), selectedUserIndex = 0)
whenever(mediaHost.visible).thenReturn(true)
kosmos.powerInteractor.setAwakeForTest()
@@ -249,6 +247,87 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
+ fun ongoingContent_umoAndOneTimer_sizedAppropriately() =
+ testScope.runTest {
+ // Widgets available.
+ widgetRepository.addWidget(appWidgetId = 0, rank = 30)
+ widgetRepository.addWidget(appWidgetId = 1, rank = 20)
+
+ // Smartspace available.
+ smartspaceRepository.setTimers(
+ listOf(
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ )
+ )
+ )
+
+ // Media playing.
+ mediaRepository.mediaActive()
+
+ val communalContent by collectLastValue(underTest.communalContent)
+
+ // One timer, UMO, two widgets, and cta.
+ assertThat(communalContent?.size).isEqualTo(5)
+
+ val timer = communalContent?.get(0)
+ val umo = communalContent?.get(1)
+
+ assertThat(timer).isInstanceOf(CommunalContentModel.Smartspace::class.java)
+ assertThat(umo).isInstanceOf(CommunalContentModel.Umo::class.java)
+
+ assertThat(timer?.size).isEqualTo(CommunalContentSize.HALF)
+ assertThat(umo?.size).isEqualTo(CommunalContentSize.HALF)
+ }
+
+ @Test
+ fun ongoingContent_umoAndTwoTimers_sizedAppropriately() =
+ testScope.runTest {
+ // Widgets available.
+ widgetRepository.addWidget(appWidgetId = 0, rank = 30)
+ widgetRepository.addWidget(appWidgetId = 1, rank = 20)
+
+ // Smartspace available.
+ smartspaceRepository.setTimers(
+ listOf(
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ ),
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ ),
+ )
+ )
+
+ // Media playing.
+ mediaRepository.mediaActive()
+
+ val communalContent by collectLastValue(underTest.communalContent)
+
+ // Two timers, UMO, two widgets, and cta.
+ assertThat(communalContent?.size).isEqualTo(6)
+
+ val timer1 = communalContent?.get(0)
+ val timer2 = communalContent?.get(1)
+ val umo = communalContent?.get(2)
+
+ assertThat(timer1).isInstanceOf(CommunalContentModel.Smartspace::class.java)
+ assertThat(timer2).isInstanceOf(CommunalContentModel.Smartspace::class.java)
+ assertThat(umo).isInstanceOf(CommunalContentModel.Umo::class.java)
+
+ // One full-sized timer and a half-sized timer and half-sized UMO.
+ assertThat(timer1?.size).isEqualTo(CommunalContentSize.HALF)
+ assertThat(timer2?.size).isEqualTo(CommunalContentSize.HALF)
+ assertThat(umo?.size).isEqualTo(CommunalContentSize.FULL)
+ }
+
+ @Test
fun communalContent_mediaHostVisible_umoIncluded() =
testScope.runTest {
// Media playing.
@@ -497,7 +576,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GLANCEABLE_HUB,
- )
+ ),
)
// Shade not expanded.
if (!SceneContainerFlag.isEnabled) shadeTestUtil.setLockscreenShadeExpansion(0f)
@@ -550,8 +629,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
stateTransition =
TransitionStep(
from = KeyguardState.DREAMING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
+ to = KeyguardState.GLANCEABLE_HUB
+ ),
)
// Then flow is not frozen
@@ -570,8 +649,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
stateTransition =
TransitionStep(
from = KeyguardState.GLANCEABLE_HUB,
- to = KeyguardState.OCCLUDED,
- )
+ to = KeyguardState.OCCLUDED
+ ),
)
// Then flow is not frozen
@@ -595,7 +674,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GLANCEABLE_HUB,
- )
+ ),
)
// Then flow is not frozen
@@ -614,7 +693,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
to = KeyguardState.OCCLUDED,
transitionState = TransitionState.STARTED,
value = 0f,
- )
+ ),
)
// Then flow is frozen
@@ -629,7 +708,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
to = KeyguardState.OCCLUDED,
transitionState = TransitionState.FINISHED,
value = 1f,
- )
+ ),
)
// Then flow is not frozen
@@ -658,8 +737,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
stateTransition =
TransitionStep(
from = KeyguardState.DREAMING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
+ to = KeyguardState.GLANCEABLE_HUB
+ ),
)
// Widgets available
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index b570e14c646a..a687734ff499 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -117,7 +117,7 @@ constructor(
sceneInteractor: SceneInteractor,
@CommunalLog logBuffer: LogBuffer,
@CommunalTableLog tableLogBuffer: TableLogBuffer,
- private val managedProfileController: ManagedProfileController
+ private val managedProfileController: ManagedProfileController,
) {
private val logger = Logger(logBuffer, "CommunalInteractor")
@@ -154,7 +154,7 @@ constructor(
allOf(
communalSettingsInteractor.isCommunalEnabled,
not(keyguardInteractor.isEncryptedOrLockdown),
- keyguardInteractor.isKeyguardShowing
+ keyguardInteractor.isKeyguardShowing,
)
.distinctUntilChanged()
.onEach { available ->
@@ -342,7 +342,7 @@ constructor(
fun changeScene(
newScene: SceneKey,
loggingReason: String,
- transitionKey: TransitionKey? = null
+ transitionKey: TransitionKey? = null,
) = communalSceneInteractor.changeScene(newScene, loggingReason, transitionKey)
fun setEditModeOpen(isOpen: Boolean) {
@@ -354,9 +354,7 @@ constructor(
}
/** Show the widget editor Activity. */
- fun showWidgetEditor(
- shouldOpenWidgetPickerOnStart: Boolean = false,
- ) {
+ fun showWidgetEditor(shouldOpenWidgetPickerOnStart: Boolean = false) {
communalSceneInteractor.setEditModeState(EditModeState.STARTING)
editWidgetsActivityStarter.startActivity(shouldOpenWidgetPickerOnStart)
}
@@ -419,7 +417,7 @@ constructor(
IntentFilter().apply {
addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
- },
+ }
)
.emitOnStart()
@@ -450,7 +448,7 @@ constructor(
rank = widget.rank,
providerInfo = widget.providerInfo,
appWidgetHost = appWidgetHost,
- inQuietMode = isQuietModeEnabled(widget.providerInfo.profile)
+ inQuietMode = isQuietModeEnabled(widget.providerInfo.profile),
)
}
is CommunalWidgetContentModel.Pending -> {
@@ -468,7 +466,7 @@ constructor(
/** Filter widgets based on whether their associated profile is allowed by device policy. */
private fun filterWidgetsAllowedByDevicePolicy(
list: List<CommunalWidgetContentModel>,
- disallowedByDevicePolicyUser: UserInfo?
+ disallowedByDevicePolicyUser: UserInfo?,
): List<CommunalWidgetContentModel> =
if (disallowedByDevicePolicyUser == null) {
list
@@ -507,7 +505,7 @@ constructor(
* A flow of ongoing content, including smartspace timers and umo, ordered by creation time and
* sized dynamically.
*/
- val ongoingContent: Flow<List<CommunalContentModel.Ongoing>> =
+ fun ongoingContent(isMediaHostVisible: Boolean): Flow<List<CommunalContentModel.Ongoing>> =
combine(smartspaceRepository.timers, mediaRepository.mediaModel) { timers, media ->
val ongoingContent = mutableListOf<CommunalContentModel.Ongoing>()
@@ -523,22 +521,20 @@ constructor(
)
// Add UMO
- if (media.hasAnyMediaOrRecommendation) {
+ if (isMediaHostVisible && media.hasAnyMediaOrRecommendation) {
ongoingContent.add(
CommunalContentModel.Umo(
- createdTimestampMillis = media.createdTimestampMillis,
+ createdTimestampMillis = media.createdTimestampMillis
)
)
}
- // Order by creation time descending
+ // Order by creation time descending.
ongoingContent.sortByDescending { it.createdTimestampMillis }
+ // Resize the items.
+ ongoingContent.resizeItems()
- // Dynamic sizing
- ongoingContent.forEachIndexed { index, model ->
- model.size = dynamicContentSize(ongoingContent.size, index)
- }
-
+ // Return the sorted and resized items.
ongoingContent
}
.flowOn(bgDispatcher)
@@ -548,7 +544,7 @@ constructor(
* stale data following user deletion.
*/
private fun filterWidgetsByExistingUsers(
- list: List<CommunalWidgetContentModel>,
+ list: List<CommunalWidgetContentModel>
): List<CommunalWidgetContentModel> {
val currentUserIds = userTracker.userProfiles.map { it.id }.toSet()
return list.filter { widget ->
@@ -560,6 +556,40 @@ constructor(
}
}
+ // Dynamically resizes the height of items in the list of ongoing items such that they fit in
+ // columns in as compact a space as possible.
+ //
+ // Currently there are three possible sizes. When the total number is 1, size for that content
+ // is [FULL], when the total number is 2, size for each is [HALF], and 3, size for each is
+ // [THIRD].
+ //
+ // This algorithm also respects each item's minimum size. All items in a column will have the
+ // same size, and all items in a column will be no smaller than any item's minimum size.
+ private fun List<CommunalContentModel.Ongoing>.resizeItems() {
+ fun resizeColumn(c: List<CommunalContentModel.Ongoing>) {
+ if (c.isEmpty()) return
+ val newSize = CommunalContentSize.toSize(span = FULL.span / c.size)
+ c.forEach { item -> item.size = newSize }
+ }
+
+ val column = mutableListOf<CommunalContentModel.Ongoing>()
+ var available = FULL.span
+
+ forEach { item ->
+ if (available < item.minSize.span) {
+ resizeColumn(column)
+ column.clear()
+ available = FULL.span
+ }
+
+ column.add(item)
+ available -= item.minSize.span
+ }
+
+ // Make sure to resize the final column.
+ resizeColumn(column)
+ }
+
companion object {
const val TAG = "CommunalInteractor"
@@ -574,31 +604,6 @@ constructor(
* of -1 means that the user's chosen screen timeout will be used instead.
*/
const val AWAKE_INTERVAL_MS = -1
-
- /**
- * Calculates the content size dynamically based on the total number of contents of that
- * type.
- *
- * Contents with the same type are expected to fill each column evenly. Currently there are
- * three possible sizes. When the total number is 1, size for that content is [FULL], when
- * the total number is 2, size for each is [HALF], and 3, size for each is [THIRD].
- *
- * When dynamic contents fill in multiple columns, the first column follows the algorithm
- * above, and the remaining contents are packed in [THIRD]s. For example, when the total
- * number if 4, the first one is [FULL], filling the column, and the remaining 3 are
- * [THIRD].
- *
- * @param size The total number of contents of this type.
- * @param index The index of the current content of this type.
- */
- private fun dynamicContentSize(size: Int, index: Int): CommunalContentSize {
- val remainder = size % CommunalContentSize.entries.size
- return CommunalContentSize.toSize(
- span =
- FULL.span /
- if (index > remainder - 1) CommunalContentSize.entries.size else remainder
- )
- }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index 4c821d482eef..c2f6e85a33e4 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -34,12 +34,18 @@ sealed interface CommunalContentModel {
/** Size to be rendered in the grid. */
val size: CommunalContentSize
+ /** The minimum size content can be resized to. */
+ val minSize: CommunalContentSize
+ get() = CommunalContentSize.HALF
+
/**
* A type of communal content is ongoing / live / ephemeral, and can be sized and ordered
* dynamically.
*/
sealed interface Ongoing : CommunalContentModel {
override var size: CommunalContentSize
+ override val minSize
+ get() = CommunalContentSize.THIRD
/** Timestamp in milliseconds of when the content was created. */
val createdTimestampMillis: Long
@@ -72,7 +78,7 @@ sealed interface CommunalContentModel {
data class DisabledWidget(
override val appWidgetId: Int,
override val rank: Int,
- val providerInfo: AppWidgetProviderInfo
+ val providerInfo: AppWidgetProviderInfo,
) : WidgetContent {
override val key = KEY.disabledWidget(appWidgetId)
override val componentName: ComponentName = providerInfo.provider
@@ -109,10 +115,7 @@ sealed interface CommunalContentModel {
override val size = CommunalContentSize.HALF
}
- class Tutorial(
- id: Int,
- override var size: CommunalContentSize,
- ) : CommunalContentModel {
+ class Tutorial(id: Int, override var size: CommunalContentSize) : CommunalContentModel {
override val key = KEY.tutorial(id)
}
@@ -128,6 +131,7 @@ sealed interface CommunalContentModel {
class Umo(
override val createdTimestampMillis: Long,
override var size: CommunalContentSize = CommunalContentSize.HALF,
+ override var minSize: CommunalContentSize = CommunalContentSize.HALF,
) : Ongoing {
override val key = KEY.umo()
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index d69ba1b23aa3..53109ac69fa9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -125,15 +125,9 @@ constructor(
private var frozenCommunalContent: List<CommunalContentModel>? = null
private val ongoingContent =
- combine(
- isMediaHostVisible,
- communalInteractor.ongoingContent.onEach { mediaHost.updateViewVisibility() }
- ) { mediaVisible, ongoingContent ->
- if (mediaVisible) {
- ongoingContent
- } else {
- // Media is not visible, don't show UMO
- ongoingContent.filterNot { it is CommunalContentModel.Umo }
+ isMediaHostVisible.flatMapLatest { isMediaHostVisible ->
+ communalInteractor.ongoingContent(isMediaHostVisible).onEach {
+ mediaHost.updateViewVisibility()
}
}
@@ -148,8 +142,7 @@ constructor(
ongoingContent,
communalInteractor.widgetContent,
communalInteractor.ctaTileContent,
- ) { ongoing, widgets, ctaTile,
- ->
+ ) { ongoing, widgets, ctaTile ->
ongoing + widgets + ctaTile
}
}
@@ -172,10 +165,10 @@ constructor(
allOf(
keyguardTransitionInteractor.isFinishedIn(
scene = Scenes.Communal,
- stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB
+ stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB,
),
keyguardInteractor.isKeyguardOccluded,
- not(keyguardInteractor.isAbleToDream)
+ not(keyguardInteractor.isAbleToDream),
)
.distinctUntilChanged()
.onEach { logger.d("isCommunalContentFlowFrozen: $it") }
@@ -208,7 +201,7 @@ constructor(
combine(
keyguardTransitionInteractor.isFinishedIn(
scene = Scenes.Communal,
- stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB
+ stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB,
),
communalInteractor.isIdleOnCommunal,
shadeInteractor.isAnyFullyExpanded,
@@ -221,7 +214,7 @@ constructor(
object : View.AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(
host: View,
- info: AccessibilityNodeInfo
+ info: AccessibilityNodeInfo,
) {
super.onInitializeAccessibilityNodeInfo(host, info)
// Hint user to long press in order to enter edit mode
@@ -230,7 +223,7 @@ constructor(
AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id,
resources
.getString(R.string.accessibility_action_label_edit_widgets)
- .lowercase()
+ .lowercase(),
)
)
}
@@ -238,7 +231,7 @@ constructor(
override fun performAccessibilityAction(
host: View,
action: Int,
- args: Bundle?
+ args: Bundle?,
): Boolean {
when (action) {
AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id -> {
@@ -271,9 +264,7 @@ constructor(
}
}
- override fun onOpenWidgetEditor(
- shouldOpenWidgetPickerOnStart: Boolean,
- ) {
+ override fun onOpenWidgetEditor(shouldOpenWidgetPickerOnStart: Boolean) {
persistScrollPosition()
communalInteractor.showWidgetEditor(shouldOpenWidgetPickerOnStart)
}