blob: 383a0e8ea2eff2615b8bdb4f77a502ddf2cf0620 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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
import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.createSettingsPage
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.model.app.installed
import com.android.settingslib.spaprivileged.template.app.AppList
import com.android.settingslib.spaprivileged.template.app.AppListInput
import com.android.settingslib.spaprivileged.template.app.AppListItem
import com.android.settingslib.spaprivileged.template.app.AppListItemModel
import com.android.settingslib.spaprivileged.template.app.AppListPage
import com.android.settingslib.spaprivileged.template.app.getStorageSize
import kotlinx.coroutines.flow.Flow
object AllAppListPageProvider : SettingsPageProvider {
override val name = "AllAppList"
private val owner = createSettingsPage()
@Composable
override fun Page(arguments: Bundle?) {
AllAppListPage()
}
fun buildInjectEntry() = SettingsEntryBuilder
.createInject(owner)
.setSearchDataFn { null }
.setUiLayoutFn {
Preference(object : PreferenceModel {
override val title = stringResource(R.string.all_apps)
override val onClick = navigator(name)
})
}
}
@Composable
fun AllAppListPage(
appList: @Composable AppListInput<AppRecordWithSize>.() -> Unit = { AppList() },
) {
val resetAppDialogPresenter = rememberResetAppDialogPresenter()
AppListPage(
title = stringResource(R.string.all_apps),
listModel = rememberContext(::AllAppListModel),
showInstantApps = true,
matchAnyUserForAdmin = true,
moreOptions = { ResetAppPreferences(resetAppDialogPresenter::open) },
appList = appList,
)
}
data class AppRecordWithSize(
override val app: ApplicationInfo,
) : AppRecord
class AllAppListModel(
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): State<String> {
val storageSummary = record.app.getStorageSummary()
return remember {
derivedStateOf {
storageSummary.value +
when {
!record.app.installed && !record.app.isArchived -> {
System.lineSeparator() + context.getString(R.string.not_installed)
}
isDisabled(record) -> {
System.lineSeparator() +
context.getString(com.android.settingslib.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);
}