diff options
| author | 2024-09-13 16:18:59 +0000 | |
|---|---|---|
| committer | 2024-09-13 16:18:59 +0000 | |
| commit | 2aa3af4aa5c3109ed6815d4939349ffc68601ee9 (patch) | |
| tree | 17131f78acd78b8e3937cbabc5bdd13f05c22cad | |
| parent | 61a577c01eca720a1f38cb07f1d5e65b3883beec (diff) | |
| parent | 4bd9ef2ad5c7e0e3d6269a1fcd5191fe4579fde8 (diff) | |
Merge "Don't allow UMO to shrink to 1/3 size." into main
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) } |