Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3316df19 authored by Darrell Shi's avatar Darrell Shi Committed by Android (Google) Code Review
Browse files

Merge "Size smartspace cards dynamically" into main

parents 2e0beb06 8a7a57eb
Loading
Loading
Loading
Loading
+104 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.systemui.communal.data.repository.FakeCommunalRepository
import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalSceneKey
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
@@ -168,6 +169,109 @@ class CommunalInteractorTest : SysuiTestCase() {
            assertThat(smartspaceContent?.get(0)?.key).isEqualTo("smartspace_target3")
        }

    @Test
    fun smartspaceDynamicSizing_oneCard_fullSize() =
        testSmartspaceDynamicSizing(
            totalTargets = 1,
            expectedSizes =
                listOf(
                    CommunalContentSize.FULL,
                )
        )

    @Test
    fun smartspace_dynamicSizing_twoCards_halfSize() =
        testSmartspaceDynamicSizing(
            totalTargets = 2,
            expectedSizes =
                listOf(
                    CommunalContentSize.HALF,
                    CommunalContentSize.HALF,
                )
        )

    @Test
    fun smartspace_dynamicSizing_threeCards_thirdSize() =
        testSmartspaceDynamicSizing(
            totalTargets = 3,
            expectedSizes =
                listOf(
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                )
        )

    @Test
    fun smartspace_dynamicSizing_fourCards_oneFullAndThreeThirdSize() =
        testSmartspaceDynamicSizing(
            totalTargets = 4,
            expectedSizes =
                listOf(
                    CommunalContentSize.FULL,
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                )
        )

    @Test
    fun smartspace_dynamicSizing_fiveCards_twoHalfAndThreeThirdSize() =
        testSmartspaceDynamicSizing(
            totalTargets = 5,
            expectedSizes =
                listOf(
                    CommunalContentSize.HALF,
                    CommunalContentSize.HALF,
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                )
        )

    @Test
    fun smartspace_dynamicSizing_sixCards_allThirdSize() =
        testSmartspaceDynamicSizing(
            totalTargets = 6,
            expectedSizes =
                listOf(
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                    CommunalContentSize.THIRD,
                )
        )

    private fun testSmartspaceDynamicSizing(
        totalTargets: Int,
        expectedSizes: List<CommunalContentSize>,
    ) =
        testScope.runTest {
            // Keyguard showing, and tutorial completed.
            keyguardRepository.setKeyguardShowing(true)
            keyguardRepository.setKeyguardOccluded(false)
            tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)

            val targets = mutableListOf<SmartspaceTarget>()
            for (index in 0 until totalTargets) {
                val target = mock(SmartspaceTarget::class.java)
                whenever(target.smartspaceTargetId).thenReturn("target$index")
                whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
                whenever(target.remoteViews).thenReturn(mock(RemoteViews::class.java))
                targets.add(target)
            }

            smartspaceRepository.setCommunalSmartspaceTargets(targets)

            val smartspaceContent by collectLastValue(underTest.smartspaceContent)
            assertThat(smartspaceContent?.size).isEqualTo(totalTargets)
            for (index in 0 until totalTargets) {
                assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index])
            }
        }

    @Test
    fun umo_mediaPlaying_showsUmo() =
        testScope.runTest {
+41 −12
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ import com.android.systemui.communal.data.repository.CommunalRepository
import com.android.systemui.communal.data.repository.CommunalWidgetRepository
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalContentSize.FULL
import com.android.systemui.communal.shared.model.CommunalContentSize.HALF
import com.android.systemui.communal.shared.model.CommunalContentSize.THIRD
import com.android.systemui.communal.shared.model.CommunalSceneKey
import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
@@ -133,12 +136,11 @@ constructor(
                        target.featureType == SmartspaceTarget.FEATURE_TIMER &&
                            target.remoteViews != null
                    }
                    .map Target@{ target ->
                    .mapIndexed Target@{ index, target ->
                        return@Target CommunalContentModel.Smartspace(
                            smartspaceTargetId = target.smartspaceTargetId,
                            remoteViews = target.remoteViews!!,
                            // Smartspace always as HALF for now.
                            size = CommunalContentSize.HALF,
                            size = dynamicContentSize(targets.size, index),
                        )
                    }
            }
@@ -147,23 +149,50 @@ constructor(
    /** A list of tutorial content to be displayed in the communal hub in tutorial mode. */
    val tutorialContent: List<CommunalContentModel.Tutorial> =
        listOf(
            CommunalContentModel.Tutorial(id = 0, CommunalContentSize.FULL),
            CommunalContentModel.Tutorial(id = 1, CommunalContentSize.THIRD),
            CommunalContentModel.Tutorial(id = 2, CommunalContentSize.THIRD),
            CommunalContentModel.Tutorial(id = 3, CommunalContentSize.THIRD),
            CommunalContentModel.Tutorial(id = 4, CommunalContentSize.HALF),
            CommunalContentModel.Tutorial(id = 5, CommunalContentSize.HALF),
            CommunalContentModel.Tutorial(id = 6, CommunalContentSize.HALF),
            CommunalContentModel.Tutorial(id = 7, CommunalContentSize.HALF),
            CommunalContentModel.Tutorial(id = 0, FULL),
            CommunalContentModel.Tutorial(id = 1, THIRD),
            CommunalContentModel.Tutorial(id = 2, THIRD),
            CommunalContentModel.Tutorial(id = 3, THIRD),
            CommunalContentModel.Tutorial(id = 4, HALF),
            CommunalContentModel.Tutorial(id = 5, HALF),
            CommunalContentModel.Tutorial(id = 6, HALF),
            CommunalContentModel.Tutorial(id = 7, HALF),
        )

    val umoContent: Flow<List<CommunalContentModel.Umo>> =
        mediaRepository.mediaPlaying.flatMapLatest { mediaPlaying ->
            if (mediaPlaying) {
                // TODO(b/310254801): support HALF and FULL layouts
                flowOf(listOf(CommunalContentModel.Umo(CommunalContentSize.THIRD)))
                flowOf(listOf(CommunalContentModel.Umo(THIRD)))
            } else {
                flowOf(emptyList())
            }
        }

    companion object {
        /**
         * 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
            )
        }
    }
}
+9 −1
Original line number Diff line number Diff line
@@ -30,5 +30,13 @@ enum class CommunalContentSize(val span: Int) {
    HALF(3),

    /** Content takes a third of the height of the column. */
    THIRD(2),
    THIRD(2);

    companion object {
        /** Converts from span to communal content size. */
        fun toSize(span: Int): CommunalContentSize {
            return entries.find { it.span == span }
                ?: throw Exception("Invalid span for communal content size")
        }
    }
}