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

Commit c0d2dfe2 authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Support grouping in the New App List"

parents 02739712 a907c9d9
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -53,6 +53,14 @@ interface AppListModel<T : AppRecord> {
        { it.record.app.uid },
    )

    /**
     * Gets the group title of this item.
     *
     * Note: Items should be sorted by group in [getComparator] first, this [getGroupTitle] will not
     * change the list order.
     */
    fun getGroupTitle(option: Int, record: T): String? = null

    /**
     * Gets the summary for the given app record.
     *
+16 −3
Original line number Diff line number Diff line
@@ -34,9 +34,11 @@ import com.android.settingslib.spa.framework.compose.LogCompositions
import com.android.settingslib.spa.framework.compose.TimeMeasurer.Companion.rememberTimeMeasurer
import com.android.settingslib.spa.framework.compose.rememberLazyListStateAndHideKeyboardWhenStartScroll
import com.android.settingslib.spa.framework.compose.toState
import com.android.settingslib.spa.widget.ui.CategoryTitle
import com.android.settingslib.spa.widget.ui.PlaceholderTitle
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.framework.compose.DisposableBroadcastReceiverAsUser
import com.android.settingslib.spaprivileged.model.app.AppEntry
import com.android.settingslib.spaprivileged.model.app.AppListConfig
import com.android.settingslib.spaprivileged.model.app.AppListData
import com.android.settingslib.spaprivileged.model.app.AppListModel
@@ -100,15 +102,26 @@ private fun <T : AppRecord> AppListWidget(
            }

            items(count = list.size, key = { option to list[it].record.app.packageName }) {
                remember(list) { listModel.getGroupTitleIfFirst(option, list, it) }
                    ?.let { group -> CategoryTitle(title = group) }

                val appEntry = list[it]
                val summary = listModel.getSummary(option, appEntry.record) ?: "".toState()
                val itemModel = remember(appEntry) {
                appItem(remember(appEntry) {
                    AppListItemModel(appEntry.record, appEntry.label, summary)
                })
            }
                appItem(itemModel)
        }
    }
}

/** Returns group title if this is the first item of the group. */
private fun <T : AppRecord> AppListModel<T>.getGroupTitleIfFirst(
    option: Int,
    list: List<AppEntry<T>>,
    index: Int,
): String? = getGroupTitle(option, list[index].record)?.takeIf {
    index == 0 || it != getGroupTitle(option, list[index - 1].record)
}

@Composable
+50 −10
Original line number Diff line number Diff line
@@ -58,26 +58,43 @@ class AppListTest {

    @Test
    fun couldShowAppItem() {
        setContent(appEntries = listOf(APP_ENTRY))
        setContent(appEntries = listOf(APP_ENTRY_A))

        composeTestRule.onNodeWithText(APP_ENTRY.label).assertIsDisplayed()
        composeTestRule.onNodeWithText(APP_ENTRY_A.label).assertIsDisplayed()
    }

    @Test
    fun couldShowHeader() {
        setContent(header = { Text(HEADER) }, appEntries = listOf(APP_ENTRY))
        setContent(appEntries = listOf(APP_ENTRY_A), header = { Text(HEADER) })

        composeTestRule.onNodeWithText(HEADER).assertIsDisplayed()
    }

    @Test
    fun whenNotGrouped_groupTitleDoesNotExist() {
        setContent(appEntries = listOf(APP_ENTRY_A, APP_ENTRY_B), enableGrouping = false)

        composeTestRule.onNodeWithText(GROUP_A).assertDoesNotExist()
        composeTestRule.onNodeWithText(GROUP_B).assertDoesNotExist()
    }

    @Test
    fun whenGrouped_groupTitleDisplayed() {
        setContent(appEntries = listOf(APP_ENTRY_A, APP_ENTRY_B), enableGrouping = true)

        composeTestRule.onNodeWithText(GROUP_A).assertIsDisplayed()
        composeTestRule.onNodeWithText(GROUP_B).assertIsDisplayed()
    }

    private fun setContent(
        header: @Composable () -> Unit = {},
        appEntries: List<AppEntry<TestAppRecord>>,
        header: @Composable () -> Unit = {},
        enableGrouping: Boolean = false,
    ) {
        composeTestRule.setContent {
            AppList(
                config = AppListConfig(userId = USER_ID, showInstantApps = false),
                listModel = TestAppListModel(),
                listModel = TestAppListModel(enableGrouping),
                state = AppListState(
                    showSystem = false.toState(),
                    option = 0.toState(),
@@ -96,17 +113,37 @@ class AppListTest {
    private companion object {
        const val USER_ID = 0
        const val HEADER = "Header"
        val APP_ENTRY = AppEntry(
            record = TestAppRecord(ApplicationInfo()),
            label = "AAA",
        const val GROUP_A = "Group A"
        const val GROUP_B = "Group B"
        val APP_ENTRY_A = AppEntry(
            record = TestAppRecord(
                app = ApplicationInfo().apply {
                    packageName = "package.name.a"
                },
                group = GROUP_A,
            ),
            label = "Label A",
            labelCollationKey = CollationKey("", byteArrayOf()),
        )
        val APP_ENTRY_B = AppEntry(
            record = TestAppRecord(
                app = ApplicationInfo().apply {
                    packageName = "package.name.b"
                },
                group = GROUP_B,
            ),
            label = "Label B",
            labelCollationKey = CollationKey("", byteArrayOf()),
        )
    }
}

private data class TestAppRecord(override val app: ApplicationInfo) : AppRecord
private data class TestAppRecord(
    override val app: ApplicationInfo,
    val group: String? = null,
) : AppRecord

private class TestAppListModel : AppListModel<TestAppRecord> {
private class TestAppListModel(val enableGrouping: Boolean) : AppListModel<TestAppRecord> {
    override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
        appListFlow.asyncMapItem { TestAppRecord(it) }

@@ -118,4 +155,7 @@ private class TestAppListModel : AppListModel<TestAppRecord> {
        option: Int,
        recordListFlow: Flow<List<TestAppRecord>>,
    ) = recordListFlow

    override fun getGroupTitle(option: Int, record: TestAppRecord) =
        if (enableGrouping) record.group else null
}