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.permissioncontroller.permission.ui.wear
18 
19 import android.os.Build
20 import androidx.annotation.RequiresApi
21 import androidx.compose.foundation.layout.fillMaxWidth
22 import androidx.compose.runtime.Composable
23 import androidx.compose.runtime.getValue
24 import androidx.compose.runtime.livedata.observeAsState
25 import androidx.compose.runtime.mutableStateOf
26 import androidx.compose.runtime.remember
27 import androidx.compose.runtime.setValue
28 import androidx.compose.ui.Modifier
29 import androidx.compose.ui.platform.LocalContext
30 import androidx.compose.ui.res.stringResource
31 import com.android.permissioncontroller.R
32 import com.android.permissioncontroller.permission.ui.handheld.v31.PermissionUsageControlPreference
33 import com.android.permissioncontroller.permission.ui.viewmodel.v31.PermissionUsageViewModel
34 import com.android.permissioncontroller.permission.ui.viewmodel.v31.PermissionUsagesUiState
35 import com.android.permissioncontroller.permission.ui.wear.elements.Chip
36 import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
37 import com.android.permissioncontroller.permission.ui.wear.model.WearPermissionUsageViewModel
38 import com.android.permissioncontroller.permission.utils.Utils
39 import java.text.Collator
40 
41 @RequiresApi(Build.VERSION_CODES.S)
42 @Composable
43 fun WearPermissionUsageScreen(
44     sessionId: Long,
45     viewModel: PermissionUsageViewModel,
46     wearViewModel: WearPermissionUsageViewModel
47 ) {
48     val context = LocalContext.current
49     val permissionUsagesUiData = wearViewModel.permissionUsagesUiStateLiveData.observeAsState(null)
50     val showSystem = wearViewModel.showSystemAppsLiveData.observeAsState(false)
51     val show7Days = wearViewModel.show7DaysLiveData.observeAsState(false)
52     var isLoading by remember { mutableStateOf(true) }
53     val isDataLoaded = permissionUsagesUiData.value is PermissionUsagesUiState.Success
54     val hasSystemApps: Boolean =
55         if (isDataLoaded) {
56             val uiState = permissionUsagesUiData.value as PermissionUsagesUiState.Success
57             uiState.shouldShowSystemToggle
58         } else {
59             false
60         }
61     val onShowSystemClick: (Boolean) -> Unit = { show ->
62         run {
63             wearViewModel.updatePermissionUsagesUiStateLiveData(viewModel.updateShowSystem(show))
64             wearViewModel.showSystemAppsLiveData.value = viewModel.getShowSystemApps()
65         }
66     }
67 
68     val permissionGroupWithUsageCounts: Map<String, Int> =
69         if (isDataLoaded) {
70             val uiState = permissionUsagesUiData.value as PermissionUsagesUiState.Success
71             uiState.permissionGroupUsageCount
72         } else {
73             emptyMap()
74         }
75     val permissionGroupWithUsageCountsEntries: List<Map.Entry<String, Int>> =
76         ArrayList<Map.Entry<String, Int>>(permissionGroupWithUsageCounts.entries)
77 
78     val collator = Collator.getInstance(context.resources.configuration.locales.get(0))
79     val permissionGroupPreferences =
80         permissionGroupWithUsageCountsEntries
81             // Removing Health Connect from the list of permissions to fix b/331260850
82             .filterNot { Utils.isHealthPermissionGroup(it.key) }
83             .map {
84                 PermissionUsageControlPreference(
85                     context,
86                     it.key,
87                     it.value,
88                     showSystem.value,
89                     sessionId,
90                     show7Days.value
91                 )
92             }
93             .sortedWith { o1, o2 ->
94                 var result = collator.compare(o1.title.toString(), o2.title.toString())
95                 if (result == 0) {
96                     result = o1.title.toString().compareTo(o2.title.toString())
97                 }
98                 result
99             }
100             .toList()
101 
102     WearPermissionUsageContent(
103         isLoading,
104         hasSystemApps,
105         showSystem.value,
106         onShowSystemClick,
107         permissionGroupPreferences
108     )
109 
110     if (isLoading && isDataLoaded) {
111         isLoading = false
112     }
113 }
114 
115 @Composable
WearPermissionUsageContentnull116 internal fun WearPermissionUsageContent(
117     isLoading: Boolean,
118     hasSystemApps: Boolean,
119     showSystem: Boolean,
120     onShowSystemClick: (Boolean) -> Unit,
121     permissionGroupPreferences: List<PermissionUsageControlPreference>
122 ) {
123     ScrollableScreen(
124         title = stringResource(R.string.permission_usage_title),
125         isLoading = isLoading
126     ) {
127         if (permissionGroupPreferences.isEmpty()) {
128             item { Chip(label = stringResource(R.string.no_permissions), onClick = {}) }
129         } else {
130             for (preference in permissionGroupPreferences) {
131                 item {
132                     Chip(
133                         label = preference.title.toString(),
134                         labelMaxLines = Int.MAX_VALUE,
135                         secondaryLabel = preference.summary.toString(),
136                         secondaryLabelMaxLines = Int.MAX_VALUE,
137                         icon = preference.icon,
138                         enabled = preference.isEnabled,
139                         onClick = { preference.performClick() }
140                     )
141                 }
142             }
143             if (hasSystemApps) {
144                 item {
145                     Chip(
146                         label =
147                             if (showSystem) {
148                                 stringResource(R.string.menu_hide_system)
149                             } else {
150                                 stringResource(R.string.menu_show_system)
151                             },
152                         labelMaxLines = Int.MAX_VALUE,
153                         onClick = { onShowSystemClick(!showSystem) },
154                         modifier = Modifier.fillMaxWidth(),
155                     )
156                 }
157             }
158         }
159     }
160 }
161