summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationScreen.kt43
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsScreen.kt41
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionScreen.kt95
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearEnhancedConfirmationScreen.kt30
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearGrantPermissionsScreen.kt11
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AlertDialog.kt108
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ResponsiveDialog.kt96
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionConfirmationDialog.kt159
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionIconBuilder.kt14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/ResourceHelper.kt26
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt36
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt10
-rw-r--r--framework-s/java/android/app/ecm/EnhancedConfirmationManager.java24
-rw-r--r--framework-s/java/android/app/ecm/IEnhancedConfirmationManager.aidl2
-rw-r--r--service/java/com/android/ecm/EnhancedConfirmationService.java33
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt44
18 files changed, 490 insertions, 303 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt b/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt
index e6cf094e3..e2d46e519 100644
--- a/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt
+++ b/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt
@@ -18,7 +18,6 @@ package com.android.permissioncontroller.ecm
import android.annotation.SuppressLint
import android.app.AlertDialog
-import android.app.AppOpsManager
import android.app.Dialog
import android.app.ecm.EnhancedConfirmationManager
import android.content.Context
@@ -55,6 +54,8 @@ import com.android.role.controller.model.Roles
class EnhancedConfirmationDialogActivity : FragmentActivity() {
companion object {
private const val KEY_WAS_CLEAR_RESTRICTION_ALLOWED = "KEY_WAS_CLEAR_RESTRICTION_ALLOWED"
+ private const val REASON_PHONE_STATE = "phone_state"
+ private const val REASON_APP_OP_RESTRICTED = "app_op_restricted"
}
private var wasClearRestrictionAllowed: Boolean = false
@@ -77,6 +78,7 @@ class EnhancedConfirmationDialogActivity : FragmentActivity() {
val packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)
val settingIdentifier = intent.getStringExtra(Intent.EXTRA_SUBJECT)
val isEcmInApp = intent.getBooleanExtra(EXTRA_IS_ECM_IN_APP, false)
+ val reason = intent.getStringExtra(Intent.EXTRA_REASON)
require(uid != Process.INVALID_UID) { "EXTRA_UID cannot be null or invalid" }
require(!packageName.isNullOrEmpty()) { "EXTRA_PACKAGE_NAME cannot be null or empty" }
@@ -84,9 +86,9 @@ class EnhancedConfirmationDialogActivity : FragmentActivity() {
wasClearRestrictionAllowed =
setClearRestrictionAllowed(packageName, UserHandle.getUserHandleForUid(uid))
- val setting = Setting.fromIdentifier(this, settingIdentifier, isEcmInApp)
+ val setting = Setting.fromIdentifier(this, settingIdentifier, isEcmInApp, reason)
if (
- SettingType.fromIdentifier(this, settingIdentifier, isEcmInApp) ==
+ SettingType.fromIdentifier(this, settingIdentifier, isEcmInApp, reason) ==
SettingType.BLOCKED_DUE_TO_PHONE_STATE &&
!Flags.unknownCallPackageInstallBlockingEnabled()
) {
@@ -127,8 +129,10 @@ class EnhancedConfirmationDialogActivity : FragmentActivity() {
context: Context,
settingIdentifier: String,
isEcmInApp: Boolean,
+ reason: String?,
): Setting {
- val settingType = SettingType.fromIdentifier(context, settingIdentifier, isEcmInApp)
+ val settingType =
+ SettingType.fromIdentifier(context, settingIdentifier, isEcmInApp, reason)
val label =
when (settingType) {
SettingType.PLATFORM_PERMISSION ->
@@ -189,10 +193,10 @@ class EnhancedConfirmationDialogActivity : FragmentActivity() {
context: Context,
settingIdentifier: String,
isEcmInApp: Boolean,
+ restrictionReason: String?,
): SettingType {
return when {
- settingIdentifier == AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES ->
- BLOCKED_DUE_TO_PHONE_STATE
+ restrictionReason == REASON_PHONE_STATE -> BLOCKED_DUE_TO_PHONE_STATE
!isEcmInApp -> OTHER
PermissionMapping.isRuntimePlatformPermission(settingIdentifier) &&
PermissionMapping.getGroupOfPlatformPermission(settingIdentifier) != null ->
diff --git a/PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationScreen.kt b/PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationScreen.kt
index 8e58d48d9..5f9f58221 100644
--- a/PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/incident/wear/WearConfirmationScreen.kt
@@ -29,14 +29,15 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
-import androidx.wear.compose.foundation.lazy.ScalingLazyListState
import androidx.wear.compose.material.CircularProgressIndicator
-import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
-import com.android.permissioncontroller.permission.ui.wear.elements.SingleButtonAlertDialog
+import com.android.permissioncontroller.permission.ui.wear.elements.DialogButtonContent
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionConfirmationDialog
+import com.android.permissioncontroller.permission.ui.wear.theme.ResourceHelper
import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionTheme
@Composable
fun WearConfirmationScreen(viewModel: WearConfirmationActivityViewModel) {
+ val materialUIVersion = ResourceHelper.materialUIVersionInSettings
// Wear screen doesn't show incident/bug report's optional reasons and images.
val showDialog = viewModel.showDialogLiveData.observeAsState(false)
val showDenyReport = viewModel.showDenyReportLiveData.observeAsState(false)
@@ -47,27 +48,25 @@ fun WearConfirmationScreen(viewModel: WearConfirmationActivityViewModel) {
if (isLoading) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
} else {
- if (showDenyReport.value) {
- contentArgs.value?.let {
- SingleButtonAlertDialog(
- showDialog = showDialog.value,
- title = it.title,
- message = it.message,
- onButtonClick = it.onDenyClick,
- scalingLazyListState = ScalingLazyListState(0)
+ contentArgs.value?.apply {
+ if (showDenyReport.value) {
+ WearPermissionConfirmationDialog(
+ materialUIVersion = materialUIVersion,
+ show = showDialog.value,
+ title = title,
+ message = message,
+ positiveButtonContent = DialogButtonContent(onClick = onDenyClick),
+ )
+ } else {
+ WearPermissionConfirmationDialog(
+ materialUIVersion = materialUIVersion,
+ show = showDialog.value,
+ title = title,
+ message = message,
+ positiveButtonContent = DialogButtonContent(onClick = onOkClick),
+ negativeButtonContent = DialogButtonContent(onClick = onCancelClick),
)
}
- return
- }
- contentArgs.value?.let {
- AlertDialog(
- showDialog = showDialog.value,
- title = it.title,
- message = it.message,
- onOKButtonClick = it.onOkClick,
- onCancelButtonClick = it.onCancelClick,
- scalingLazyListState = ScalingLazyListState(0)
- )
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsScreen.kt
index ba37205a6..13fb30d73 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionGroupsScreen.kt
@@ -24,17 +24,20 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
-import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.DialogButtonContent
import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip
import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionConfirmationDialog
import com.android.permissioncontroller.permission.ui.wear.model.RevokeDialogArgs
+import com.android.permissioncontroller.permission.ui.wear.theme.ResourceHelper
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion
@Composable
fun WearAppPermissionGroupsScreen(helper: WearAppPermissionGroupsHelper) {
+ val materialUIVersion = ResourceHelper.materialUIVersionInSettings
val packagePermGroups = helper.viewModel.packagePermGroupsLiveData.observeAsState(null)
val autoRevoke = helper.viewModel.autoRevokeLiveData.observeAsState(null)
val appPermissionUsages = helper.wearViewModel.appPermissionUsages.observeAsState(emptyList())
@@ -50,11 +53,12 @@ fun WearAppPermissionGroupsScreen(helper: WearAppPermissionGroupsHelper) {
WearAppPermissionGroupsContent(
isLoading,
helper.getPermissionGroupChipParams(appPermissionUsages.value),
- helper.getAutoRevokeChipParam(autoRevoke.value)
+ helper.getAutoRevokeChipParam(autoRevoke.value),
)
RevokeDialog(
+ materialUIVersion = materialUIVersion,
showDialog = showRevokeDialog.value,
- args = helper.revokeDialogViewModel.revokeDialogArgs
+ args = helper.revokeDialogViewModel.revokeDialogArgs,
)
if (showLocationProviderDialog.value) {
LocationProviderDialogScreen(
@@ -72,7 +76,7 @@ fun WearAppPermissionGroupsScreen(helper: WearAppPermissionGroupsHelper) {
internal fun WearAppPermissionGroupsContent(
isLoading: Boolean,
permissionGroupChipParams: List<PermissionGroupChipParam>,
- autoRevokeChipParam: AutoRevokeChipParam?
+ autoRevokeChipParam: AutoRevokeChipParam?,
) {
ScrollableScreen(title = stringResource(R.string.app_permissions), isLoading = isLoading) {
if (permissionGroupChipParams.isEmpty()) {
@@ -86,7 +90,7 @@ internal fun WearAppPermissionGroupsContent(
label = info.label,
enabled = info.enabled,
toggleControl = ToggleChipToggleControl.Switch,
- onCheckedChanged = info.onCheckedChanged
+ onCheckedChanged = info.onCheckedChanged,
)
} else {
Chip(
@@ -95,7 +99,7 @@ internal fun WearAppPermissionGroupsContent(
secondaryLabel = info.summary?.let { info.summary },
secondaryLabelMaxLines = Integer.MAX_VALUE,
enabled = info.enabled,
- onClick = info.onClick
+ onClick = info.onClick,
)
}
}
@@ -108,7 +112,7 @@ internal fun WearAppPermissionGroupsContent(
label = stringResource(it.labelRes),
labelMaxLine = 3,
toggleControl = ToggleChipToggleControl.Switch,
- onCheckedChanged = it.onCheckedChanged
+ onCheckedChanged = it.onCheckedChanged,
)
}
}
@@ -118,14 +122,19 @@ internal fun WearAppPermissionGroupsContent(
}
@Composable
-internal fun RevokeDialog(showDialog: Boolean, args: RevokeDialogArgs?) {
- args?.let {
- AlertDialog(
- showDialog = showDialog,
- message = stringResource(it.messageId),
- onOKButtonClick = it.onOkButtonClick,
- onCancelButtonClick = it.onCancelButtonClick,
- scalingLazyListState = rememberScalingLazyListState()
+internal fun RevokeDialog(
+ materialUIVersion: WearPermissionMaterialUIVersion,
+ showDialog: Boolean,
+ args: RevokeDialogArgs?,
+) {
+
+ args?.run {
+ WearPermissionConfirmationDialog(
+ materialUIVersion = materialUIVersion,
+ show = showDialog,
+ message = stringResource(messageId),
+ positiveButtonContent = DialogButtonContent(onClick = onOkButtonClick),
+ negativeButtonContent = DialogButtonContent(onClick = onCancelButtonClick),
)
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionScreen.kt
index 202ad49bb..0b96214a2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearAppPermissionScreen.kt
@@ -24,21 +24,26 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
-import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material.ToggleChipDefaults
import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonState
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType
import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs
-import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
+import com.android.permissioncontroller.permission.ui.wear.elements.DialogButtonContent
import com.android.permissioncontroller.permission.ui.wear.elements.ListFooter
import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip
import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionConfirmationDialog
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionIconBuilder
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.defaultAlertConfirmIcon
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.defaultAlertDismissIcon
import com.android.permissioncontroller.permission.ui.wear.elements.toggleChipDisabledColors
import com.android.permissioncontroller.permission.ui.wear.model.AppPermissionConfirmDialogViewModel
import com.android.permissioncontroller.permission.ui.wear.model.ConfirmDialogArgs
+import com.android.permissioncontroller.permission.ui.wear.theme.ResourceHelper
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion
import com.android.settingslib.RestrictedLockUtils
@Composable
@@ -53,8 +58,9 @@ fun WearAppPermissionScreen(
onConfirmDialogCancelButtonClick: () -> Unit,
onAdvancedConfirmDialogOkButtonClick: (AdvancedConfirmDialogArgs) -> Unit,
onAdvancedConfirmDialogCancelButtonClick: () -> Unit,
- onDisabledAllowButtonClick: () -> Unit
+ onDisabledAllowButtonClick: () -> Unit,
) {
+ val materialUIVersion = ResourceHelper.materialUIVersionInSettings
val buttonState = viewModel.buttonStateLiveData.observeAsState(null)
val detailResIds = viewModel.detailResIdLiveData.observeAsState(null)
val admin = viewModel.showAdminSupportLiveData.observeAsState(null)
@@ -73,19 +79,21 @@ fun WearAppPermissionScreen(
onLocationSwitchChanged,
onGrantedStateChanged,
onFooterClicked,
- onDisabledAllowButtonClick
+ onDisabledAllowButtonClick,
)
ConfirmDialog(
+ materialUIVersion = materialUIVersion,
showDialog = showConfirmDialog.value,
args = confirmDialogViewModel.confirmDialogArgs,
onOkButtonClick = onConfirmDialogOkButtonClick,
- onCancelButtonClick = onConfirmDialogCancelButtonClick
+ onCancelButtonClick = onConfirmDialogCancelButtonClick,
)
AdvancedConfirmDialog(
+ materialUIVersion = materialUIVersion,
showDialog = showAdvancedConfirmDialog.value,
args = confirmDialogViewModel.advancedConfirmDialogArgs,
onOkButtonClick = onAdvancedConfirmDialogOkButtonClick,
- onCancelButtonClick = onAdvancedConfirmDialogCancelButtonClick
+ onCancelButtonClick = onAdvancedConfirmDialogCancelButtonClick,
)
}
if (isLoading && !buttonState.value.isNullOrEmpty()) {
@@ -103,7 +111,7 @@ internal fun WearAppPermissionContent(
onLocationSwitchChanged: (Boolean) -> Unit,
onGrantedStateChanged: (ButtonType, Boolean) -> Unit,
onFooterClicked: (RestrictedLockUtils.EnforcedAdmin) -> Unit,
- onDisabledAllowButtonClick: () -> Unit
+ onDisabledAllowButtonClick: () -> Unit,
) {
ScrollableScreen(title = title, isLoading = isLoading) {
buttonState?.get(ButtonType.LOCATION_ACCURACY)?.let {
@@ -115,7 +123,7 @@ internal fun WearAppPermissionContent(
label = stringResource(R.string.app_permission_location_accuracy),
toggleControl = ToggleChipToggleControl.Switch,
onCheckedChanged = onLocationSwitchChanged,
- labelMaxLine = Integer.MAX_VALUE
+ labelMaxLine = Integer.MAX_VALUE,
)
}
}
@@ -141,7 +149,7 @@ internal fun WearAppPermissionContent(
onDisabledAllowButtonClick()
}
},
- labelMaxLine = Integer.MAX_VALUE
+ labelMaxLine = Integer.MAX_VALUE,
)
}
}
@@ -157,7 +165,7 @@ internal fun WearAppPermissionContent(
{ onFooterClicked(admin) }
} else {
null
- }
+ },
)
}
}
@@ -172,7 +180,7 @@ internal val buttonTypeOrder =
ButtonType.ASK_ONCE,
ButtonType.ASK,
ButtonType.DENY,
- ButtonType.DENY_FOREGROUND
+ ButtonType.DENY_FOREGROUND,
)
@Composable
@@ -191,45 +199,60 @@ internal fun labelsByButton(buttonType: ButtonType) =
@Composable
internal fun ConfirmDialog(
+ materialUIVersion: WearPermissionMaterialUIVersion,
showDialog: Boolean,
args: ConfirmDialogArgs?,
onOkButtonClick: (ConfirmDialogArgs) -> Unit,
- onCancelButtonClick: () -> Unit
+ onCancelButtonClick: () -> Unit,
) {
- args?.let {
- AlertDialog(
- showDialog = showDialog,
- message = stringResource(it.messageId),
- onOKButtonClick = { onOkButtonClick(it) },
- onCancelButtonClick = onCancelButtonClick,
- scalingLazyListState = rememberScalingLazyListState()
+ args?.run {
+ WearPermissionConfirmationDialog(
+ materialUIVersion = materialUIVersion,
+ show = showDialog,
+ message = stringResource(messageId),
+ positiveButtonContent = DialogButtonContent(onClick = { onOkButtonClick(this) }),
+ negativeButtonContent = DialogButtonContent(onClick = { onCancelButtonClick() }),
)
}
}
@Composable
internal fun AdvancedConfirmDialog(
+ materialUIVersion: WearPermissionMaterialUIVersion,
showDialog: Boolean,
args: AdvancedConfirmDialogArgs?,
onOkButtonClick: (AdvancedConfirmDialogArgs) -> Unit,
- onCancelButtonClick: () -> Unit
+ onCancelButtonClick: () -> Unit,
) {
- args?.let {
- AlertDialog(
- showDialog = showDialog,
- title =
- if (it.titleId != 0) {
- stringResource(it.titleId)
- } else {
- ""
- },
- iconRes = it.iconId,
- message = stringResource(it.messageId),
- okButtonContentDescription = stringResource(it.positiveButtonTextId),
- cancelButtonContentDescription = stringResource(it.negativeButtonTextId),
- onOKButtonClick = { onOkButtonClick(it) },
- onCancelButtonClick = onCancelButtonClick,
- scalingLazyListState = rememberScalingLazyListState()
+ args?.run {
+ val title =
+ if (titleId != 0) {
+ stringResource(titleId)
+ } else {
+ ""
+ }
+ val okButtonIconBuilder =
+ WearPermissionIconBuilder.defaultAlertConfirmIcon()
+ .contentDescription(stringResource(positiveButtonTextId))
+ val cancelButtonIconBuilder =
+ WearPermissionIconBuilder.defaultAlertDismissIcon()
+ .contentDescription(stringResource(negativeButtonTextId))
+ WearPermissionConfirmationDialog(
+ materialUIVersion = materialUIVersion,
+ show = showDialog,
+ title = title,
+ iconRes = WearPermissionIconBuilder.builder(iconId),
+ message = stringResource(messageId),
+ positiveButtonContent =
+ DialogButtonContent(
+ icon = okButtonIconBuilder,
+ onClick = { onOkButtonClick(this) },
+ ),
+ negativeButtonContent =
+ DialogButtonContent(
+ icon = cancelButtonIconBuilder,
+ onClick = { onCancelButtonClick() },
+ ),
)
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearEnhancedConfirmationScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearEnhancedConfirmationScreen.kt
index 1c31ec96f..0f37511de 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearEnhancedConfirmationScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearEnhancedConfirmationScreen.kt
@@ -33,24 +33,26 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.fragment.app.FragmentActivity
import androidx.wear.compose.foundation.SwipeToDismissValue
-import androidx.wear.compose.foundation.lazy.ScalingLazyListState
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material.ChipDefaults
import androidx.wear.compose.material.CircularProgressIndicator
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.SwipeToDismissBox
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
import com.android.permissioncontroller.permission.ui.wear.elements.CheckYourPhoneScreen
import com.android.permissioncontroller.permission.ui.wear.elements.CheckYourPhoneState
import com.android.permissioncontroller.permission.ui.wear.elements.CheckYourPhoneState.InProgress
import com.android.permissioncontroller.permission.ui.wear.elements.CheckYourPhoneState.Success
import com.android.permissioncontroller.permission.ui.wear.elements.Chip
+import com.android.permissioncontroller.permission.ui.wear.elements.DialogButtonContent
import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
import com.android.permissioncontroller.permission.ui.wear.elements.dismiss
import com.android.permissioncontroller.permission.ui.wear.elements.findActivity
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionConfirmationDialog
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionIconBuilder
import com.android.permissioncontroller.permission.ui.wear.model.WearEnhancedConfirmationViewModel
import com.android.permissioncontroller.permission.ui.wear.model.WearEnhancedConfirmationViewModel.ScreenState
+import com.android.permissioncontroller.permission.ui.wear.theme.ResourceHelper
@Composable
fun WearEnhancedConfirmationScreen(
@@ -58,6 +60,7 @@ fun WearEnhancedConfirmationScreen(
title: String?,
message: CharSequence?,
) {
+ val materialUIVersion = ResourceHelper.materialUIVersionInSettings
var dismissed by remember { mutableStateOf(false) }
val context = LocalContext.current
val ecmScreenState = remember { viewModel.screenState }
@@ -97,7 +100,7 @@ fun WearEnhancedConfirmationScreen(
onClick = { dismiss(activity) },
modifier = Modifier.fillMaxWidth(),
textColor = MaterialTheme.colors.surface,
- colors = ChipDefaults.primaryChipColors()
+ colors = ChipDefaults.primaryChipColors(),
)
}
item {
@@ -107,27 +110,30 @@ fun WearEnhancedConfirmationScreen(
modifier = Modifier.fillMaxWidth(),
)
}
- }
+ },
)
@Composable
fun ShowCheckYourPhoneDialog(state: CheckYourPhoneState) =
CheckYourPhoneScreen(
title = stringResource(id = R.string.wear_check_your_phone_title),
- state = state
+ state = state,
)
@Composable
fun ShowRemoteConnectionErrorDialog() =
- AlertDialog(
+ WearPermissionConfirmationDialog(
+ materialUIVersion = materialUIVersion,
+ show = true,
title = stringResource(R.string.wear_phone_connection_error),
message = stringResource(R.string.wear_phone_connection_should_retry),
- iconRes = R.drawable.ic_error,
- showDialog = true,
- okButtonIcon = R.drawable.ic_refresh,
- onOKButtonClick = { viewModel.openUriOnPhone(context) },
- onCancelButtonClick = { dismiss(activity) },
- scalingLazyListState = ScalingLazyListState(1)
+ iconRes = WearPermissionIconBuilder.builder(R.drawable.ic_error),
+ positiveButtonContent =
+ DialogButtonContent(
+ icon = WearPermissionIconBuilder.builder(R.drawable.ic_refresh),
+ onClick = { viewModel.openUriOnPhone(context) },
+ ),
+ negativeButtonContent = DialogButtonContent(onClick = { dismiss(activity) }),
)
SwipeToDismissBox(state = state) { isBackground ->
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearGrantPermissionsScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearGrantPermissionsScreen.kt
index e6c141cc8..4670cfb78 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearGrantPermissionsScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearGrantPermissionsScreen.kt
@@ -47,7 +47,6 @@ import com.android.permissioncontroller.permission.ui.wear.elements.material3.We
import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionToggleControl
import com.android.permissioncontroller.permission.ui.wear.model.WearGrantPermissionsViewModel
import com.android.permissioncontroller.permission.ui.wear.theme.ResourceHelper
-import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL2_5
import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL3
import kotlinx.coroutines.delay
@@ -63,13 +62,7 @@ fun WearGrantPermissionsScreen(
val locationVisibilities = viewModel.locationVisibilitiesLiveData.observeAsState(emptyList())
val preciseLocationChecked = viewModel.preciseLocationCheckedLiveData.observeAsState(false)
val buttonVisibilities = viewModel.buttonVisibilitiesLiveData.observeAsState(emptyList())
- val materialUIVersion =
- if (ResourceHelper.material3Enabled) {
- MATERIAL3
- } else {
- MATERIAL2_5
- }
-
+ val materialUIVersion = ResourceHelper.materialUIVersionInApp
ScrollableScreen(
materialUIVersion = materialUIVersion,
showTimeText = false,
@@ -129,7 +122,7 @@ fun setContent(
onLocationSwitchChanged: (Boolean) -> Unit,
) {
composeView.setContent {
- if (ResourceHelper.material3Enabled) {
+ if (ResourceHelper.materialUIVersionInApp == MATERIAL3) {
AsDialog(onCancelled) {
WearGrantPermissionsScreen(viewModel, onButtonClicked, onLocationSwitchChanged)
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AlertDialog.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AlertDialog.kt
index c07d2ba9e..a700c02e2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AlertDialog.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/AlertDialog.kt
@@ -17,17 +17,12 @@
package com.android.permissioncontroller.permission.ui.wear.elements
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Check
-import androidx.compose.material.icons.filled.Close
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
@@ -35,15 +30,19 @@ import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.ScalingLazyListScope
import androidx.wear.compose.foundation.lazy.ScalingLazyListState
-import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.LocalTextStyle
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.Text
-import androidx.wear.compose.material.dialog.Alert
import androidx.wear.compose.material.dialog.Dialog
import com.android.permissioncontroller.permission.ui.wear.elements.layout.ScalingLazyColumnDefaults
import com.android.permissioncontroller.permission.ui.wear.elements.layout.ScalingLazyColumnState
import com.android.permissioncontroller.permission.ui.wear.elements.layout.rememberColumnState
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionIconBuilder
+
+data class DialogButtonContent(
+ val icon: WearPermissionIconBuilder? = null,
+ val onClick: (() -> Unit),
+)
/**
* This component is an alternative to [AlertContent], providing the following:
@@ -54,95 +53,44 @@ import com.android.permissioncontroller.permission.ui.wear.elements.layout.remem
*/
@Composable
fun AlertDialog(
+ title: String? = null,
message: String,
- iconRes: Int? = null,
- okButtonIcon: Any = Icons.Default.Check,
- cancelButtonIcon: Any = Icons.Default.Close,
- onCancelButtonClick: () -> Unit,
- onOKButtonClick: () -> Unit,
+ positiveButtonContent: DialogButtonContent?,
+ negativeButtonContent: DialogButtonContent?,
showDialog: Boolean,
- scalingLazyListState: ScalingLazyListState,
modifier: Modifier = Modifier,
- title: String? = null,
- okButtonContentDescription: String = stringResource(android.R.string.ok),
- cancelButtonContentDescription: String = stringResource(android.R.string.cancel)
+ iconRes: WearPermissionIconBuilder? = null,
+ scalingLazyListState: ScalingLazyListState,
) {
val focusManager = LocalFocusManager.current
Dialog(
showDialog = showDialog,
onDismissRequest = {
focusManager.clearFocus()
- onCancelButtonClick()
+ negativeButtonContent?.onClick?.invoke()
},
scrollState = scalingLazyListState,
- modifier = modifier
- ) {
- AlertContent(
- title = title,
- icon = { AlertIcon(iconRes) },
- message = message,
- okButtonIcon = okButtonIcon,
- cancelButtonIcon = cancelButtonIcon,
- onCancel = onCancelButtonClick,
- onOk = onOKButtonClick,
- okButtonContentDescription = okButtonContentDescription,
- cancelButtonContentDescription = cancelButtonContentDescription
- )
- }
-}
-
-/**
- * This component is an alternative to [Alert], providing the following:
- * - a convenient way of passing a title and a message;
- * - default one button;
- * - wrapped in a [Dialog];
- */
-@Composable
-fun SingleButtonAlertDialog(
- message: String,
- iconRes: Int? = null,
- okButtonIcon: Any = Icons.Default.Check,
- onButtonClick: () -> Unit,
- showDialog: Boolean,
- scalingLazyListState: ScalingLazyListState,
- modifier: Modifier = Modifier,
- title: String? = null,
- buttonContentDescription: String = stringResource(android.R.string.ok)
-) {
- Dialog(
- showDialog = showDialog,
- onDismissRequest = {},
- scrollState = scalingLazyListState,
- modifier = modifier
+ modifier = modifier,
) {
AlertContent(
title = title,
- icon = { AlertIcon(iconRes) },
+ icon = { iconRes?.build() },
message = message,
- okButtonIcon = okButtonIcon,
- onOk = onButtonClick,
- okButtonContentDescription = buttonContentDescription
+ positiveButtonContent = positiveButtonContent,
+ negativeButtonContent = negativeButtonContent,
)
}
}
@Composable
fun AlertContent(
- onCancel: (() -> Unit)? = null,
- onOk: (() -> Unit)? = null,
icon: @Composable (() -> Unit)? = null,
title: String? = null,
message: String? = null,
- okButtonIcon: Any = Icons.Default.Check,
- cancelButtonIcon: Any = Icons.Default.Close,
- okButtonContentDescription: String = stringResource(android.R.string.ok),
- cancelButtonContentDescription: String = stringResource(android.R.string.cancel),
+ positiveButtonContent: DialogButtonContent?,
+ negativeButtonContent: DialogButtonContent?,
state: ScalingLazyColumnState =
- rememberColumnState(
- ScalingLazyColumnDefaults.responsive(
- additionalPaddingAtBottom = 0.dp,
- ),
- ),
+ rememberColumnState(ScalingLazyColumnDefaults.responsive(additionalPaddingAtBottom = 0.dp)),
showPositionIndicator: Boolean = true,
content: (ScalingLazyListScope.() -> Unit)? = null,
) {
@@ -185,7 +133,7 @@ fun AlertContent(
maxWidth =
(maxScreenWidthPx *
(1f - totalPaddingPercentage * 2f / 100f))
- .toInt(),
+ .toInt()
),
)
.lineCount
@@ -200,21 +148,9 @@ fun AlertContent(
}
},
content = content,
- onOk = onOk,
- onCancel = onCancel,
- okButtonIcon = okButtonIcon,
- cancelButtonIcon = cancelButtonIcon,
- okButtonContentDescription = okButtonContentDescription,
- cancelButtonContentDescription = cancelButtonContentDescription,
+ positiveButtonContent = positiveButtonContent,
+ negativeButtonContent = negativeButtonContent,
state = state,
showPositionIndicator = showPositionIndicator,
)
}
-
-@Composable
-private fun AlertIcon(iconRes: Int?) =
- if (iconRes != null && iconRes != 0) {
- Icon(painter = painterResource(iconRes), contentDescription = null)
- } else {
- null
- }
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ResponsiveDialog.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ResponsiveDialog.kt
index e1e869f71..361a6c925 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ResponsiveDialog.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ResponsiveDialog.kt
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.android.permissioncontroller.permission.ui.wear.elements
import androidx.compose.foundation.layout.Arrangement
@@ -29,15 +28,11 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Check
-import androidx.compose.material.icons.filled.Close
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@@ -53,9 +48,9 @@ import com.android.permissioncontroller.permission.ui.wear.elements.layout.Scali
import com.android.permissioncontroller.permission.ui.wear.elements.layout.ScalingLazyColumnDefaults.responsive
import com.android.permissioncontroller.permission.ui.wear.elements.layout.ScalingLazyColumnState
import com.android.permissioncontroller.permission.ui.wear.elements.layout.rememberColumnState
-
-// This file is a copy of ResponsiveDialogContent.kt from Horologist (go/horologist),
-// remove it once after wear compose supports large screen dialogs.
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionIconBuilder
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.defaultAlertConfirmIcon
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.defaultAlertDismissIcon
@Composable
fun ResponsiveDialogContent(
@@ -63,18 +58,11 @@ fun ResponsiveDialogContent(
icon: @Composable (() -> Unit)? = null,
title: @Composable (() -> Unit)? = null,
message: @Composable (() -> Unit)? = null,
- okButtonIcon: Any = Icons.Default.Check,
- cancelButtonIcon: Any = Icons.Default.Close,
- onOk: (() -> Unit)? = null,
- onCancel: (() -> Unit)? = null,
- okButtonContentDescription: String = stringResource(android.R.string.ok),
- cancelButtonContentDescription: String = stringResource(android.R.string.cancel),
+ positiveButtonContent: DialogButtonContent? = null,
+ negativeButtonContent: DialogButtonContent? = null,
state: ScalingLazyColumnState =
rememberColumnState(
- responsive(
- firstItemIsFullWidth = icon == null,
- additionalPaddingAtBottom = 0.dp,
- ),
+ responsive(firstItemIsFullWidth = icon == null, additionalPaddingAtBottom = 0.dp)
),
showPositionIndicator: Boolean = true,
content: (ScalingLazyListScope.() -> Unit)? = null,
@@ -89,9 +77,7 @@ fun ResponsiveDialogContent(
timeText = {},
) {
// This will be applied only to the content.
- CompositionLocalProvider(
- LocalTextStyle provides MaterialTheme.typography.body2,
- ) {
+ CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.body2) {
ScalingLazyColumn(columnState = state) {
icon?.let {
item {
@@ -107,11 +93,11 @@ fun ResponsiveDialogContent(
item {
CompositionLocalProvider(
LocalTextStyle provides
- MaterialTheme.typography.title3.copy(fontWeight = FontWeight.W600),
+ MaterialTheme.typography.title3.copy(fontWeight = FontWeight.W600)
) {
Box(
Modifier.fillMaxWidth(titleMaxWidthFraction)
- .padding(bottom = 8.dp), // 12.dp below icon
+ .padding(bottom = 8.dp) // 12.dp below icon
) {
it()
}
@@ -123,22 +109,20 @@ fun ResponsiveDialogContent(
item { Spacer(Modifier.height(20.dp)) }
}
message?.let {
- item {
- Box(
- Modifier.fillMaxWidth(messageMaxWidthFraction),
- ) {
- it()
- }
- }
+ item { Box(Modifier.fillMaxWidth(messageMaxWidthFraction)) { it() } }
}
content?.let { it() }
- if (onOk != null || onCancel != null) {
+ if (positiveButtonContent != null || negativeButtonContent != null) {
item {
val width = LocalConfiguration.current.screenWidthDp
// Single buttons, or buttons on smaller screens are not meant to be
// responsive.
val buttonWidth =
- if (width < 225 || onOk == null || onCancel == null) {
+ if (
+ width < 225 ||
+ positiveButtonContent == null ||
+ negativeButtonContent == null
+ ) {
ButtonDefaults.DefaultButtonSize
} else {
// 14.56% on top of 5.2% margin on the sides, 12.dp between.
@@ -147,25 +131,30 @@ fun ResponsiveDialogContent(
Row(
Modifier.fillMaxWidth()
.padding(
- top = if (content != null || message != null) 12.dp else 0.dp,
+ top = if (content != null || message != null) 12.dp else 0.dp
),
horizontalArrangement = spacedBy(12.dp, Alignment.CenterHorizontally),
verticalAlignment = Alignment.CenterVertically,
) {
- onCancel?.let {
+ negativeButtonContent?.run {
ResponsiveButton(
- icon = cancelButtonIcon,
- cancelButtonContentDescription,
- onClick = it,
+ this.icon
+ ?: WearPermissionIconBuilder.defaultAlertDismissIcon()
+ .tint(
+ ChipDefaults.secondaryChipColors()
+ .contentColor(true)
+ .value
+ ),
+ onClick,
buttonWidth,
ChipDefaults.secondaryChipColors(),
)
}
- onOk?.let {
+ positiveButtonContent?.run {
ResponsiveButton(
- icon = okButtonIcon,
- okButtonContentDescription,
- onClick = it,
+ this.icon
+ ?: WearPermissionIconBuilder.defaultAlertConfirmIcon(),
+ onClick,
buttonWidth,
)
}
@@ -179,8 +168,7 @@ fun ResponsiveDialogContent(
@Composable
private fun ResponsiveButton(
- icon: Any,
- contentDescription: String,
+ icon: WearPermissionIconBuilder,
onClick: () -> Unit,
buttonWidth: Dp,
colors: ChipColors = ChipDefaults.primaryChipColors(),
@@ -188,12 +176,9 @@ private fun ResponsiveButton(
androidx.wear.compose.material.Chip(
label = {
Box(Modifier.fillMaxWidth()) {
- Icon(
- icon = icon,
- contentDescription = contentDescription,
- modifier =
- Modifier.size(ButtonDefaults.DefaultIconSize).align(Alignment.Center),
- )
+ icon
+ .modifier(Modifier.size(ButtonDefaults.DefaultIconSize).align(Alignment.Center))
+ .build()
}
},
contentPadding = PaddingValues(0.dp),
@@ -210,19 +195,10 @@ internal const val titleExtraHorizontalPadding = 8.84f
// Fraction of the max available width that message should take (after global and message padding)
internal val messageMaxWidthFraction =
- 1f -
- 2f *
- calculatePaddingFraction(
- messageExtraHorizontalPadding,
- )
+ 1f - 2f * calculatePaddingFraction(messageExtraHorizontalPadding)
// Fraction of the max available width that title should take (after global and message padding)
-internal val titleMaxWidthFraction =
- 1f -
- 2f *
- calculatePaddingFraction(
- titleExtraHorizontalPadding,
- )
+internal val titleMaxWidthFraction = 1f - 2f * calculatePaddingFraction(titleExtraHorizontalPadding)
// Calculate total padding given global padding and additional padding required inside that.
internal fun calculatePaddingFraction(extraPadding: Float) =
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionConfirmationDialog.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionConfirmationDialog.kt
new file mode 100644
index 000000000..4647d6eae
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionConfirmationDialog.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2025 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.permissioncontroller.permission.ui.wear.elements.material3
+
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
+import androidx.wear.compose.material3.AlertDialog as Material3AlertDialog
+import androidx.wear.compose.material3.AlertDialogDefaults
+import androidx.wear.compose.material3.Text
+import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
+import com.android.permissioncontroller.permission.ui.wear.elements.DialogButtonContent
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion
+
+@Composable
+fun WearPermissionConfirmationDialog(
+ materialUIVersion: WearPermissionMaterialUIVersion =
+ WearPermissionMaterialUIVersion.MATERIAL2_5,
+ show: Boolean,
+ iconRes: WearPermissionIconBuilder? = null,
+ title: String? = null,
+ message: String? = null,
+ positiveButtonContent: DialogButtonContent? = null,
+ negativeButtonContent: DialogButtonContent? = null,
+) {
+
+ if (materialUIVersion == WearPermissionMaterialUIVersion.MATERIAL3) {
+ if (
+ (positiveButtonContent == null && negativeButtonContent != null) ||
+ (positiveButtonContent != null && negativeButtonContent == null)
+ ) {
+ val edgeButtonContent = (positiveButtonContent ?: negativeButtonContent)!!
+ WearPermissionConfirmationDialogInternal(
+ show = show,
+ edgeButtonContent = edgeButtonContent,
+ iconRes = iconRes,
+ title = title,
+ message = message,
+ )
+ } else {
+ WearPermissionConfirmationDialogInternal(
+ show = show,
+ positiveButtonContent = positiveButtonContent,
+ negativeButtonContent = negativeButtonContent,
+ iconRes = iconRes,
+ title = title,
+ message = message,
+ )
+ }
+ } else {
+ AlertDialog(
+ title = title,
+ iconRes = iconRes,
+ message = message ?: "",
+ positiveButtonContent = positiveButtonContent,
+ negativeButtonContent = negativeButtonContent,
+ showDialog = show,
+ scalingLazyListState = rememberScalingLazyListState(),
+ )
+ }
+}
+
+@Composable
+private fun WearPermissionConfirmationDialogInternal(
+ show: Boolean,
+ edgeButtonContent: DialogButtonContent,
+ iconRes: WearPermissionIconBuilder?,
+ title: String?,
+ message: String?,
+) {
+ val edgeIcon: @Composable RowScope.() -> Unit =
+ edgeButtonContent.icon?.let {
+ { it.modifier(Modifier.size(36.dp).align(Alignment.CenterVertically)).build() }
+ } ?: AlertDialogDefaults.ConfirmIcon
+
+ Material3AlertDialog(
+ show = show,
+ onDismissRequest = edgeButtonContent.onClick,
+ edgeButton = {
+ AlertDialogDefaults.EdgeButton(onClick = edgeButtonContent.onClick, content = edgeIcon)
+ },
+ icon = { iconRes?.build() },
+ title = title?.let { { Text(text = title) } } ?: {},
+ text = message?.let { { Text(text = message) } },
+ )
+}
+
+@Composable
+private fun WearPermissionConfirmationDialogInternal(
+ show: Boolean,
+ positiveButtonContent: DialogButtonContent?,
+ negativeButtonContent: DialogButtonContent?,
+ iconRes: WearPermissionIconBuilder?,
+ title: String?,
+ message: String?,
+) {
+ val positiveButton: (@Composable RowScope.() -> Unit)? =
+ positiveButtonContent?.let {
+ {
+ val positiveIcon: @Composable RowScope.() -> Unit =
+ positiveButtonContent.icon?.let {
+ {
+ it.modifier(Modifier.size(36.dp).align(Alignment.CenterVertically))
+ .build()
+ }
+ } ?: AlertDialogDefaults.ConfirmIcon
+
+ AlertDialogDefaults.ConfirmButton(
+ onClick = positiveButtonContent.onClick,
+ content = positiveIcon,
+ )
+ }
+ }
+
+ val negativeButton: (@Composable RowScope.() -> Unit)? =
+ negativeButtonContent?.let {
+ {
+ val negativeIcon: @Composable RowScope.() -> Unit =
+ negativeButtonContent.icon?.let {
+ {
+ it.modifier(Modifier.size(36.dp).align(Alignment.CenterVertically))
+ .build()
+ }
+ } ?: AlertDialogDefaults.DismissIcon
+
+ AlertDialogDefaults.DismissButton(
+ onClick = negativeButtonContent.onClick,
+ content = negativeIcon,
+ )
+ }
+ }
+
+ Material3AlertDialog(
+ show = show,
+ onDismissRequest = negativeButtonContent?.onClick ?: {},
+ confirmButton = positiveButton ?: {},
+ dismissButton = negativeButton ?: {},
+ icon = { iconRes?.build() },
+ title = title?.let { { Text(text = title) } } ?: {},
+ text = message?.let { { Text(text = message) } },
+ )
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionIconBuilder.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionIconBuilder.kt
index b7521d073..52674b50d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionIconBuilder.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/material3/WearPermissionIconBuilder.kt
@@ -17,12 +17,16 @@ package com.android.permissioncontroller.permission.ui.wear.elements.material3
import android.graphics.drawable.Drawable
import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Close
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconButtonDefaults
import com.android.permissioncontroller.permission.ui.wear.elements.rememberDrawablePainter
@@ -66,7 +70,7 @@ class WearPermissionIconBuilder private constructor() {
}
fun modifier(modifier: Modifier): WearPermissionIconBuilder {
- this.modifier then modifier
+ this.modifier = modifier then this.modifier
return this
}
@@ -99,3 +103,11 @@ class WearPermissionIconBuilder private constructor() {
fun builder(icon: Any) = WearPermissionIconBuilder().apply { iconResource = icon }
}
}
+
+@Composable
+fun WearPermissionIconBuilder.Companion.defaultAlertConfirmIcon() =
+ builder(Icons.Default.Check).contentDescription((stringResource(android.R.string.ok)))
+
+@Composable
+fun WearPermissionIconBuilder.Companion.defaultAlertDismissIcon() =
+ builder(Icons.Default.Close).contentDescription((stringResource(android.R.string.cancel)))
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/ResourceHelper.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/ResourceHelper.kt
index c7ed0958c..2a40a625f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/ResourceHelper.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/ResourceHelper.kt
@@ -27,11 +27,35 @@ internal object ResourceHelper {
private const val MATERIAL3_ENABLED_SYSPROP = "persist.cw_build.bluechip.enabled"
- val material3Enabled: Boolean
+ /* This controls in app permission controller experience. */
+ private val material3Enabled: Boolean
get() {
return SystemProperties.getBoolean(MATERIAL3_ENABLED_SYSPROP, false)
}
+ val materialUIVersionInApp: WearPermissionMaterialUIVersion =
+ if (material3Enabled) {
+ WearPermissionMaterialUIVersion.MATERIAL3
+ } else {
+ WearPermissionMaterialUIVersion.MATERIAL2_5
+ }
+
+ /*
+ This is to control the permission controller screens in settings.
+ Currently it is set as false. We will either use the flag or a common property from settings
+ based on settings implementation when we are ready" */
+ private val material3EnabledInSettings: Boolean
+ get() {
+ return false
+ }
+
+ val materialUIVersionInSettings: WearPermissionMaterialUIVersion =
+ if (material3EnabledInSettings) {
+ WearPermissionMaterialUIVersion.MATERIAL3
+ } else {
+ WearPermissionMaterialUIVersion.MATERIAL2_5
+ }
+
@DoNotInline
fun getColor(context: Context, @ColorRes id: Int): Color? {
return try {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt
index 8823bee07..736d543a3 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/theme/WearPermissionTheme.kt
@@ -53,9 +53,6 @@ fun WearPermissionTheme(
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
WearPermissionLegacyTheme(content)
} else {
- // Whether we are ready to use material3 for any screen.
- val useBridgedTheme = ResourceHelper.material3Enabled
-
// Material3 UI controls are still being used in the screen that the theme is applied
if (version == MATERIAL3) {
val material3Theme = WearOverlayableMaterial3Theme(LocalContext.current)
@@ -70,7 +67,7 @@ fun WearPermissionTheme(
// But some in-app screens(like permission grant screen) are migrated to material3.
// To avoid having two set of overlay resources, we will use material3 overlay resources to
// support material2_5 UI controls as well.
- else if (version == MATERIAL2_5 && useBridgedTheme) {
+ else if (version == MATERIAL2_5 && ResourceHelper.materialUIVersionInApp == MATERIAL3) {
val material3Theme = WearOverlayableMaterial3Theme(LocalContext.current)
val bridgedLegacyTheme = WearMaterialBridgedLegacyTheme.createFrom(material3Theme)
MaterialTheme(
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt
index 5d4233c6e..5a90380e0 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearDefaultAppScreen.kt
@@ -25,14 +25,16 @@ import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material.ToggleChipDefaults
-import com.android.permissioncontroller.permission.ui.wear.elements.AlertDialog
+import com.android.permissioncontroller.permission.ui.wear.elements.DialogButtonContent
import com.android.permissioncontroller.permission.ui.wear.elements.ListFooter
import com.android.permissioncontroller.permission.ui.wear.elements.ScrollableScreen
import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChip
import com.android.permissioncontroller.permission.ui.wear.elements.ToggleChipToggleControl
+import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionConfirmationDialog
import com.android.permissioncontroller.permission.ui.wear.elements.toggleChipDisabledColors
+import com.android.permissioncontroller.permission.ui.wear.theme.ResourceHelper
+import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion
import com.android.permissioncontroller.role.ui.wear.model.ConfirmDialogArgs
@Composable
@@ -41,11 +43,13 @@ fun WearDefaultAppScreen(helper: WearDefaultAppHelper) {
val showConfirmDialog =
helper.confirmDialogViewModel.showConfirmDialogLiveData.observeAsState(false)
var isLoading by remember { mutableStateOf(true) }
+ val materialUIVersion = ResourceHelper.materialUIVersionInSettings
Box {
WearDefaultAppContent(isLoading, roleLiveData.value, helper)
ConfirmDialog(
+ materialUIVersion = materialUIVersion,
showDialog = showConfirmDialog.value,
- args = helper.confirmDialogViewModel.confirmDialogArgs
+ args = helper.confirmDialogViewModel.confirmDialogArgs,
)
}
if (isLoading && roleLiveData.value.isNotEmpty()) {
@@ -57,7 +61,7 @@ fun WearDefaultAppScreen(helper: WearDefaultAppHelper) {
private fun WearDefaultAppContent(
isLoading: Boolean,
qualifyingApplications: List<Pair<ApplicationInfo, Boolean>>,
- helper: WearDefaultAppHelper
+ helper: WearDefaultAppHelper,
) {
ScrollableScreen(title = helper.getTitle(), isLoading = isLoading) {
helper.getNonePreference(qualifyingApplications)?.let {
@@ -68,7 +72,7 @@ private fun WearDefaultAppContent(
checked = it.checked,
onCheckedChanged = it.onDefaultCheckChanged,
toggleControl = ToggleChipToggleControl.Radio,
- labelMaxLine = Integer.MAX_VALUE
+ labelMaxLine = Integer.MAX_VALUE,
)
}
}
@@ -88,7 +92,7 @@ private fun WearDefaultAppContent(
onCheckedChanged = pref.getOnCheckChanged(),
toggleControl = ToggleChipToggleControl.Radio,
labelMaxLine = Integer.MAX_VALUE,
- secondaryLabelMaxLine = Integer.MAX_VALUE
+ secondaryLabelMaxLine = Integer.MAX_VALUE,
)
}
}
@@ -98,14 +102,18 @@ private fun WearDefaultAppContent(
}
@Composable
-private fun ConfirmDialog(showDialog: Boolean, args: ConfirmDialogArgs?) {
- args?.let {
- AlertDialog(
- showDialog = showDialog,
- message = it.message,
- onOKButtonClick = it.onOkButtonClick,
- onCancelButtonClick = it.onCancelButtonClick,
- scalingLazyListState = rememberScalingLazyListState()
+private fun ConfirmDialog(
+ materialUIVersion: WearPermissionMaterialUIVersion,
+ showDialog: Boolean,
+ args: ConfirmDialogArgs?,
+) {
+ args?.run {
+ WearPermissionConfirmationDialog(
+ materialUIVersion = materialUIVersion,
+ show = showDialog,
+ message = message,
+ positiveButtonContent = DialogButtonContent(onClick = onOkButtonClick),
+ negativeButtonContent = DialogButtonContent(onClick = onCancelButtonClick),
)
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt
index fcc0d56f9..4a00efa1a 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRequestRoleScreen.kt
@@ -41,8 +41,6 @@ import com.android.permissioncontroller.permission.ui.wear.elements.material3.We
import com.android.permissioncontroller.permission.ui.wear.elements.material3.WearPermissionToggleControlStyle
import com.android.permissioncontroller.permission.ui.wear.theme.ResourceHelper
import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion
-import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL2_5
-import com.android.permissioncontroller.permission.ui.wear.theme.WearPermissionMaterialUIVersion.MATERIAL3
import com.android.permissioncontroller.role.UserPackage
import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData
@@ -80,14 +78,8 @@ fun WearRequestRoleScreen(
helper.initializeSelectedPackage()
}
}
- val materialUIVersion =
- if (ResourceHelper.material3Enabled) {
- MATERIAL3
- } else {
- MATERIAL2_5
- }
WearRequestRoleContent(
- materialUIVersion,
+ ResourceHelper.materialUIVersionInApp,
isLoading,
helper,
roleLiveData.value,
diff --git a/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java b/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java
index db05a0af6..290388558 100644
--- a/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java
+++ b/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java
@@ -33,6 +33,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.permission.flags.Flags;
import android.util.ArraySet;
@@ -202,6 +203,19 @@ public final class EnhancedConfirmationManager {
public static final String ACTION_SHOW_ECM_RESTRICTED_SETTING_DIALOG =
"android.app.ecm.action.SHOW_ECM_RESTRICTED_SETTING_DIALOG";
+ /**
+ * The setting is restricted because of the phone state of the device
+ * @hide
+ */
+ public static final String REASON_PHONE_STATE = "phone_state";
+
+ /**
+ * The setting is restricted because the restricted app op is set for the given package
+ * @hide
+ */
+ public static final String REASON_APP_OP_RESTRICTED = "app_op_restricted";
+
+
/** A map of ECM states to their corresponding app op states */
@Retention(java.lang.annotation.RetentionPolicy.SOURCE)
@IntDef(prefix = {"ECM_STATE_"}, value = {EcmState.ECM_STATE_NOT_GUARDED,
@@ -349,8 +363,16 @@ public final class EnhancedConfirmationManager {
@NonNull String settingIdentifier) throws NameNotFoundException {
Intent intent = new Intent(ACTION_SHOW_ECM_RESTRICTED_SETTING_DIALOG);
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- intent.putExtra(Intent.EXTRA_UID, getPackageUid(packageName));
+ int uid = getPackageUid(packageName);
+ intent.putExtra(Intent.EXTRA_UID, uid);
intent.putExtra(Intent.EXTRA_SUBJECT, settingIdentifier);
+ try {
+ intent.putExtra(Intent.EXTRA_REASON, mService.getRestrictionReason(packageName,
+ settingIdentifier, UserHandle.getUserHandleForUid(uid).getIdentifier()));
+ } catch (SecurityException | RemoteException e) {
+ // The caller of this method does not have permission to read the ECM state, so we
+ // won't include it in the return
+ }
return intent;
}
diff --git a/framework-s/java/android/app/ecm/IEnhancedConfirmationManager.aidl b/framework-s/java/android/app/ecm/IEnhancedConfirmationManager.aidl
index 5149daa49..79d2322bd 100644
--- a/framework-s/java/android/app/ecm/IEnhancedConfirmationManager.aidl
+++ b/framework-s/java/android/app/ecm/IEnhancedConfirmationManager.aidl
@@ -25,6 +25,8 @@ interface IEnhancedConfirmationManager {
boolean isRestricted(in String packageName, in String settingIdentifier, int userId);
+ String getRestrictionReason(in String packageName, in String settingIdentifier, int userId);
+
void clearRestriction(in String packageName, int userId);
boolean isClearRestrictionAllowed(in String packageName, int userId);
diff --git a/service/java/com/android/ecm/EnhancedConfirmationService.java b/service/java/com/android/ecm/EnhancedConfirmationService.java
index 65fde6daf..dde5404a4 100644
--- a/service/java/com/android/ecm/EnhancedConfirmationService.java
+++ b/service/java/com/android/ecm/EnhancedConfirmationService.java
@@ -16,6 +16,9 @@
package com.android.ecm;
+import static android.app.ecm.EnhancedConfirmationManager.REASON_APP_OP_RESTRICTED;
+import static android.app.ecm.EnhancedConfirmationManager.REASON_PHONE_STATE;
+
import android.Manifest;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -89,7 +92,7 @@ public class EnhancedConfirmationService extends SystemService {
private static final int CALL_TYPE_UNTRUSTED = 0;
private static final int CALL_TYPE_TRUSTED = 1;
- private static final int CALL_TYPE_EMERGENCY = 2;
+ private static final int CALL_TYPE_EMERGENCY = 1 << 1;
@IntDef(flag = true, value = {
CALL_TYPE_UNTRUSTED,
CALL_TYPE_TRUSTED,
@@ -269,6 +272,8 @@ public class EnhancedConfirmationService extends SystemService {
PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES);
UNTRUSTED_CALL_RESTRICTED_SETTINGS.add(
AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES);
+ UNTRUSTED_CALL_RESTRICTED_SETTINGS.add(
+ AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE);
}
}
@@ -287,10 +292,16 @@ public class EnhancedConfirmationService extends SystemService {
public boolean isRestricted(@NonNull String packageName, @NonNull String settingIdentifier,
@UserIdInt int userId) {
+ return getRestrictionReason(packageName, settingIdentifier, userId) != null;
+ }
+
+ public String getRestrictionReason(@NonNull String packageName,
+ @NonNull String settingIdentifier,
+ @UserIdInt int userId) {
enforcePermissions("isRestricted", userId);
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
- return false;
+ return null;
}
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
@@ -299,12 +310,13 @@ public class EnhancedConfirmationService extends SystemService {
try {
if (!isSettingEcmProtected(settingIdentifier)) {
- return false;
+ return null;
}
- if (isSettingProtectedGlobally(settingIdentifier)) {
- return true;
+ String globalProtectionReason = getGlobalProtectionReason(settingIdentifier);
+ if (globalProtectionReason != null) {
+ return globalProtectionReason;
}
- return isPackageEcmGuarded(packageName, userId);
+ return isPackageEcmGuarded(packageName, userId) ? REASON_APP_OP_RESTRICTED : null;
} catch (NameNotFoundException e) {
throw new IllegalArgumentException(e);
}
@@ -513,12 +525,13 @@ public class EnhancedConfirmationService extends SystemService {
return false;
}
- private boolean isSettingProtectedGlobally(@NonNull String settingIdentifier) {
- if (UNTRUSTED_CALL_RESTRICTED_SETTINGS.contains(settingIdentifier)) {
- return isUntrustedCallOngoing();
+ private String getGlobalProtectionReason(@NonNull String settingIdentifier) {
+ if (UNTRUSTED_CALL_RESTRICTED_SETTINGS.contains(settingIdentifier)
+ && isUntrustedCallOngoing()) {
+ return REASON_PHONE_STATE;
}
- return false;
+ return null;
}
@Nullable
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt
index baebfe06f..56072d521 100644
--- a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt
+++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt
@@ -52,14 +52,17 @@ class PermissionTapjackingTest : BaseUsePermissionTest() {
requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {}
val buttonCenter =
- waitFindObject(By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT))
- .displayId(displayId))
+ waitFindObject(
+ By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT))
+ .displayId(displayId)
+ )
.visibleCenter
// Wait for overlay to hide the dialog
context.sendBroadcast(Intent(ACTION_SHOW_OVERLAY).putExtra(EXTRA_FULL_OVERLAY, true))
waitFindObject(
- By.res("android.permissionui.cts.usepermission:id/overlay").displayId(displayId))
+ By.res("android.permissionui.cts.usepermission:id/overlay").displayId(displayId)
+ )
tryClicking(buttonCenter)
}
@@ -76,18 +79,19 @@ class PermissionTapjackingTest : BaseUsePermissionTest() {
assertAppHasPermission(ACCESS_FINE_LOCATION, false)
requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {}
- val foregroundButtonCenter =
- waitFindObject(By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT))
- .displayId(displayId))
- .visibleCenter
val oneTimeButton =
- waitFindObjectOrNull(By.text(getPermissionControllerString(ALLOW_ONE_TIME_BUTTON_TEXT))
- .displayId(displayId))
+ waitFindObjectOrNull(
+ By.text(getPermissionControllerString(ALLOW_ONE_TIME_BUTTON_TEXT))
+ .displayId(displayId)
+ )
+
// If one-time button is not available, fallback to deny button
val overlayButtonBounds =
oneTimeButton?.visibleBounds
- ?: waitFindObject(By.text(getPermissionControllerString(DENY_BUTTON_TEXT))
- .displayId(displayId))
+ ?: waitFindObject(
+ By.text(getPermissionControllerString(DENY_BUTTON_TEXT))
+ .displayId(displayId)
+ )
.visibleBounds
// Wait for overlay to hide the dialog
@@ -100,7 +104,15 @@ class PermissionTapjackingTest : BaseUsePermissionTest() {
.putExtra(OVERLAY_BOTTOM, overlayButtonBounds.bottom)
)
waitFindObject(
- By.res("android.permissionui.cts.usepermission:id/overlay").displayId(displayId))
+ By.res("android.permissionui.cts.usepermission:id/overlay").displayId(displayId)
+ )
+
+ val foregroundButtonCenter =
+ waitFindObject(
+ By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT))
+ .displayId(displayId)
+ )
+ .visibleCenter
tryClicking(foregroundButtonCenter)
}
@@ -119,7 +131,7 @@ class PermissionTapjackingTest : BaseUsePermissionTest() {
}
assertAppHasPermission(ACCESS_FINE_LOCATION, true)
},
- 10000
+ 10000,
)
} catch (e: RuntimeException) {
// expected
@@ -140,15 +152,15 @@ class PermissionTapjackingTest : BaseUsePermissionTest() {
}
assertAppHasPermission(ACCESS_FINE_LOCATION, true)
},
- 10000
+ 10000,
)
}
private fun click(buttonCenter: Point) {
val downTime = SystemClock.uptimeMillis()
- val x= buttonCenter.x.toFloat()
+ val x = buttonCenter.x.toFloat()
val y = buttonCenter.y.toFloat()
- var event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN,x , y, 0)
+ var event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0)
event.displayId = displayId
uiAutomation.injectInputEvent(event, true)