diff options
Diffstat (limited to 'PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt')
-rw-r--r-- | PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt | 986 |
1 files changed, 555 insertions, 431 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt index 99b40d8a7..971542e2b 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt @@ -20,6 +20,7 @@ package com.android.permissioncontroller.permission.ui.model import android.Manifest import android.Manifest.permission.ACCESS_COARSE_LOCATION import android.Manifest.permission.ACCESS_FINE_LOCATION +import android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED import android.Manifest.permission_group.READ_MEDIA_VISUAL import android.annotation.SuppressLint import android.app.Activity @@ -28,19 +29,14 @@ import android.app.AppOpsManager.MODE_ALLOWED import android.app.AppOpsManager.MODE_ERRORED import android.app.AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE import android.app.Application -import android.content.Context import android.content.Intent import android.os.Build import android.os.Bundle import android.os.UserHandle -import android.provider.MediaStore import android.util.Log -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContract import androidx.annotation.ChecksSdkIntAtLeast import androidx.annotation.RequiresApi import androidx.annotation.StringRes -import androidx.core.util.Consumer import androidx.fragment.app.Fragment import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -56,14 +52,13 @@ import com.android.permissioncontroller.R import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState import com.android.permissioncontroller.permission.data.LightAppPermGroupLiveData -import com.android.permissioncontroller.permission.data.v34.SafetyLabelInfoLiveData import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData import com.android.permissioncontroller.permission.data.get +import com.android.permissioncontroller.permission.data.v34.SafetyLabelInfoLiveData import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission import com.android.permissioncontroller.permission.service.PermissionChangeStorageImpl import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl -import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.ALLOW import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.ALLOW_ALWAYS import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.ALLOW_FOREGROUND @@ -73,12 +68,13 @@ import com.android.permissioncontroller.permission.ui.model.AppPermissionViewMod import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.DENY_FOREGROUND import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.LOCATION_ACCURACY import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.SELECT_PHOTOS +import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleActivity import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleActivity.EXTRA_SHOULD_SHOW_SETTINGS_SECTION import com.android.permissioncontroller.permission.utils.KotlinUtils -import com.android.permissioncontroller.permission.utils.KotlinUtils.getDefaultPrecision import com.android.permissioncontroller.permission.utils.KotlinUtils.isLocationAccuracyEnabled import com.android.permissioncontroller.permission.utils.KotlinUtils.isPhotoPickerPromptEnabled +import com.android.permissioncontroller.permission.utils.KotlinUtils.openPhotoPickerForApp import com.android.permissioncontroller.permission.utils.LocationUtils import com.android.permissioncontroller.permission.utils.PermissionMapping import com.android.permissioncontroller.permission.utils.PermissionMapping.getPartialStorageGrantPermissionsForGroup @@ -112,7 +108,6 @@ class AppPermissionViewModel( companion object { private val LOG_TAG = AppPermissionViewModel::class.java.simpleName private const val DEVICE_PROFILE_ROLE_PREFIX = "android.app.role" - const val PHOTO_PICKER_REQUEST_CODE = 1 } interface ConfirmDialogShowingFragment { @@ -134,15 +129,16 @@ class AppPermissionViewModel( GRANT_BOTH(GRANT_FOREGROUND.value or GRANT_BACKGROUND.value), REVOKE_BOTH(REVOKE_FOREGROUND.value or REVOKE_BACKGROUND.value), GRANT_FOREGROUND_ONLY(GRANT_FOREGROUND.value or REVOKE_BACKGROUND.value), - GRANT_All_FILE_ACCESS(1 shl 4), + GRANT_ALL_FILE_ACCESS(1 shl 4), GRANT_FINE_LOCATION(1 shl 5), REVOKE_FINE_LOCATION(1 shl 6), GRANT_STORAGE_SUPERGROUP(1 shl 7), REVOKE_STORAGE_SUPERGROUP(1 shl 8), GRANT_STORAGE_SUPERGROUP_CONFIRMED( - GRANT_STORAGE_SUPERGROUP.value or GRANT_FOREGROUND.value), + GRANT_STORAGE_SUPERGROUP.value or GRANT_FOREGROUND.value + ), REVOKE_STORAGE_SUPERGROUP_CONFIRMED(REVOKE_STORAGE_SUPERGROUP.value or REVOKE_BOTH.value), - PHOTOS_SELECTED( 1 shl 9); + PHOTOS_SELECTED(1 shl 9); infix fun andValue(other: ChangeRequest): Int { return value and other.value @@ -158,89 +154,86 @@ class AppPermissionViewModel( DENY(5), DENY_FOREGROUND(6), LOCATION_ACCURACY(7), - SELECT_PHOTOS( 8); + SELECT_PHOTOS(8) } private val isStorageAndLessThanT = permGroupName == Manifest.permission_group.STORAGE && !SdkLevel.isAtLeastT() private var hasConfirmedRevoke = false private var lightAppPermGroup: LightAppPermGroup? = null - private var photoPickerLauncher: ActivityResultLauncher<Unit>? = null - private var photoPickerResultConsumer: Consumer<Int>? = null private val mediaStorageSupergroupPermGroups = mutableMapOf<String, LightAppPermGroup>() /* Whether the current ViewModel is Location permission with both Coarse and Fine */ private var shouldShowLocationAccuracy: Boolean? = null - /** - * A livedata which determines which detail string, if any, should be shown - */ + /** A livedata which determines which detail string, if any, should be shown */ val detailResIdLiveData = MutableLiveData<Pair<Int, Int?>>() - /** - * A livedata which stores the device admin, if there is one - */ + /** A livedata which stores the device admin, if there is one */ val showAdminSupportLiveData = MutableLiveData<RestrictedLockUtils.EnforcedAdmin>() - /** - * A livedata for determining the display state of safety label information - */ - val showPermissionRationaleLiveData = object : SmartUpdateMediatorLiveData<Boolean>() { - private val safetyLabelInfoLiveData = if (SdkLevel.isAtLeastU()) { - SafetyLabelInfoLiveData[packageName, user] - } else { - null - } + /** A livedata for determining the display state of safety label information */ + val showPermissionRationaleLiveData = + object : SmartUpdateMediatorLiveData<Boolean>() { + private val safetyLabelInfoLiveData = + if (SdkLevel.isAtLeastU()) { + SafetyLabelInfoLiveData[packageName, user] + } else { + null + } - init { - if (safetyLabelInfoLiveData != null && - PermissionMapping.isSafetyLabelAwarePermissionGroup(permGroupName)) { - addSource(safetyLabelInfoLiveData) { update() } - } else { - value = false + init { + if ( + safetyLabelInfoLiveData != null && + PermissionMapping.isSafetyLabelAwarePermissionGroup(permGroupName) + ) { + addSource(safetyLabelInfoLiveData) { update() } + } else { + value = false + } } - } - override fun onUpdate() { - if (safetyLabelInfoLiveData != null && safetyLabelInfoLiveData.isStale) { - return - } + override fun onUpdate() { + if (safetyLabelInfoLiveData != null && safetyLabelInfoLiveData.isStale) { + return + } - val safetyLabel = safetyLabelInfoLiveData?.value?.safetyLabel - if (safetyLabel == null) { - value = false - return - } + val safetyLabel = safetyLabelInfoLiveData?.value?.safetyLabel + if (safetyLabel == null) { + value = false + return + } - value = SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup( - safetyLabel, permGroupName).any() + value = + SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup( + safetyLabel, + permGroupName + ) + .any() + } } - } - /** - * A livedata which determines which detail string, if any, should be shown - */ - val fullStorageStateLiveData = object : SmartUpdateMediatorLiveData<FullStoragePackageState>() { - init { - if (isStorageAndLessThanT) { - addSource(FullStoragePermissionAppsLiveData) { - update() + /** A livedata which determines which detail string, if any, should be shown */ + val fullStorageStateLiveData = + object : SmartUpdateMediatorLiveData<FullStoragePackageState>() { + init { + if (isStorageAndLessThanT) { + addSource(FullStoragePermissionAppsLiveData) { update() } + } else { + value = null } - } else { - value = null } - } - override fun onUpdate() { - for (state in FullStoragePermissionAppsLiveData.value ?: return) { - if (state.packageName == packageName && state.user == user) { - value = state - return + override fun onUpdate() { + for (state in FullStoragePermissionAppsLiveData.value ?: return) { + if (state.packageName == packageName && state.user == user) { + value = state + return + } } + value = null + return } - value = null - return } - } data class ButtonState( var isChecked: Boolean, @@ -251,182 +244,211 @@ class AppPermissionViewModel( constructor() : this(false, true, false, null) } - /** - * A livedata which computes the state of the radio buttons - */ - val buttonStateLiveData = object : - SmartUpdateMediatorLiveData<@JvmSuppressWildcards Map<ButtonType, ButtonState>>() { + /** A livedata which computes the state of the radio buttons */ + val buttonStateLiveData = + object : SmartUpdateMediatorLiveData<@JvmSuppressWildcards Map<ButtonType, ButtonState>>() { - private val appPermGroupLiveData = LightAppPermGroupLiveData[packageName, permGroupName, - user] - private val mediaStorageSupergroupLiveData = - mutableMapOf<String, LightAppPermGroupLiveData>() + private val appPermGroupLiveData = + LightAppPermGroupLiveData[packageName, permGroupName, user] + private val mediaStorageSupergroupLiveData = + mutableMapOf<String, LightAppPermGroupLiveData>() - init { + init { + addSource(appPermGroupLiveData) { appPermGroup -> + lightAppPermGroup = appPermGroup + if (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) { + onMediaPermGroupUpdate(permGroupName, appPermGroup) + } + if (appPermGroupLiveData.isInitialized && appPermGroup == null) { + value = null + } else if (appPermGroup != null) { + if (isStorageAndLessThanT && !fullStorageStateLiveData.isInitialized) { + return@addSource + } + update() + } + } - addSource(appPermGroupLiveData) { appPermGroup -> - lightAppPermGroup = appPermGroup - if (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) { - onMediaPermGroupUpdate(permGroupName, appPermGroup) + if (isStorageAndLessThanT) { + addSource(fullStorageStateLiveData) { update() } } - if (appPermGroupLiveData.isInitialized && appPermGroup == null) { - value = null - } else if (appPermGroup != null) { - if (isStorageAndLessThanT && !fullStorageStateLiveData.isInitialized) { - return@addSource + + if (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) { + for (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) { + val liveData = LightAppPermGroupLiveData[packageName, permGroupName, user] + mediaStorageSupergroupLiveData[permGroupName] = liveData + } + for (permGroupName in mediaStorageSupergroupLiveData.keys) { + val liveData = mediaStorageSupergroupLiveData[permGroupName]!! + addSource(liveData) { permGroup -> + onMediaPermGroupUpdate(permGroupName, permGroup) + } } - update() } + + addSource(showPermissionRationaleLiveData) { update() } } - if (isStorageAndLessThanT) { - addSource(fullStorageStateLiveData) { + private fun onMediaPermGroupUpdate( + permGroupName: String, + permGroup: LightAppPermGroup? + ) { + if (permGroup == null) { + mediaStorageSupergroupPermGroups.remove(permGroupName) + value = null + } else { + mediaStorageSupergroupPermGroups[permGroupName] = permGroup update() } } - if (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) { - for (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) { - val liveData = LightAppPermGroupLiveData[packageName, permGroupName, user] - mediaStorageSupergroupLiveData[permGroupName] = liveData - } - for (permGroupName in mediaStorageSupergroupLiveData.keys) { - val liveData = mediaStorageSupergroupLiveData[permGroupName]!! - addSource(liveData) { permGroup -> - onMediaPermGroupUpdate(permGroupName, permGroup) + override fun onUpdate() { + val group = appPermGroupLiveData.value ?: return + for (mediaGroupLiveData in mediaStorageSupergroupLiveData.values) { + if (!mediaGroupLiveData.isInitialized) { + return } } - } - - addSource(showPermissionRationaleLiveData) { - update() - } - } - - private fun onMediaPermGroupUpdate(permGroupName: String, permGroup: LightAppPermGroup?) { - if (permGroup == null) { - mediaStorageSupergroupPermGroups.remove(permGroupName) - value = null - } else { - mediaStorageSupergroupPermGroups[permGroupName] = permGroup - update() - } - } - override fun onUpdate() { - val group = appPermGroupLiveData.value ?: return - for (mediaGroupLiveData in mediaStorageSupergroupLiveData.values) { - if (!mediaGroupLiveData.isInitialized) { + if (!showPermissionRationaleLiveData.isInitialized) { return } - } - if (!showPermissionRationaleLiveData.isInitialized) { - return - } - - val admin = RestrictedLockUtils.getProfileOrDeviceOwner(app, user) - - val allowedState = ButtonState() - val allowedAlwaysState = ButtonState() - val allowedForegroundState = ButtonState() - val askOneTimeState = ButtonState() - val askState = ButtonState() - val deniedState = ButtonState() - val deniedForegroundState = ButtonState() - val selectState = ButtonState() - - askOneTimeState.isShown = group.foreground.isGranted && group.isOneTime - askState.isShown = PermissionMapping.supportsOneTimeGrant(permGroupName) && - !(group.foreground.isGranted && group.isOneTime) - deniedState.isShown = true - - if (group.hasPermWithBackgroundMode) { - // Background / Foreground / Deny case - allowedForegroundState.isShown = true - if (group.hasBackgroundGroup) { - allowedAlwaysState.isShown = true - } + val admin = RestrictedLockUtils.getProfileOrDeviceOwner(app, user) + + val allowedState = ButtonState() + val allowedAlwaysState = ButtonState() + val allowedForegroundState = ButtonState() + val askOneTimeState = ButtonState() + val askState = ButtonState() + val deniedState = ButtonState() + val deniedForegroundState = ButtonState() + val selectState = ButtonState() + + askOneTimeState.isShown = group.foreground.isGranted && group.isOneTime + askState.isShown = + PermissionMapping.supportsOneTimeGrant(permGroupName) && + !(group.foreground.isGranted && group.isOneTime) + deniedState.isShown = true - allowedAlwaysState.isChecked = group.background.isGranted && - group.foreground.isGranted && !group.background.isOneTime - allowedForegroundState.isChecked = group.foreground.isGranted && - (!group.background.isGranted || group.background.isOneTime) && - !group.foreground.isOneTime - askState.isChecked = !group.foreground.isGranted && group.isOneTime - askOneTimeState.isChecked = group.foreground.isGranted && group.isOneTime - askOneTimeState.isShown = askOneTimeState.isChecked - deniedState.isChecked = !group.foreground.isGranted && !group.isOneTime - if (applyFixToForegroundBackground(group, group.foreground.isSystemFixed, - group.background.isSystemFixed, allowedAlwaysState, - allowedForegroundState, askState, deniedState, - deniedForegroundState) || - applyFixToForegroundBackground(group, group.foreground.isPolicyFixed, - group.background.isPolicyFixed, allowedAlwaysState, - allowedForegroundState, askState, deniedState, - deniedForegroundState)) { - showAdminSupportLiveData.value = admin - val detailId = getDetailResIdForFixedByPolicyPermissionGroup(group, - admin != null) - if (detailId != 0) { - detailResIdLiveData.value = detailId to null + if (group.hasPermWithBackgroundMode) { + // Background / Foreground / Deny case + allowedForegroundState.isShown = true + if (group.hasBackgroundGroup) { + allowedAlwaysState.isShown = true } - } else if (Utils.areGroupPermissionsIndividuallyControlled(app, permGroupName)) { - val detailId = getIndividualPermissionDetailResId(group) - detailResIdLiveData.value = detailId.first to detailId.second - } - } else if (KotlinUtils.isPhotoPickerPromptEnabled() && - group.permGroupName == READ_MEDIA_VISUAL && - group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU) { - // Allow / Select Photos / Deny case - allowedState.isShown = true - deniedState.isShown = true - selectState.isShown = true - deniedState.isChecked = !group.isGranted - selectState.isChecked = isPartialStorageGrant(group) - allowedState.isChecked = group.isGranted && !isPartialStorageGrant(group) - } else { - // Allow / Deny case - allowedState.isShown = true - - allowedState.isChecked = group.foreground.isGranted && !group.foreground.isOneTime - askState.isChecked = !group.foreground.isGranted && group.isOneTime - askOneTimeState.isChecked = group.foreground.isGranted && group.isOneTime - askOneTimeState.isShown = askOneTimeState.isChecked - deniedState.isChecked = !group.foreground.isGranted && !group.isOneTime - - if (group.foreground.isPolicyFixed || group.foreground.isSystemFixed) { - allowedState.isEnabled = false - askState.isEnabled = false - deniedState.isEnabled = false - showAdminSupportLiveData.value = admin - val detailId = getDetailResIdForFixedByPolicyPermissionGroup(group, - admin != null) - if (detailId != 0) { - detailResIdLiveData.value = detailId to null + allowedAlwaysState.isChecked = + group.background.isGranted && + group.foreground.isGranted && + !group.background.isOneTime + allowedForegroundState.isChecked = + group.foreground.isGranted && + (!group.background.isGranted || group.background.isOneTime) && + !group.foreground.isOneTime + askState.isChecked = !group.foreground.isGranted && group.isOneTime + askOneTimeState.isChecked = group.foreground.isGranted && group.isOneTime + askOneTimeState.isShown = askOneTimeState.isChecked + deniedState.isChecked = !group.foreground.isGranted && !group.isOneTime + if ( + applyFixToForegroundBackground( + group, + group.foreground.isSystemFixed, + group.background.isSystemFixed, + allowedAlwaysState, + allowedForegroundState, + askState, + deniedState, + deniedForegroundState + ) || + applyFixToForegroundBackground( + group, + group.foreground.isPolicyFixed, + group.background.isPolicyFixed, + allowedAlwaysState, + allowedForegroundState, + askState, + deniedState, + deniedForegroundState + ) + ) { + showAdminSupportLiveData.value = admin + val detailId = + getDetailResIdForFixedByPolicyPermissionGroup(group, admin != null) + if (detailId != 0) { + detailResIdLiveData.value = detailId to null + } + } else if ( + Utils.areGroupPermissionsIndividuallyControlled(app, permGroupName) + ) { + val detailId = getIndividualPermissionDetailResId(group) + detailResIdLiveData.value = detailId.first to detailId.second + } + } else if ( + shouldShowPhotoPickerPromptForApp(group) && + group.permGroupName == READ_MEDIA_VISUAL + ) { + // Allow / Select Photos / Deny case + allowedState.isShown = true + deniedState.isShown = true + selectState.isShown = true + + deniedState.isChecked = !group.isGranted + selectState.isChecked = isPartialStorageGrant(group) + allowedState.isChecked = group.isGranted && !isPartialStorageGrant(group) + if (group.foreground.isPolicyFixed || group.foreground.isSystemFixed) { + allowedState.isEnabled = false + selectState.isEnabled = false + deniedState.isEnabled = false + showAdminSupportLiveData.value = admin + val detailId = + getDetailResIdForFixedByPolicyPermissionGroup(group, admin != null) + if (detailId != 0) { + detailResIdLiveData.value = detailId to null + } + } + } else { + // Allow / Deny case + allowedState.isShown = true + + allowedState.isChecked = + group.foreground.isGranted && !group.foreground.isOneTime + askState.isChecked = !group.foreground.isGranted && group.isOneTime + askOneTimeState.isChecked = group.foreground.isGranted && group.isOneTime + askOneTimeState.isShown = askOneTimeState.isChecked + deniedState.isChecked = !group.foreground.isGranted && !group.isOneTime + + if (group.foreground.isPolicyFixed || group.foreground.isSystemFixed) { + allowedState.isEnabled = false + askState.isEnabled = false + deniedState.isEnabled = false + showAdminSupportLiveData.value = admin + val detailId = + getDetailResIdForFixedByPolicyPermissionGroup(group, admin != null) + if (detailId != 0) { + detailResIdLiveData.value = detailId to null + } + } + if (isForegroundGroupSpecialCase(permGroupName)) { + allowedForegroundState.isShown = true + allowedState.isShown = false + allowedForegroundState.isChecked = allowedState.isChecked + allowedForegroundState.isEnabled = allowedState.isEnabled } } - if (isForegroundGroupSpecialCase(permGroupName)) { - allowedForegroundState.isShown = true - allowedState.isShown = false - allowedForegroundState.isChecked = allowedState.isChecked - allowedForegroundState.isEnabled = allowedState.isEnabled + if (group.packageInfo.targetSdkVersion < Build.VERSION_CODES.M) { + // Pre-M app's can't ask for runtime permissions + askState.isShown = false + deniedState.isChecked = askState.isChecked || deniedState.isChecked + deniedForegroundState.isChecked = + askState.isChecked || deniedForegroundState.isChecked } - } - if (group.packageInfo.targetSdkVersion < Build.VERSION_CODES.M) { - // Pre-M app's can't ask for runtime permissions - askState.isShown = false - deniedState.isChecked = askState.isChecked || deniedState.isChecked - deniedForegroundState.isChecked = askState.isChecked || - deniedForegroundState.isChecked - } - val storageState = fullStorageStateLiveData.value - if (isStorageAndLessThanT && storageState?.isLegacy != true) { - val allowedAllFilesState = allowedAlwaysState - val allowedMediaOnlyState = allowedForegroundState - if (storageState != null) { + val storageState = fullStorageStateLiveData.value + if (isStorageAndLessThanT && storageState?.isLegacy != true) { + val allowedAllFilesState = allowedAlwaysState + val allowedMediaOnlyState = allowedForegroundState + if (storageState != null) { // Set up the tri state permission for storage allowedAllFilesState.isEnabled = allowedState.isEnabled allowedAllFilesState.isShown = true @@ -434,62 +456,64 @@ class AppPermissionViewModel( allowedAllFilesState.isChecked = true deniedState.isChecked = false } - } else { - allowedAllFilesState.isEnabled = false - allowedAllFilesState.isShown = false + } else { + allowedAllFilesState.isEnabled = false + allowedAllFilesState.isShown = false + } + allowedMediaOnlyState.isShown = true + allowedMediaOnlyState.isEnabled = allowedState.isEnabled + allowedMediaOnlyState.isChecked = + allowedState.isChecked && storageState?.isGranted != true + allowedState.isChecked = false + allowedState.isShown = false } - allowedMediaOnlyState.isShown = true - allowedMediaOnlyState.isEnabled = allowedState.isEnabled - allowedMediaOnlyState.isChecked = allowedState.isChecked && - storageState?.isGranted != true - allowedState.isChecked = false - allowedState.isShown = false - } - if (shouldShowLocationAccuracy == null) { - shouldShowLocationAccuracy = isLocationAccuracyEnabled() && - group.permissions.containsKey(ACCESS_FINE_LOCATION) - } - val locationAccuracyState = ButtonState(isFineLocationChecked(group), - true, false, null) - if (shouldShowLocationAccuracy == true && !deniedState.isChecked) { - locationAccuracyState.isShown = true - } - if (group.foreground.isSystemFixed || group.foreground.isPolicyFixed) { - locationAccuracyState.isEnabled = false - } + if (shouldShowLocationAccuracy == null) { + shouldShowLocationAccuracy = + isLocationAccuracyEnabled() && + group.permissions.containsKey(ACCESS_FINE_LOCATION) + } + val locationAccuracyState = + ButtonState(isFineLocationChecked(group), true, false, null) + if (shouldShowLocationAccuracy == true && !deniedState.isChecked) { + locationAccuracyState.isShown = true + } + if (group.foreground.isSystemFixed || group.foreground.isPolicyFixed) { + locationAccuracyState.isEnabled = false + } - if (value == null) { - logAppPermissionFragmentViewed() - } + if (value == null) { + logAppPermissionFragmentViewed() + } - value = mapOf( - ALLOW to allowedState, ALLOW_ALWAYS to allowedAlwaysState, - ALLOW_FOREGROUND to allowedForegroundState, ASK_ONCE to askOneTimeState, - ASK to askState, DENY to deniedState, DENY_FOREGROUND to deniedForegroundState, - LOCATION_ACCURACY to locationAccuracyState, SELECT_PHOTOS to selectState) + value = + mapOf( + ALLOW to allowedState, + ALLOW_ALWAYS to allowedAlwaysState, + ALLOW_FOREGROUND to allowedForegroundState, + ASK_ONCE to askOneTimeState, + ASK to askState, + DENY to deniedState, + DENY_FOREGROUND to deniedForegroundState, + LOCATION_ACCURACY to locationAccuracyState, + SELECT_PHOTOS to selectState + ) + } } - } - fun registerPhotoPickerResultIfNeeded(fragment: Fragment) { - if (permGroupName != READ_MEDIA_VISUAL) { - return + @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake") + private fun shouldShowPhotoPickerPromptForApp(group: LightAppPermGroup): Boolean { + if ( + !isPhotoPickerPromptEnabled() || + group.packageInfo.targetSdkVersion < Build.VERSION_CODES.TIRAMISU + ) { + return false } - photoPickerLauncher = fragment.registerForActivityResult( - object : ActivityResultContract<Unit, Int>() { - override fun parseResult(resultCode: Int, intent: Intent?): Int { - return resultCode - } - - override fun createIntent(context: Context, input: Unit): Intent { - return Intent(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP) - .putExtra(Intent.EXTRA_UID, lightAppPermGroup?.packageInfo?.uid) - .setType(KotlinUtils.getMimeTypeForPermissions( - lightAppPermGroup?.foregroundPermNames ?: emptyList())) - } - }) { result -> - photoPickerResultConsumer?.accept(result) + if (group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + return true } + val userSelectedPerm = group.permissions[READ_MEDIA_VISUAL_USER_SELECTED] ?: return false + return !userSelectedPerm.isImplicit } private fun isFineLocationChecked(group: LightAppPermGroup): Boolean { @@ -501,14 +525,17 @@ class AppPermissionViewModel( // 2. Else if FINE or COARSE have the isSelectedLocationAccuracy flag set, then return // true if FINE isSelectedLocationAccuracy is set. // 3. Else, return default precision from device config. - return if (fineLocation.isGrantedIncludingAppOp || - coarseLocation.isGrantedIncludingAppOp) { + return if ( + fineLocation.isGrantedIncludingAppOp || coarseLocation.isGrantedIncludingAppOp + ) { fineLocation.isGrantedIncludingAppOp - } else if (fineLocation.isSelectedLocationAccuracy || - coarseLocation.isSelectedLocationAccuracy) { + } else if ( + fineLocation.isSelectedLocationAccuracy || coarseLocation.isSelectedLocationAccuracy + ) { fineLocation.isSelectedLocationAccuracy } else { - getDefaultPrecision() + // default location precision is true, indicates FINE + true } } return false @@ -517,7 +544,7 @@ class AppPermissionViewModel( // TODO evanseverson: Actually change mic/camera to be a foreground only permission private fun isForegroundGroupSpecialCase(permissionGroupName: String): Boolean { return permissionGroupName.equals(Manifest.permission_group.CAMERA) || - permissionGroupName.equals(Manifest.permission_group.MICROPHONE) + permissionGroupName.equals(Manifest.permission_group.MICROPHONE) } /** @@ -608,10 +635,12 @@ class AppPermissionViewModel( logAppPermissionFragmentActionReportedForPermissionGroup( /* changeId= */ Random().nextLong(), group, - APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__PERMISSION_RATIONALE) + APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__PERMISSION_RATIONALE + ) } - val intent = Intent(activity, PermissionRationaleActivity::class.java).apply { + val intent = + Intent(activity, PermissionRationaleActivity::class.java).apply { putExtra(Intent.EXTRA_PACKAGE_NAME, packageName) putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName) putExtra(Constants.EXTRA_SESSION_ID, sessionId) @@ -622,6 +651,7 @@ class AppPermissionViewModel( /** * Navigate to either the App Permission Groups screen, or the Permission Apps Screen. + * * @param fragment The current fragment * @param action The action to be taken * @param args The arguments to pass to the fragment @@ -635,26 +665,33 @@ class AppPermissionViewModel( fragment.findNavController().navigateSafe(actionId, args) } + fun openPhotoPicker(fragment: Fragment) { + val appPermGroup = lightAppPermGroup ?: return + openPhotoPickerForApp( + fragment.requireActivity(), + appPermGroup.packageInfo.uid, + appPermGroup.foregroundPermNames, + 0 + ) + } + /** * Request to grant/revoke permissions group. * * Does <u>not</u> handle: - * - * * Individually granted permissions - * * Permission groups with background permissions + * * Individually granted permissions + * * Permission groups with background permissions * * <u>Does</u> handle: - * - * * Default grant permissions + * * Default grant permissions * * @param setOneTime Whether or not to set this permission as one time * @param fragment The fragment calling this method * @param defaultDeny The system which will show the default deny dialog. Usually the same as - * the fragment. + * the fragment. * @param changeRequest Which permission group (foreground/background/both) should be changed * @param buttonClicked button which was pressed to initiate the change, one of - * AppPermissionFragmentActionReported.button_pressed constants - * + * AppPermissionFragmentActionReported.button_pressed constants * @return The dialogue to show, if applicable, or if the request was processed. */ fun requestChange( @@ -685,8 +722,12 @@ class AppPermissionViewModel( if (changeRequest == ChangeRequest.REVOKE_FINE_LOCATION) { if (!group.isOneTime) { - val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group, - filterPermissions = listOf(ACCESS_FINE_LOCATION)) + val newGroup = + KotlinUtils.revokeForegroundRuntimePermissions( + app, + group, + filterPermissions = listOf(ACCESS_FINE_LOCATION) + ) logPermissionChanges(group, newGroup, buttonClicked) } KotlinUtils.setFlagsWhenLocationAccuracyChanged(app, group, false) @@ -696,10 +737,18 @@ class AppPermissionViewModel( if (changeRequest == ChangeRequest.PHOTOS_SELECTED) { val partialGrantPerms = getPartialStorageGrantPermissionsForGroup(group) val nonSelectedPerms = group.permissions.keys.filter { it !in partialGrantPerms } - var newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group, - filterPermissions = nonSelectedPerms) - newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, newGroup, - filterPermissions = partialGrantPerms.toList()) + var newGroup = + KotlinUtils.revokeForegroundRuntimePermissions( + app, + group, + filterPermissions = nonSelectedPerms + ) + newGroup = + KotlinUtils.grantForegroundRuntimePermissions( + app, + newGroup, + filterPermissions = partialGrantPerms.toList() + ) logPermissionChanges(group, newGroup, buttonClicked) return } @@ -713,27 +762,31 @@ class AppPermissionViewModel( var showCDMWarning = false if (shouldRevokeForeground && wasForegroundGranted) { - showDefaultDenyDialog = (group.foreground.isGrantedByDefault || + showDefaultDenyDialog = + (group.foreground.isGrantedByDefault || !group.supportsRuntimePerms || group.hasInstallToRuntimeSplit) - showGrantedByDefaultWarning = showGrantedByDefaultWarning || - group.foreground.isGrantedByDefault + showGrantedByDefaultWarning = + showGrantedByDefaultWarning || group.foreground.isGrantedByDefault showCDMWarning = showCDMWarning || group.foreground.isGrantedByRole } if (shouldRevokeBackground && wasBackgroundGranted) { - showDefaultDenyDialog = showDefaultDenyDialog || + showDefaultDenyDialog = + showDefaultDenyDialog || group.background.isGrantedByDefault || !group.supportsRuntimePerms || group.hasInstallToRuntimeSplit - showGrantedByDefaultWarning = showGrantedByDefaultWarning || - group.background.isGrantedByDefault + showGrantedByDefaultWarning = + showGrantedByDefaultWarning || group.background.isGrantedByDefault showCDMWarning = showCDMWarning || group.background.isGrantedByRole } if (showCDMWarning) { // Refine showCDMWarning to only trigger for apps holding a device profile role - val heldRoles = context.getSystemService(android.app.role.RoleManager::class.java) + val heldRoles = + context + .getSystemService(android.app.role.RoleManager::class.java)!! .getHeldRolesFromController(packageName) val heldProfiles = heldRoles.filter { it.startsWith(DEVICE_PROFILE_ROLE_PREFIX) } showCDMWarning = showCDMWarning && heldProfiles.isNotEmpty() @@ -743,14 +796,24 @@ class AppPermissionViewModel( if (group.permGroupName == Manifest.permission_group.STORAGE) { showDefaultDenyDialog = false } else if (changeRequest == ChangeRequest.GRANT_FOREGROUND) { - showMediaConfirmDialog(setOneTime, defaultDeny, - ChangeRequest.GRANT_STORAGE_SUPERGROUP, buttonClicked, group.permGroupName, - group.packageInfo.targetSdkVersion) + showMediaConfirmDialog( + setOneTime, + defaultDeny, + ChangeRequest.GRANT_STORAGE_SUPERGROUP, + buttonClicked, + group.permGroupName, + group.packageInfo.targetSdkVersion + ) return } else if (changeRequest == ChangeRequest.REVOKE_BOTH) { - showMediaConfirmDialog(setOneTime, defaultDeny, - ChangeRequest.REVOKE_STORAGE_SUPERGROUP, buttonClicked, group.permGroupName, - group.packageInfo.targetSdkVersion) + showMediaConfirmDialog( + setOneTime, + defaultDeny, + ChangeRequest.REVOKE_STORAGE_SUPERGROUP, + buttonClicked, + group.permGroupName, + group.packageInfo.targetSdkVersion + ) return } else { showDefaultDenyDialog = false @@ -758,20 +821,32 @@ class AppPermissionViewModel( } if (showDefaultDenyDialog && !hasConfirmedRevoke && showGrantedByDefaultWarning) { - defaultDeny.showConfirmDialog(changeRequest, R.string.system_warning, buttonClicked, - setOneTime) + defaultDeny.showConfirmDialog( + changeRequest, + R.string.system_warning, + buttonClicked, + setOneTime + ) return } if (showDefaultDenyDialog && !hasConfirmedRevoke) { - defaultDeny.showConfirmDialog(changeRequest, R.string.old_sdk_deny_warning, - buttonClicked, setOneTime) + defaultDeny.showConfirmDialog( + changeRequest, + R.string.old_sdk_deny_warning, + buttonClicked, + setOneTime + ) return } if (showCDMWarning) { - defaultDeny.showConfirmDialog(changeRequest, - R.string.cdm_profile_revoke_warning, buttonClicked, setOneTime) + defaultDeny.showConfirmDialog( + changeRequest, + R.string.cdm_profile_revoke_warning, + buttonClicked, + setOneTime + ) return } @@ -780,12 +855,20 @@ class AppPermissionViewModel( var newGroup = group2 val oldGroup = group2 - if (shouldRevokeBackground && group2.hasBackgroundGroup && - (wasBackgroundGranted || group2.background.isUserFixed || - group2.isOneTime != setOneTime)) { - newGroup = KotlinUtils - .revokeBackgroundRuntimePermissions(app, newGroup, oneTime = setOneTime, - forceRemoveRevokedCompat = shouldClearOneTimeRevokedCompat(newGroup)) + if ( + shouldRevokeBackground && + group2.hasBackgroundGroup && + (wasBackgroundGranted || + group2.background.isUserFixed || + group2.isOneTime != setOneTime) + ) { + newGroup = + KotlinUtils.revokeBackgroundRuntimePermissions( + app, + newGroup, + oneTime = setOneTime, + forceRemoveRevokedCompat = shouldClearOneTimeRevokedCompat(newGroup) + ) // only log if we have actually denied permissions, not if we switch from // "ask every time" to denied @@ -794,12 +877,17 @@ class AppPermissionViewModel( } } - if (shouldRevokeForeground && - (wasForegroundGranted || group2.isOneTime != setOneTime)) { - newGroup = KotlinUtils - .revokeForegroundRuntimePermissions(app, newGroup, userFixed = false, - oneTime = setOneTime, - forceRemoveRevokedCompat = shouldClearOneTimeRevokedCompat(newGroup)) + if ( + shouldRevokeForeground && (wasForegroundGranted || group2.isOneTime != setOneTime) + ) { + newGroup = + KotlinUtils.revokeForegroundRuntimePermissions( + app, + newGroup, + userFixed = false, + oneTime = setOneTime, + forceRemoveRevokedCompat = shouldClearOneTimeRevokedCompat(newGroup) + ) // only log if we have actually denied permissions, not if we switch from // "ask every time" to denied @@ -809,13 +897,16 @@ class AppPermissionViewModel( } if (shouldGrantForeground) { - newGroup = if (shouldShowLocationAccuracy == true && - !isFineLocationChecked(newGroup)) { - KotlinUtils.grantForegroundRuntimePermissions(app, newGroup, - filterPermissions = listOf(ACCESS_COARSE_LOCATION)) - } else { - KotlinUtils.grantForegroundRuntimePermissions(app, newGroup) - } + newGroup = + if (shouldShowLocationAccuracy == true && !isFineLocationChecked(newGroup)) { + KotlinUtils.grantForegroundRuntimePermissions( + app, + newGroup, + filterPermissions = listOf(ACCESS_COARSE_LOCATION) + ) + } else { + KotlinUtils.grantForegroundRuntimePermissions(app, newGroup) + } if (!wasForegroundGranted) { SafetyNetLogger.logPermissionToggled(newGroup) @@ -832,15 +923,14 @@ class AppPermissionViewModel( logPermissionChanges(oldGroup, newGroup, buttonClicked) - fullStorageStateLiveData.value?.let { - FullStoragePermissionAppsLiveData.recalculate() - } + fullStorageStateLiveData.value?.let { FullStoragePermissionAppsLiveData.recalculate() } } } private fun shouldClearOneTimeRevokedCompat(group: LightAppPermGroup): Boolean { - return isPhotoPickerPromptEnabled() && permGroupName == READ_MEDIA_VISUAL && - group.permissions.values.any { it.isCompatRevoked && it.isOneTime } + return isPhotoPickerPromptEnabled() && + permGroupName == READ_MEDIA_VISUAL && + group.permissions.values.any { it.isCompatRevoked && it.isOneTime } } @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU) @@ -850,8 +940,10 @@ class AppPermissionViewModel( } private fun expandToSupergroup(group: LightAppPermGroup): List<LightAppPermGroup> { - val mediaSupergroup = PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS - .mapNotNull { mediaStorageSupergroupPermGroups[it] } + val mediaSupergroup = + PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS.mapNotNull { + mediaStorageSupergroupPermGroups[it] + } return if (expandsToStorageSupergroup(group)) { mediaSupergroup } else { @@ -860,21 +952,23 @@ class AppPermissionViewModel( } private fun getPermGroupIcon(permGroup: String) = - Utils.getGroupInfo(permGroup, app.applicationContext)?.icon ?: R.drawable.ic_empty_icon + Utils.getGroupInfo(permGroup, app.applicationContext)?.icon ?: R.drawable.ic_empty_icon private val storagePermGroupIcon = getPermGroupIcon(Manifest.permission_group.STORAGE) - private val auralPermGroupIcon = if (SdkLevel.isAtLeastT()) { - getPermGroupIcon(Manifest.permission_group.READ_MEDIA_AURAL) - } else { - R.drawable.ic_empty_icon - } + private val auralPermGroupIcon = + if (SdkLevel.isAtLeastT()) { + getPermGroupIcon(Manifest.permission_group.READ_MEDIA_AURAL) + } else { + R.drawable.ic_empty_icon + } - private val visualPermGroupIcon = if (SdkLevel.isAtLeastT()) { - getPermGroupIcon(Manifest.permission_group.READ_MEDIA_VISUAL) - } else { - R.drawable.ic_empty_icon - } + private val visualPermGroupIcon = + if (SdkLevel.isAtLeastT()) { + getPermGroupIcon(Manifest.permission_group.READ_MEDIA_VISUAL) + } else { + R.drawable.ic_empty_icon + } @RequiresApi(Build.VERSION_CODES.TIRAMISU) private fun showMediaConfirmDialog( @@ -885,56 +979,63 @@ class AppPermissionViewModel( groupName: String, targetSdk: Int ) { - val aural = groupName == Manifest.permission_group.READ_MEDIA_AURAL val visual = groupName == Manifest.permission_group.READ_MEDIA_VISUAL val allow = changeRequest === ChangeRequest.GRANT_STORAGE_SUPERGROUP val deny = changeRequest === ChangeRequest.REVOKE_STORAGE_SUPERGROUP - val (iconId, titleId, messageId) = when { - targetSdk < Build.VERSION_CODES.Q && aural && allow -> - Triple( - storagePermGroupIcon, - R.string.media_confirm_dialog_title_a_to_p_aural_allow, - R.string.media_confirm_dialog_message_a_to_p_aural_allow) - targetSdk < Build.VERSION_CODES.Q && aural && deny -> - Triple( - storagePermGroupIcon, - R.string.media_confirm_dialog_title_a_to_p_aural_deny, - R.string.media_confirm_dialog_message_a_to_p_aural_deny) - targetSdk < Build.VERSION_CODES.Q && visual && allow -> - Triple( - storagePermGroupIcon, - R.string.media_confirm_dialog_title_a_to_p_visual_allow, - R.string.media_confirm_dialog_message_a_to_p_visual_allow) - targetSdk < Build.VERSION_CODES.Q && visual && deny -> - Triple( - storagePermGroupIcon, - R.string.media_confirm_dialog_title_a_to_p_visual_deny, - R.string.media_confirm_dialog_message_a_to_p_visual_deny) - targetSdk <= Build.VERSION_CODES.S_V2 && aural && allow -> - Triple( - visualPermGroupIcon, - R.string.media_confirm_dialog_title_q_to_s_aural_allow, - R.string.media_confirm_dialog_message_q_to_s_aural_allow) - targetSdk <= Build.VERSION_CODES.S_V2 && aural && deny -> - Triple( - visualPermGroupIcon, - R.string.media_confirm_dialog_title_q_to_s_aural_deny, - R.string.media_confirm_dialog_message_q_to_s_aural_deny) - targetSdk <= Build.VERSION_CODES.S_V2 && visual && allow -> - Triple( - auralPermGroupIcon, - R.string.media_confirm_dialog_title_q_to_s_visual_allow, - R.string.media_confirm_dialog_message_q_to_s_visual_allow) - targetSdk <= Build.VERSION_CODES.S_V2 && visual && deny -> - Triple( - auralPermGroupIcon, - R.string.media_confirm_dialog_title_q_to_s_visual_deny, - R.string.media_confirm_dialog_message_q_to_s_visual_deny) - else -> - Triple(0, 0, 0) - } + val (iconId, titleId, messageId) = + when { + targetSdk < Build.VERSION_CODES.Q && aural && allow -> + Triple( + storagePermGroupIcon, + R.string.media_confirm_dialog_title_a_to_p_aural_allow, + R.string.media_confirm_dialog_message_a_to_p_aural_allow + ) + targetSdk < Build.VERSION_CODES.Q && aural && deny -> + Triple( + storagePermGroupIcon, + R.string.media_confirm_dialog_title_a_to_p_aural_deny, + R.string.media_confirm_dialog_message_a_to_p_aural_deny + ) + targetSdk < Build.VERSION_CODES.Q && visual && allow -> + Triple( + storagePermGroupIcon, + R.string.media_confirm_dialog_title_a_to_p_visual_allow, + R.string.media_confirm_dialog_message_a_to_p_visual_allow + ) + targetSdk < Build.VERSION_CODES.Q && visual && deny -> + Triple( + storagePermGroupIcon, + R.string.media_confirm_dialog_title_a_to_p_visual_deny, + R.string.media_confirm_dialog_message_a_to_p_visual_deny + ) + targetSdk <= Build.VERSION_CODES.S_V2 && aural && allow -> + Triple( + visualPermGroupIcon, + R.string.media_confirm_dialog_title_q_to_s_aural_allow, + R.string.media_confirm_dialog_message_q_to_s_aural_allow + ) + targetSdk <= Build.VERSION_CODES.S_V2 && aural && deny -> + Triple( + visualPermGroupIcon, + R.string.media_confirm_dialog_title_q_to_s_aural_deny, + R.string.media_confirm_dialog_message_q_to_s_aural_deny + ) + targetSdk <= Build.VERSION_CODES.S_V2 && visual && allow -> + Triple( + auralPermGroupIcon, + R.string.media_confirm_dialog_title_q_to_s_visual_allow, + R.string.media_confirm_dialog_message_q_to_s_visual_allow + ) + targetSdk <= Build.VERSION_CODES.S_V2 && visual && deny -> + Triple( + auralPermGroupIcon, + R.string.media_confirm_dialog_title_q_to_s_visual_deny, + R.string.media_confirm_dialog_message_q_to_s_visual_deny + ) + else -> Triple(0, 0, 0) + } if (iconId == 0 || titleId == 0 || messageId == 0) { throw UnsupportedOperationException() @@ -962,9 +1063,8 @@ class AppPermissionViewModel( * * @param changeRequest whether to change foreground, background, or both. * @param buttonPressed button pressed to initiate the change, one of - * AppPermissionFragmentActionReported.button_pressed constants + * AppPermissionFragmentActionReported.button_pressed constants * @param oneTime whether the change should show that the permission was selected as one-time - * */ fun onDenyAnyWay(changeRequest: ChangeRequest, buttonPressed: Int, oneTime: Boolean) { val unexpandedGroup = lightAppPermGroup ?: return @@ -977,16 +1077,17 @@ class AppPermissionViewModel( var newGroup = group val oldGroup = group - if (changeRequest andValue ChangeRequest.REVOKE_BACKGROUND != 0 && - group.hasBackgroundGroup) { + if ( + changeRequest andValue ChangeRequest.REVOKE_BACKGROUND != 0 && + group.hasBackgroundGroup + ) { newGroup = KotlinUtils.revokeBackgroundRuntimePermissions(app, newGroup, false, oneTime) if (wasBackgroundGranted) { SafetyNetLogger.logPermissionToggled(newGroup) } - hasDefaultPermissions = hasDefaultPermissions || - group.background.isGrantedByDefault + hasDefaultPermissions = hasDefaultPermissions || group.background.isGrantedByDefault } if (changeRequest andValue ChangeRequest.REVOKE_FOREGROUND != 0) { @@ -1003,9 +1104,7 @@ class AppPermissionViewModel( hasConfirmedRevoke = true } - fullStorageStateLiveData.value?.let { - FullStoragePermissionAppsLiveData.recalculate() - } + fullStorageStateLiveData.value?.let { FullStoragePermissionAppsLiveData.recalculate() } } } @@ -1017,11 +1116,12 @@ class AppPermissionViewModel( fun setAllFilesAccess(granted: Boolean) { val aom = app.getSystemService(AppOpsManager::class.java)!! val uid = lightAppPermGroup?.packageInfo?.uid ?: return - val mode = if (granted) { - MODE_ALLOWED - } else { - MODE_ERRORED - } + val mode = + if (granted) { + MODE_ALLOWED + } else { + MODE_ERRORED + } val fullStorageGrant = fullStorageStateLiveData.value?.isGranted if (fullStorageGrant != null && fullStorageGrant != granted) { aom.setUidMode(OPSTR_MANAGE_EXTERNAL_STORAGE, uid, mode) @@ -1039,8 +1139,9 @@ class AppPermissionViewModel( } private fun getIndividualPermissionDetailResId(group: LightAppPermGroup): Pair<Int, Int> { - return when (val numRevoked = - group.permissions.filter { !it.value.isGrantedIncludingAppOp }.size) { + return when ( + val numRevoked = group.permissions.filter { !it.value.isGrantedIncludingAppOp }.size + ) { 0 -> R.string.permission_revoked_none to numRevoked group.permissions.size -> R.string.permission_revoked_all to numRevoked else -> R.string.permission_revoked_count to numRevoked @@ -1055,16 +1156,16 @@ class AppPermissionViewModel( hasAdmin: Boolean ): Int { val isForegroundPolicyDenied = group.foreground.isPolicyFixed && !group.foreground.isGranted - val isPolicyFullyFixedWithGrantedOrNoBkg = group.isPolicyFullyFixed && - (group.background.isGranted || !group.hasBackgroundGroup) + val isPolicyFullyFixedWithGrantedOrNoBkg = + group.isPolicyFullyFixed && (group.background.isGranted || !group.hasBackgroundGroup) if (group.foreground.isSystemFixed || group.background.isSystemFixed) { return R.string.permission_summary_enabled_system_fixed } else if (hasAdmin) { // Permission is fully controlled by policy and cannot be switched if (isForegroundPolicyDenied) { - return R.string.disabled_by_admin + return com.android.settingslib.widget.restricted.R.string.disabled_by_admin } else if (isPolicyFullyFixedWithGrantedOrNoBkg) { - return R.string.enabled_by_admin + return com.android.settingslib.widget.restricted.R.string.enabled_by_admin } else if (group.isPolicyFullyFixed) { return R.string.permission_summary_enabled_by_admin_foreground_only } @@ -1110,11 +1211,17 @@ class AppPermissionViewModel( for ((permName, permission) in oldGroup.permissions) { val newPermission = newGroup.permissions[permName] ?: continue - if (permission.isGrantedIncludingAppOp != newPermission.isGrantedIncludingAppOp || - permission.flags != newPermission.flags) { + if ( + permission.isGrantedIncludingAppOp != newPermission.isGrantedIncludingAppOp || + permission.flags != newPermission.flags + ) { logAppPermissionFragmentActionReported(changeId, newPermission, buttonPressed) - PermissionDecisionStorageImpl.recordPermissionDecision(app.applicationContext, - packageName, permGroupName, newPermission.isGrantedIncludingAppOp) + PermissionDecisionStorageImpl.recordPermissionDecision( + app.applicationContext, + packageName, + permGroupName, + newPermission.isGrantedIncludingAppOp + ) PermissionChangeStorageImpl.recordPermissionChange(packageName) } } @@ -1136,13 +1243,28 @@ class AppPermissionViewModel( buttonPressed: Int ) { val uid = KotlinUtils.getPackageUid(app, packageName, user) ?: return - PermissionControllerStatsLog.write(APP_PERMISSION_FRAGMENT_ACTION_REPORTED, sessionId, - changeId, uid, packageName, permission.permInfo.name, - permission.isGrantedIncludingAppOp, permission.flags, buttonPressed) - Log.v(LOG_TAG, "Permission changed via UI with sessionId=$sessionId changeId=" + - "$changeId uid=$uid packageName=$packageName permission=" + permission.permInfo.name + - " isGranted=" + permission.isGrantedIncludingAppOp + " permissionFlags=" + - permission.flags + " buttonPressed=$buttonPressed") + PermissionControllerStatsLog.write( + APP_PERMISSION_FRAGMENT_ACTION_REPORTED, + sessionId, + changeId, + uid, + packageName, + permission.permInfo.name, + permission.isGrantedIncludingAppOp, + permission.flags, + buttonPressed + ) + Log.i( + LOG_TAG, + "Permission changed via UI with sessionId=$sessionId changeId=" + + "$changeId uid=$uid packageName=$packageName permission=" + + permission.permInfo.name + + " isGranted=" + + permission.isGrantedIncludingAppOp + + " permissionFlags=" + + permission.flags + + " buttonPressed=$buttonPressed" + ) } /** Logs information about this AppPermissionGroup and view session */ @@ -1156,19 +1278,20 @@ class AppPermissionViewModel( uid, packageName, permGroupName, - permissionRationaleShown) - Log.v( + permissionRationaleShown + ) + Log.i( LOG_TAG, "AppPermission fragment viewed with sessionId=$sessionId uid=$uid " + "packageName=$packageName permGroupName=$permGroupName " + - "permissionRationaleShown=$permissionRationaleShown") + "permissionRationaleShown=$permissionRationaleShown" + ) } /** - * A partial storage grant happens when: - * An app which doesn't support the photo picker has READ_MEDIA_VISUAL_USER_SELECTED granted, or - * An app which does support the photo picker has READ_MEDIA_VISUAL_USER_SELECTED and/or - * ACCESS_MEDIA_LOCATION granted + * A partial storage grant happens when: An app which doesn't support the photo picker has + * READ_MEDIA_VISUAL_USER_SELECTED granted, or An app which does support the photo picker has + * READ_MEDIA_VISUAL_USER_SELECTED and/or ACCESS_MEDIA_LOCATION granted */ private fun isPartialStorageGrant(group: LightAppPermGroup): Boolean { if (!isPhotoPickerPromptEnabled() || group.permGroupName != READ_MEDIA_VISUAL) { @@ -1177,9 +1300,10 @@ class AppPermissionViewModel( val partialPerms = getPartialStorageGrantPermissionsForGroup(group) - return group.isGranted && group.permissions.values.all { - it.name in partialPerms || (it.name !in partialPerms && !it.isGrantedIncludingAppOp) - } + return group.isGranted && + group.permissions.values.all { + it.name in partialPerms || (it.name !in partialPerms && !it.isGrantedIncludingAppOp) + } } } |