1 /*
<lambda>null2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.settings.spa.app.storage
18
19 import android.content.Context
20 import android.content.pm.ApplicationInfo
21 import android.os.Bundle
22 import androidx.annotation.StringRes
23 import androidx.compose.runtime.Composable
24 import androidx.compose.runtime.State
25 import androidx.compose.runtime.getValue
26 import androidx.compose.runtime.remember
27 import androidx.compose.ui.platform.LocalContext
28 import androidx.compose.ui.res.stringResource
29 import com.android.settings.R
30 import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
31 import com.android.settingslib.spa.framework.common.SettingsPageProvider
32 import com.android.settingslib.spa.framework.util.filterItem
33 import com.android.settingslib.spa.framework.util.mapItem
34 import com.android.settingslib.spaprivileged.model.app.AppEntry
35 import com.android.settingslib.spaprivileged.model.app.AppListModel
36 import com.android.settingslib.spaprivileged.model.app.AppRecord
37 import com.android.settingslib.spaprivileged.model.app.AppStorageRepositoryImpl
38 import com.android.settingslib.spaprivileged.template.app.AppList
39 import com.android.settingslib.spaprivileged.template.app.AppListInput
40 import com.android.settingslib.spaprivileged.template.app.AppListItem
41 import com.android.settingslib.spaprivileged.template.app.AppListItemModel
42 import com.android.settingslib.spaprivileged.template.app.AppListPage
43 import com.android.settingslib.spaprivileged.template.app.getStorageSize
44 import kotlinx.coroutines.flow.Flow
45
46 sealed class StorageAppListPageProvider(private val type: StorageType) : SettingsPageProvider {
47 @Composable
48 override fun Page(arguments: Bundle?) {
49 StorageAppListPage(type)
50 }
51
52 object Apps : StorageAppListPageProvider(StorageType.Apps) {
53 override val name = "StorageAppList"
54 }
55
56 object Games : StorageAppListPageProvider(StorageType.Games) {
57 override val name = "GameStorageAppList"
58 }
59 }
60
61 sealed class StorageType(
62 @StringRes val titleResource: Int,
63 val filter: (AppRecordWithSize) -> Boolean
64 ) {
65 object Apps : StorageType(
66 titleResource = R.string.apps_storage,
<lambda>null67 filter = {
68 (it.app.flags and ApplicationInfo.FLAG_IS_GAME) == 0 &&
69 it.app.category != ApplicationInfo.CATEGORY_GAME
70 }
71 )
72 object Games : StorageType(
73 titleResource = R.string.game_storage_settings,
<lambda>null74 filter = {
75 (it.app.flags and ApplicationInfo.FLAG_IS_GAME) != 0 ||
76 it.app.category == ApplicationInfo.CATEGORY_GAME
77 }
78 )
79 }
80
81 @Composable
StorageAppListPagenull82 fun StorageAppListPage(
83 type: StorageType,
84 appList: @Composable AppListInput<AppRecordWithSize>.() -> Unit = { AppList() }
85 ) {
86 val context = LocalContext.current
87 AppListPage(
88 title = stringResource(type.titleResource),
89 listModel = when (type) {
<lambda>null90 StorageType.Apps -> remember(context) { StorageAppListModel(context, type) }
<lambda>null91 StorageType.Games -> remember(context) { StorageAppListModel(context, type) }
92 },
93 showInstantApps = true,
94 matchAnyUserForAdmin = true,
95 appList = appList,
<lambda>null96 moreOptions = { }, // TODO(b/292165031) Sorting in Options not yet supported
97 )
98 }
99
100 data class AppRecordWithSize(
101 override val app: ApplicationInfo,
102 val size: Long
103 ) : AppRecord
104
105 class StorageAppListModel(
106 private val context: Context,
107 private val type: StorageType,
<lambda>null108 private val getStorageSummary: @Composable ApplicationInfo.() -> State<String> = {
109 getStorageSize()
110 }
111 ) : AppListModel<AppRecordWithSize> {
112 private val appStorageRepository = AppStorageRepositoryImpl(context)
113
transformnull114 override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
115 appListFlow.mapItem { app ->
116 AppRecordWithSize(app, appStorageRepository.calculateSizeBytes(app) ?: 0L)
117 }
118
filternull119 override fun filter(
120 userIdFlow: Flow<Int>,
121 option: Int,
122 recordListFlow: Flow<List<AppRecordWithSize>>
123 ): Flow<List<AppRecordWithSize>> = recordListFlow.filterItem { type.filter(it) }
124
125 @Composable
getSummarynull126 override fun getSummary(option: Int, record: AppRecordWithSize): () -> String {
127 val storageSummary by record.app.getStorageSummary()
128 return { storageSummary }
129 }
130
131 @Composable
AppItemnull132 override fun AppListItemModel<AppRecordWithSize>.AppItem() {
133 AppListItem(onClick = AppInfoSettingsProvider.navigator(app = record.app))
134 }
135
<lambda>null136 override fun getComparator(option: Int) = compareByDescending<AppEntry<AppRecordWithSize>> {
137 it.record.size
138 }.then(super.getComparator(option))
139 }
140