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 androidx.compose.foundation.layout.Box
20 import androidx.compose.runtime.Composable
21 import androidx.compose.runtime.getValue
22 import androidx.compose.runtime.livedata.observeAsState
23 import androidx.compose.runtime.mutableStateOf
24 import androidx.compose.runtime.remember
25 import androidx.compose.runtime.setValue
26 import androidx.compose.ui.res.stringResource
27 import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
28 import com.android.permissioncontroller.R
29 import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel
30 import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonState
31 import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType
32 import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs
33 import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
34 import com.android.permissioncontroller.permission.ui.wear.elements.ListFooter
35 import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
36 import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip
37 import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl
38 import com.android.permissioncontroller.permission.ui.wear.model.AppPermissionConfirmDialogViewModel
39 import com.android.permissioncontroller.permission.ui.wear.model.ConfirmDialogArgs
40 import com.android.settingslib.RestrictedLockUtils
41
42 @Composable
43 fun WearAppPermissionScreen(
44 title: String,
45 viewModel: AppPermissionViewModel,
46 confirmDialogViewModel: AppPermissionConfirmDialogViewModel,
47 onLocationSwitchChanged: (Boolean) -> Unit,
48 onGrantedStateChanged: (ButtonType, Boolean) -> Unit,
49 onFooterClicked: (RestrictedLockUtils.EnforcedAdmin) -> Unit,
50 onConfirmDialogOkButtonClick: (ConfirmDialogArgs) -> Unit,
51 onConfirmDialogCancelButtonClick: () -> Unit,
52 onAdvancedConfirmDialogOkButtonClick: (AdvancedConfirmDialogArgs) -> Unit,
53 onAdvancedConfirmDialogCancelButtonClick: () -> Unit
54 ) {
55 val buttonState = viewModel.buttonStateLiveData.observeAsState(null)
56 val detailResIds = viewModel.detailResIdLiveData.observeAsState(null)
57 val admin = viewModel.showAdminSupportLiveData.observeAsState(null)
58 var isLoading by remember { mutableStateOf(true) }
59 val showConfirmDialog = confirmDialogViewModel.showConfirmDialogLiveData.observeAsState(false)
60 val showAdvancedConfirmDialog =
61 confirmDialogViewModel.showAdvancedConfirmDialogLiveData.observeAsState(false)
62
63 Box {
64 WearAppPermissionContent(
65 title,
66 buttonState.value,
67 detailResIds.value,
68 admin.value,
69 isLoading,
70 onLocationSwitchChanged,
71 onGrantedStateChanged,
72 onFooterClicked,
73 )
74 ConfirmDialog(
75 showDialog = showConfirmDialog.value,
76 args = confirmDialogViewModel.confirmDialogArgs,
77 onOkButtonClick = onConfirmDialogOkButtonClick,
78 onCancelButtonClick = onConfirmDialogCancelButtonClick
79 )
80 AdvancedConfirmDialog(
81 showDialog = showAdvancedConfirmDialog.value,
82 args = confirmDialogViewModel.advancedConfirmDialogArgs,
83 onOkButtonClick = onAdvancedConfirmDialogOkButtonClick,
84 onCancelButtonClick = onAdvancedConfirmDialogCancelButtonClick
85 )
86 }
87 if (isLoading && !buttonState.value.isNullOrEmpty()) {
88 isLoading = false
89 }
90 }
91
92 @Composable
WearAppPermissionContentnull93 internal fun WearAppPermissionContent(
94 title: String,
95 buttonState: Map<ButtonType, ButtonState>?,
96 detailResIds: Pair<Int, Int?>?,
97 admin: RestrictedLockUtils.EnforcedAdmin?,
98 isLoading: Boolean,
99 onLocationSwitchChanged: (Boolean) -> Unit,
100 onGrantedStateChanged: (ButtonType, Boolean) -> Unit,
101 onFooterClicked: (RestrictedLockUtils.EnforcedAdmin) -> Unit
102 ) {
103 ScrollableScreen(title = title, isLoading = isLoading) {
104 buttonState?.get(ButtonType.LOCATION_ACCURACY)?.let {
105 if (it.isShown) {
106 item {
107 ToggleChip(
108 checked = it.isChecked,
109 enabled = it.isEnabled,
110 label = stringResource(R.string.app_permission_location_accuracy),
111 toggleControl = ToggleChipToggleControl.Switch,
112 onCheckedChanged = onLocationSwitchChanged,
113 labelMaxLine = Integer.MAX_VALUE
114 )
115 }
116 }
117 }
118 for (buttonType in buttonTypeOrder) {
119 buttonState?.get(buttonType)?.let {
120 if (it.isShown) {
121 item {
122 ToggleChip(
123 checked = it.isChecked,
124 enabled = it.isEnabled,
125 label = labelsByButton(buttonType),
126 toggleControl = ToggleChipToggleControl.Radio,
127 onCheckedChanged = { checked ->
128 onGrantedStateChanged(buttonType, checked)
129 },
130 labelMaxLine = Integer.MAX_VALUE
131 )
132 }
133 }
134 }
135 }
136 detailResIds?.let {
137 item {
138 ListFooter(
139 description = stringResource(detailResIds.first),
140 iconRes = R.drawable.ic_info,
141 onClick =
142 if (admin != null) {
143 { onFooterClicked(admin) }
144 } else {
145 null
146 }
147 )
148 }
149 }
150 }
151 }
152
153 internal val buttonTypeOrder =
154 listOf(
155 ButtonType.ALLOW,
156 ButtonType.ALLOW_ALWAYS,
157 ButtonType.ALLOW_FOREGROUND,
158 ButtonType.ASK_ONCE,
159 ButtonType.ASK,
160 ButtonType.DENY,
161 ButtonType.DENY_FOREGROUND
162 )
163
164 @Composable
labelsByButtonnull165 internal fun labelsByButton(buttonType: ButtonType) =
166 when (buttonType) {
167 ButtonType.ALLOW -> stringResource(R.string.app_permission_button_allow)
168 ButtonType.ALLOW_ALWAYS -> stringResource(R.string.app_permission_button_allow_always)
169 ButtonType.ALLOW_FOREGROUND ->
170 stringResource(R.string.app_permission_button_allow_foreground)
171 ButtonType.ASK_ONCE -> stringResource(R.string.app_permission_button_ask)
172 ButtonType.ASK -> stringResource(R.string.app_permission_button_ask)
173 ButtonType.DENY -> stringResource(R.string.app_permission_button_deny)
174 ButtonType.DENY_FOREGROUND -> stringResource(R.string.app_permission_button_deny)
175 else -> ""
176 }
177
178 @Composable
ConfirmDialognull179 internal fun ConfirmDialog(
180 showDialog: Boolean,
181 args: ConfirmDialogArgs?,
182 onOkButtonClick: (ConfirmDialogArgs) -> Unit,
183 onCancelButtonClick: () -> Unit
184 ) {
185 args?.let {
186 AlertDialog(
187 showDialog = showDialog,
188 message = stringResource(it.messageId),
189 onOKButtonClick = { onOkButtonClick(it) },
190 onCancelButtonClick = onCancelButtonClick,
191 scalingLazyListState = rememberScalingLazyListState()
192 )
193 }
194 }
195
196 @Composable
AdvancedConfirmDialognull197 internal fun AdvancedConfirmDialog(
198 showDialog: Boolean,
199 args: AdvancedConfirmDialogArgs?,
200 onOkButtonClick: (AdvancedConfirmDialogArgs) -> Unit,
201 onCancelButtonClick: () -> Unit
202 ) {
203 args?.let {
204 AlertDialog(
205 showDialog = showDialog,
206 title =
207 if (it.titleId != 0) {
208 stringResource(it.titleId)
209 } else {
210 ""
211 },
212 iconRes = it.iconId,
213 message = stringResource(it.messageId),
214 okButtonContentDescription = stringResource(it.positiveButtonTextId),
215 cancelButtonContentDescription = stringResource(it.negativeButtonTextId),
216 onOKButtonClick = { onOkButtonClick(it) },
217 onCancelButtonClick = onCancelButtonClick,
218 scalingLazyListState = rememberScalingLazyListState()
219 )
220 }
221 }
222