Merge "Add spinner options to "All apps""
diff --git a/src/com/android/settings/spa/app/AllAppList.kt b/src/com/android/settings/spa/app/AllAppList.kt
index 05f77ed..08b06a6 100644
--- a/src/com/android/settings/spa/app/AllAppList.kt
+++ b/src/com/android/settings/spa/app/AllAppList.kt
@@ -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.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 @@
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 @@
) : 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);
+}
diff --git a/src/com/android/settings/spa/development/UsageStatsListModel.kt b/src/com/android/settings/spa/development/UsageStatsListModel.kt
index caa30cc..61c24ac 100644
--- a/src/com/android/settings/spa/development/UsageStatsListModel.kt
+++ b/src/com/android/settings/spa/development/UsageStatsListModel.kt
@@ -26,6 +26,7 @@
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,9 +54,13 @@
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(
userIdFlow: Flow<Int>,
@@ -75,7 +80,8 @@
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"
diff --git a/src/com/android/settings/spa/notification/AppNotificationsListModel.kt b/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
index 29c8a2b..028b2f4 100644
--- a/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
+++ b/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
@@ -30,6 +30,7 @@
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 @@
}
}
- 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,9 +99,13 @@
}
}
- 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) =
StringUtil.formatRelativeTime(
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
index b767912..b5dfddc 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
@@ -121,7 +121,7 @@
@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 @@
@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 @@
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 @@
private fun setItemContent() {
composeTestRule.setContent {
fakeNavControllerWrapper.Wrapper {
- with(AllAppListModel()) {
+ with(AllAppListModel(context)) {
AppListItemModel(
record = AppRecordWithSize(app = APP),
label = LABEL,