1 /*
2  * Copyright (C) 2022 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.settingslib.spaprivileged.template.app
18 
19 import android.content.Context
20 import android.content.pm.ApplicationInfo
21 import androidx.compose.runtime.Composable
22 import androidx.compose.runtime.State
23 import androidx.compose.ui.text.AnnotatedString
24 import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
25 import com.android.settingslib.spa.framework.common.SettingsPageProvider
26 import com.android.settingslib.spa.framework.compose.rememberContext
27 import com.android.settingslib.spa.framework.util.asyncMapItem
28 import com.android.settingslib.spaprivileged.model.app.AppRecord
29 import kotlinx.coroutines.flow.Flow
30 
31 /**
32  * Implement this interface to build an App List which toggles a permission on / off.
33  */
34 interface TogglePermissionAppListModel<T : AppRecord> {
35     val pageTitleResId: Int
36     val switchTitleResId: Int
37     val footerResId: Int
38     val switchRestrictionKeys: List<String>
39         get() = emptyList()
40     @Composable
41     fun footerContent(): (@Composable () -> Unit)? {
42         return null
43     }
44     /**
45      * Loads the extra info for the App List, and generates the [AppRecord] List.
46      *
47      * Default is implemented by [transformItem]
48      */
49     fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>): Flow<List<T>> =
50         appListFlow.asyncMapItem(::transformItem)
51 
52     /**
53      * Loads the extra info for one app, and generates the [AppRecord].
54      *
55      * This must be implemented, because when show the App Info page for single app, this will be
56      * used instead of [transform].
57      */
58     fun transformItem(app: ApplicationInfo): T
59 
60     /**
61      * Filters the [AppRecord] list.
62      *
63      * @return the [AppRecord] list which will be displayed.
64      */
65     fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<T>>): Flow<List<T>>
66 
67     /**
68      * Gets whether the permission is allowed for the given app.
69      */
70     @Composable
71     fun isAllowed(record: T): State<Boolean?>
72 
73     /**
74      * Gets whether the permission on / off is changeable for the given app.
75      */
76     fun isChangeable(record: T): Boolean
77 
78     /**
79      * Sets whether the permission is allowed for the given app.
80      */
81     fun setAllowed(record: T, newAllowed: Boolean)
82 }
83 
84 interface TogglePermissionAppListProvider {
85     val permissionType: String
86 
87     fun createModel(context: Context): TogglePermissionAppListModel<out AppRecord>
88 
89     fun buildAppListInjectEntry(): SettingsEntryBuilder =
90         TogglePermissionAppListPageProvider.buildInjectEntry(permissionType) { createModel(it) }
91 
92     /**
93      * Gets the route to the toggle permission App List page.
94      *
95      * Expose route to enable enter from non-SPA pages.
96      */
97     fun getAppListRoute(): String =
98         TogglePermissionAppListPageProvider.getRoute(permissionType)
99 
100     /**
101      * Gets the route prefix to the toggle permission App Info page.
102      *
103      * Expose route prefix to enable enter from non-SPA pages.
104      */
105     fun getAppInfoRoutePrefix(): String =
106         TogglePermissionAppInfoPageProvider.getRoutePrefix(permissionType)
107 
108     @Composable
109     fun InfoPageEntryItem(app: ApplicationInfo) {
110         val listModel = rememberContext(::createModel)
111         listModel.TogglePermissionAppInfoPageEntryItem(permissionType, app)
112     }
113 }
114 
115 class TogglePermissionAppListTemplate(
116     allProviders: List<TogglePermissionAppListProvider>,
117 ) {
118     private val listModelProviderMap = allProviders.associateBy { it.permissionType }
119 
120     fun createPageProviders(): List<SettingsPageProvider> = listOf(
121         TogglePermissionAppListPageProvider(this),
122         TogglePermissionAppInfoPageProvider(this),
123     )
124 
125     @Composable
126     internal fun rememberModel(permissionType: String) = rememberContext { context ->
127         listModelProviderMap.getValue(permissionType).createModel(context)
128     }
129 }
130