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

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

Merge "Add spinner options to "All apps""

parents 181119f0 74b3bfc0
Loading
Loading
Loading
Loading
+62 −3
Original line number Diff line number Diff line
@@ -16,10 +16,12 @@

package com.android.settings.spa.app

import android.content.Context
import android.content.pm.ApplicationInfo
import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.res.stringResource
import com.android.settings.R
@@ -28,9 +30,12 @@ import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.rememberContext
import com.android.settingslib.spa.framework.util.filterItem
import com.android.settingslib.spa.framework.util.mapItem
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.template.app.AppList
@@ -67,7 +72,7 @@ fun AllAppListPage(
    val resetAppDialogPresenter = rememberResetAppDialogPresenter()
    AppListPage(
        title = stringResource(R.string.all_apps),
        listModel = remember { AllAppListModel() },
        listModel = rememberContext(::AllAppListModel),
        showInstantApps = true,
        moreOptions = { ResetAppPreferences(resetAppDialogPresenter::open) },
        appList = appList,
@@ -79,17 +84,71 @@ data class AppRecordWithSize(
) : AppRecord

class AllAppListModel(
    private val getSummary: @Composable ApplicationInfo.() -> State<String> = { getStorageSize() },
    private val context: Context,
    private val getStorageSummary: @Composable ApplicationInfo.() -> State<String> = {
        getStorageSize()
    },
) : AppListModel<AppRecordWithSize> {

    override fun getSpinnerOptions(recordList: List<AppRecordWithSize>): List<SpinnerOption> {
        val hasDisabled = recordList.any(isDisabled)
        val hasInstant = recordList.any(isInstant)
        if (!hasDisabled && !hasInstant) return emptyList()
        val options = mutableListOf(SpinnerItem.All, SpinnerItem.Enabled)
        if (hasDisabled) options += SpinnerItem.Disabled
        if (hasInstant) options += SpinnerItem.Instant
        return options.map {
            SpinnerOption(
                id = it.ordinal,
                text = context.getString(it.stringResId),
            )
        }
    }

    override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
        appListFlow.mapItem(::AppRecordWithSize)

    override fun filter(
        userIdFlow: Flow<Int>,
        option: Int,
        recordListFlow: Flow<List<AppRecordWithSize>>,
    ): Flow<List<AppRecordWithSize>> = recordListFlow.filterItem(
        when (SpinnerItem.values().getOrNull(option)) {
            SpinnerItem.Enabled -> ({ it.app.enabled && !it.app.isInstantApp })
            SpinnerItem.Disabled -> isDisabled
            SpinnerItem.Instant -> isInstant
            else -> ({ true })
        }
    )

    private val isDisabled: (AppRecordWithSize) -> Boolean =
        { !it.app.enabled && !it.app.isInstantApp }

    private val isInstant: (AppRecordWithSize) -> Boolean = { it.app.isInstantApp }

    @Composable
    override fun getSummary(option: Int, record: AppRecordWithSize) = record.app.getSummary()
    override fun getSummary(option: Int, record: AppRecordWithSize): State<String> {
        val storageSummary = record.app.getStorageSummary()
        return remember {
            derivedStateOf {
                storageSummary.value +
                    when (isDisabled(record)) {
                        true -> System.lineSeparator() + context.getString(R.string.disabled)
                        else -> ""
                    }
            }
        }
    }

    @Composable
    override fun AppListItemModel<AppRecordWithSize>.AppItem() {
        AppListItem(onClick = AppInfoSettingsProvider.navigator(app = record.app))
    }
}

private enum class SpinnerItem(val stringResId: Int) {
    All(R.string.filter_all_apps),
    Enabled(R.string.filter_enabled_apps),
    Disabled(R.string.filter_apps_disabled),
    Instant(R.string.filter_instant_apps);
}
+10 −4
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import androidx.compose.runtime.State
import com.android.settings.R
import com.android.settings.spa.development.UsageStatsListModel.SpinnerItem.Companion.toSpinnerItem
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.model.app.AppEntry
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
@@ -53,8 +54,12 @@ class UsageStatsListModel(private val context: Context) : AppListModel<UsageStat
            appList.map { app -> UsageStatsAppRecord(app, usageStatsMap[app.packageName]) }
        }

    override fun getSpinnerOptions() = SpinnerItem.values().map {
        context.getString(it.stringResId)
    override fun getSpinnerOptions(recordList: List<UsageStatsAppRecord>): List<SpinnerOption> =
        SpinnerItem.values().map {
            SpinnerOption(
                id = it.ordinal,
                text = context.getString(it.stringResId),
            )
        }

    override fun filter(
@@ -75,7 +80,8 @@ class UsageStatsListModel(private val context: Context) : AppListModel<UsageStat
    override fun getSummary(option: Int, record: UsageStatsAppRecord): State<String>? {
        val usageStats = record.usageStats ?: return null
        val lastTimeUsed = DateUtils.formatSameDayTime(
            usageStats.lastTimeUsed, now, DateFormat.MEDIUM, DateFormat.MEDIUM)
            usageStats.lastTimeUsed, now, DateFormat.MEDIUM, DateFormat.MEDIUM
        )
        val lastTimeUsedLine = "${context.getString(R.string.last_time_used_label)}: $lastTimeUsed"
        val usageTime = DateUtils.formatElapsedTime(usageStats.totalTimeInForeground / 1000)
        val usageTimeLine = "${context.getString(R.string.usage_time_label)}: $usageTime"
+10 −4
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.settings.spa.notification.SpinnerItem.Companion.toSpinnerItem
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.framework.util.asyncFilter
import com.android.settingslib.spa.framework.util.asyncForEach
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.model.app.AppEntry
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
@@ -78,8 +79,9 @@ class AppNotificationsListModel(
        }
    }

    override suspend fun onFirstLoaded(recordList: List<AppNotificationsRecord>) {
    override suspend fun onFirstLoaded(recordList: List<AppNotificationsRecord>): Boolean {
        recordList.asyncForEach { it.controller.getEnabled() }
        return true
    }

    override fun getComparator(option: Int) = when (option.toSpinnerItem()) {
@@ -97,8 +99,12 @@ class AppNotificationsListModel(
        }
    }

    override fun getSpinnerOptions() = SpinnerItem.values().map {
        context.getString(it.stringResId)
    override fun getSpinnerOptions(recordList: List<AppNotificationsRecord>): List<SpinnerOption> =
        SpinnerItem.values().map {
            SpinnerOption(
                id = it.ordinal,
                text = context.getString(it.stringResId),
            )
        }

    private fun formatLastSent(lastSent: Long) =
+20 −3
Original line number Diff line number Diff line
@@ -121,7 +121,7 @@ class AllAppListTest {
    @OptIn(ExperimentalCoroutinesApi::class)
    @Test
    fun allAppListModel_transform() = runTest {
        val listModel = AllAppListModel { stateOf(SUMMARY) }
        val listModel = AllAppListModel(context) { stateOf(SUMMARY) }

        val recordListFlow = listModel.transform(flowOf(USER_ID), flowOf(listOf(APP)))

@@ -132,7 +132,7 @@ class AllAppListTest {

    @Test
    fun allAppListModel_getSummary() {
        val listModel = AllAppListModel { stateOf(SUMMARY) }
        val listModel = AllAppListModel(context) { stateOf(SUMMARY) }

        lateinit var summaryState: State<String>
        composeTestRule.setContent {
@@ -142,6 +142,23 @@ class AllAppListTest {
        assertThat(summaryState.value).isEqualTo(SUMMARY)
    }

    @Test
    fun allAppListModel_getSummaryWhenDisabled() {
        val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
        val disabledApp = ApplicationInfo().apply {
            packageName = PACKAGE_NAME
            enabled = false
        }

        lateinit var summaryState: State<String>
        composeTestRule.setContent {
            summaryState =
                listModel.getSummary(option = 0, record = AppRecordWithSize(app = disabledApp))
        }

        assertThat(summaryState.value).isEqualTo("$SUMMARY${System.lineSeparator()}Disabled")
    }

    private fun getAppListInput(): AppListInput<AppRecordWithSize> {
        lateinit var input: AppListInput<AppRecordWithSize>
        composeTestRule.setContent {
@@ -157,7 +174,7 @@ class AllAppListTest {
    private fun setItemContent() {
        composeTestRule.setContent {
            fakeNavControllerWrapper.Wrapper {
                with(AllAppListModel()) {
                with(AllAppListModel(context)) {
                    AppListItemModel(
                        record = AppRecordWithSize(app = APP),
                        label = LABEL,