diff options
| author | 2023-12-07 23:35:26 +0000 | |
|---|---|---|
| committer | 2023-12-07 23:35:26 +0000 | |
| commit | fce39f1443b1348c5c36951d165f56f99ca1fee4 (patch) | |
| tree | 1f6155b6f6adda69ee4dcc1951da54769d3d3eb9 | |
| parent | 08f3d0adacbec8ea11f0d678fcab121f95ec90d7 (diff) | |
| parent | c30ecdc7437d83abb0e0bf7990e20d7eba15425a (diff) | |
Merge "Update Special App Access Compose Components for ECM" into main
10 files changed, 144 insertions, 18 deletions
| diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedMode.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedMode.kt index 3acc9ad83d2c..b6d92422c333 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedMode.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedMode.kt @@ -18,6 +18,7 @@ package com.android.settingslib.spaprivileged.model.enterprise  import android.app.admin.DevicePolicyResources.Strings.Settings  import android.content.Context +import android.content.Intent  import com.android.settingslib.RestrictedLockUtils  import com.android.settingslib.widget.restricted.R @@ -32,6 +33,11 @@ interface BlockedByAdmin : RestrictedMode {      fun sendShowAdminSupportDetailsIntent()  } +interface BlockedByEcm : RestrictedMode { +    fun showRestrictedSettingsDetails() +} + +  internal data class BlockedByAdminImpl(      private val context: Context,      private val enforcedAdmin: RestrictedLockUtils.EnforcedAdmin, @@ -55,3 +61,13 @@ internal data class BlockedByAdminImpl(          RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context, enforcedAdmin)      }  } + +internal data class BlockedByEcmImpl( +    private val context: Context, +    private val intent: Intent, +) : BlockedByEcm { + +    override fun showRestrictedSettingsDetails() { +        context.startActivity(intent) +    } +} diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt index 550966beb0b8..9432d5995151 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt @@ -29,10 +29,20 @@ import kotlinx.coroutines.Dispatchers  import kotlinx.coroutines.flow.flow  import kotlinx.coroutines.flow.flowOn +data class EnhancedConfirmation( +    val key: String, +    val uid: Int, +    val packageName: String, +)  data class Restrictions(      val userId: Int = UserHandle.myUserId(),      val keys: List<String>, -) +    val enhancedConfirmation: EnhancedConfirmation? = null, +) { +    fun isEmpty(): Boolean { +        return keys.isEmpty() && enhancedConfirmation == null +    } +}  interface RestrictionsProvider {      @Composable @@ -77,6 +87,14 @@ internal class RestrictionsProviderImpl(                  .checkIfRestrictionEnforced(context, key, restrictions.userId)                  ?.let { return BlockedByAdminImpl(context = context, enforcedAdmin = it) }          } + +        restrictions.enhancedConfirmation?.let { ec -> +            RestrictedLockUtilsInternal +                    .checkIfRequiresEnhancedConfirmation(context, ec.key, +                        ec.uid, ec.packageName) +                    ?.let { intent -> return BlockedByEcmImpl(context = context, intent = intent) } +        } +          return NoRestricted      }  } diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt index 06b3eabfad26..25c3bc541249 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt @@ -47,6 +47,9 @@ abstract class AppOpPermissionListModel(      abstract val appOp: Int      abstract val permission: String +    override val enhancedConfirmationKey: String? +        get() = AppOpsManager.opToPublicName(appOp) +      /**       * When set, specifies the broader permission who trumps the [permission].       * diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt index 565543614866..1c830c1c5b06 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt @@ -41,6 +41,7 @@ import com.android.settingslib.spaprivileged.model.app.AppRecord  import com.android.settingslib.spaprivileged.model.app.IPackageManagers  import com.android.settingslib.spaprivileged.model.app.PackageManagers  import com.android.settingslib.spaprivileged.model.app.toRoute +import com.android.settingslib.spaprivileged.model.enterprise.EnhancedConfirmation  import com.android.settingslib.spaprivileged.model.enterprise.Restrictions  import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory  import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl @@ -154,7 +155,12 @@ internal fun <T : AppRecord> TogglePermissionAppListModel<T>.TogglePermissionApp              override val changeable = { isChangeable }              override val onCheckedChange: (Boolean) -> Unit = { setAllowed(record, it) }          } -        val restrictions = Restrictions(userId, switchRestrictionKeys) +        val restrictions = Restrictions(userId = userId, +            keys = switchRestrictionKeys, +            enhancedConfirmation = enhancedConfirmationKey?.let { EnhancedConfirmation( +                key = it, +                uid = checkNotNull(applicationInfo).uid, +                packageName = packageName) })          RestrictedSwitchPreference(switchModel, restrictions, restrictionsProviderFactory)      }  } diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt index 8704f20f5c4a..916d83af3f8f 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt @@ -36,6 +36,9 @@ interface TogglePermissionAppListModel<T : AppRecord> {      val switchRestrictionKeys: List<String>          get() = emptyList() +    val enhancedConfirmationKey: String? +        get() = null +      /**       * Loads the extra info for the App List, and generates the [AppRecord] List.       * diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt index 36c91f463efe..4b474379c54b 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt @@ -41,6 +41,7 @@ import com.android.settingslib.spaprivileged.framework.compose.getPlaceholder  import com.android.settingslib.spaprivileged.model.app.AppListModel  import com.android.settingslib.spaprivileged.model.app.AppRecord  import com.android.settingslib.spaprivileged.model.app.userId +import com.android.settingslib.spaprivileged.model.enterprise.EnhancedConfirmation  import com.android.settingslib.spaprivileged.model.enterprise.Restrictions  import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory  import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl @@ -149,11 +150,17 @@ internal class TogglePermissionInternalAppListModel<T : AppRecord>(      @Composable      fun getSummary(record: T): () -> String { -        val restrictions = remember(record.app.userId) { +        val restrictions = remember(record.app.userId, +                record.app.uid, record.app.packageName) {              Restrictions(                  userId = record.app.userId,                  keys = listModel.switchRestrictionKeys, -            ) +                enhancedConfirmation = listModel.enhancedConfirmationKey?.let { +                    EnhancedConfirmation( +                        key = it, +                        uid = record.app.uid, +                        packageName = record.app.packageName) +                })          }          val restrictedMode by restrictionsProviderFactory.rememberRestrictedMode(restrictions)          val allowed = listModel.isAllowed(record) diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt index d5c5574a0450..cd720252e485 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt @@ -40,7 +40,7 @@ internal fun RestrictedSwitchPreference(      restrictions: Restrictions,      restrictionsProviderFactory: RestrictionsProviderFactory,  ) { -    if (restrictions.keys.isEmpty()) { +    if (restrictions.isEmpty()) {          SwitchPreference(model)          return      } diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt index fa44ecb92ed5..aba3460fc1b9 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt @@ -31,6 +31,7 @@ import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel  import com.android.settingslib.spaprivileged.framework.compose.getPlaceholder  import com.android.settingslib.spaprivileged.model.enterprise.BaseUserRestricted  import com.android.settingslib.spaprivileged.model.enterprise.BlockedByAdmin +import com.android.settingslib.spaprivileged.model.enterprise.BlockedByEcm  import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted  import com.android.settingslib.spaprivileged.model.enterprise.RestrictedMode  import com.android.settingslib.spaprivileged.model.enterprise.Restrictions @@ -56,6 +57,7 @@ internal class RestrictedSwitchPreferenceModel(          is NoRestricted -> model.checked          is BaseUserRestricted -> ({ false })          is BlockedByAdmin -> model.checked +        is BlockedByEcm -> model.checked      }      override val changeable = if (restrictedMode is NoRestricted) model.changeable else ({ false }) @@ -68,24 +70,42 @@ internal class RestrictedSwitchPreferenceModel(          is BaseUserRestricted -> model.onCheckedChange          // Pass null since semantics ToggleableState is provided in RestrictionWrapper.          is BlockedByAdmin -> null +        is BlockedByEcm -> null      }      @Composable      fun RestrictionWrapper(content: @Composable () -> Unit) { -        if (restrictedMode !is BlockedByAdmin) { -            content() -            return +        when (restrictedMode) { +            is BlockedByAdmin -> { +                Box( +                    Modifier +                            .clickable( +                                role = Role.Switch, +                                onClick = { restrictedMode.sendShowAdminSupportDetailsIntent() }, +                            ) +                            .semantics { +                                this.toggleableState = ToggleableState(checked()) +                            }, +                ) { content() } +            } + +            is BlockedByEcm -> { +                Box( +                    Modifier +                            .clickable( +                                role = Role.Switch, +                                onClick = { restrictedMode.showRestrictedSettingsDetails() }, +                            ) +                            .semantics { +                                this.toggleableState = ToggleableState(checked()) +                            }, +                ) { content() } +            } + +            else -> { +                content() +            }          } -        Box( -            Modifier -                .clickable( -                    role = Role.Switch, -                    onClick = { restrictedMode.sendShowAdminSupportDetailsIntent() }, -                ) -                .semantics { -                    this.toggleableState = ToggleableState(checked()) -                }, -        ) { content() }      }      private fun ToggleableState(value: Boolean?) = when (value) { @@ -123,6 +143,9 @@ internal class RestrictedSwitchPreferenceModel(                      context.getString(com.android.settingslib.R.string.disabled)                  is BlockedByAdmin -> restrictedMode.getSummary(checked()) +                is BlockedByEcm -> +                    context.getString(com.android.settingslib.R.string.disabled) +                  null -> context.getPlaceholder()              }          } diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt index f9abefc11e24..977615b55a6a 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.Composable  import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope  import com.android.settingslib.spaprivileged.model.enterprise.BaseUserRestricted  import com.android.settingslib.spaprivileged.model.enterprise.BlockedByAdmin +import com.android.settingslib.spaprivileged.model.enterprise.BlockedByEcm  import com.android.settingslib.spaprivileged.model.enterprise.Restrictions  import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory  import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl @@ -47,6 +48,7 @@ internal fun MoreOptionsScope.RestrictedMenuItemImpl(      MenuItem(text = text, enabled = restrictedMode !== BaseUserRestricted) {          when (restrictedMode) {              is BlockedByAdmin -> restrictedMode.sendShowAdminSupportDetailsIntent() +            is BlockedByEcm -> restrictedMode.showRestrictedSettingsDetails()              else -> onClick()          }      } diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java index e77964c6fa0c..4454b710b7e4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java @@ -22,13 +22,16 @@ import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AF  import static com.android.settingslib.Utils.getColorAttrDefaultColor; +import android.Manifest;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.UserIdInt;  import android.app.AppGlobals; +import android.app.AppOpsManager;  import android.app.admin.DevicePolicyManager;  import android.content.ComponentName;  import android.content.Context; +import android.content.Intent;  import android.content.pm.IPackageManager;  import android.content.pm.PackageManager;  import android.content.pm.UserInfo; @@ -39,10 +42,12 @@ import android.os.RemoteException;  import android.os.UserHandle;  import android.os.UserManager;  import android.os.UserManager.EnforcingUser; +import android.provider.Settings;  import android.text.SpannableStringBuilder;  import android.text.Spanned;  import android.text.style.ForegroundColorSpan;  import android.text.style.ImageSpan; +import android.util.ArraySet;  import android.util.Log;  import android.view.MenuItem;  import android.widget.TextView; @@ -53,6 +58,7 @@ import androidx.annotation.VisibleForTesting;  import com.android.internal.widget.LockPatternUtils;  import java.util.List; +import java.util.Set;  /**   * Utility class to host methods usable in adding a restricted padlock icon and showing admin @@ -62,6 +68,16 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {      private static final String LOG_TAG = "RestrictedLockUtils";      private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG); +    private static final Set<String> ECM_KEYS = new ArraySet<>(); + +    static { +        if (android.security.Flags.extendEcmToAllSettings()) { +            ECM_KEYS.add(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW); +            ECM_KEYS.add(AppOpsManager.OPSTR_GET_USAGE_STATS); +            ECM_KEYS.add(AppOpsManager.OPSTR_LOADER_USAGE_STATS); +            ECM_KEYS.add(Manifest.permission.BIND_DEVICE_ADMIN); +        } +    }      /**       * @return drawables for displaying with settings that are locked by a device admin. @@ -81,6 +97,38 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {      }      /** +     * Checks if a given permission requires additional confirmation for the given package +     * +     * @return An intent to show the user if additional confirmation is required, null otherwise +     */ +    @Nullable +    public static Intent checkIfRequiresEnhancedConfirmation(@NonNull Context context, +                                                             @NonNull String restriction, +                                                             int uid, +                                                             @Nullable String packageName) { +        // TODO(b/297372999): Replace with call to mainline module once ready + +        if (!ECM_KEYS.contains(restriction)) { +            return null; +        } + +        final AppOpsManager appOps = (AppOpsManager) context +                .getSystemService(Context.APP_OPS_SERVICE); +        final int mode = appOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS, +                uid, packageName, null, null); +        final boolean ecmEnabled = context.getResources().getBoolean( +                com.android.internal.R.bool.config_enhancedConfirmationModeEnabled); +        if (ecmEnabled && mode != AppOpsManager.MODE_ALLOWED) { +            final Intent intent = new Intent(Settings.ACTION_SHOW_RESTRICTED_SETTING_DIALOG); +            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); +            intent.putExtra(Intent.EXTRA_UID, uid); +            return intent; +        } + +        return null; +    } + +    /**       * Checks if a restriction is enforced on a user and returns the enforced admin and       * admin userId.       * |