Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e4cd34e authored by Nate Myren's avatar Nate Myren Committed by Android (Google) Code Review
Browse files

Merge "Final AppPermissionFragment refactor"

parents 850cd699 7dbd950c
Loading
Loading
Loading
Loading
+52 −1
Original line number Diff line number Diff line
@@ -17,10 +17,14 @@
package com.android.permissioncontroller.permission.data

import android.app.Application
import android.content.pm.PackageManager
import android.content.pm.PermissionInfo
import android.os.Build
import android.os.UserHandle
import android.permission.PermissionManager
import android.util.Log
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission
import com.android.permissioncontroller.permission.utils.LocationUtils
import com.android.permissioncontroller.permission.utils.SoftRestrictedPermissionPolicy
@@ -42,6 +46,8 @@ class AppPermGroupLiveData(
    private val user: UserHandle
) : SmartUpdateMediatorLiveData<LightAppPermGroup>() {

    val LOG_TAG = this::class.java.simpleName

    private val permStateLiveData = PermStateRepository.getPermStateLiveData(app, packageName,
        permGroupName, user)
    private val permGroupLiveData = PermGroupRepository.getPermGroupLiveData(app, permGroupName)
@@ -125,7 +131,52 @@ class AppPermGroupLiveData(
            specialLocationGrant = LocationUtils.isExtraLocationControllerPackageEnabled(
                userContext)
        }
        val hasInstallToRuntimeSplit = hasInstallToRuntimeSplit(packageInfo, permissionMap)
        value = LightAppPermGroup(packageInfo, permGroup.groupInfo, permissionMap,
            specialLocationGrant)
            hasInstallToRuntimeSplit, specialLocationGrant)
    }

    /**
     * Check if permission group contains a runtime permission that split from an installed
     * permission and the split happened in an Android version higher than app's targetSdk.
     *
     * @return `true` if there is such permission, `false` otherwise
     */
    private fun hasInstallToRuntimeSplit(
        packageInfo: LightPackageInfo,
        permissionMap: Map<String, LightPermission>
    ): Boolean {
        val permissionManager = app.getSystemService(PermissionManager::class.java) ?: return false

        for (spi in permissionManager.splitPermissions) {
            val splitPerm = spi.splitPermission

            val pi = try {
                app.packageManager.getPermissionInfo(splitPerm, 0)
            } catch (e: PackageManager.NameNotFoundException) {
                Log.w(LOG_TAG, "No such permission: $splitPerm", e)
                continue
            }

            // Skip if split permission is not "install" permission.
            if (pi.protection != PermissionInfo.PROTECTION_NORMAL) {
                continue
            }

            val newPerms = spi.newPermissions
            for (permName in newPerms) {
                val newPerm = permissionMap[permName]?.permInfo ?: continue

                // Skip if new permission is not "runtime" permission.
                if (newPerm.protection != PermissionInfo.PROTECTION_DANGEROUS) {
                    continue
                }

                if (packageInfo.targetSdkVersion < spi.targetSdk) {
                    return true
                }
            }
        }
        return false
    }
}
 No newline at end of file
+23 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.permissioncontroller.permission.model.livedatatypes

import android.os.Build
import android.os.UserHandle

/**
@@ -25,6 +26,8 @@ import android.os.UserHandle
 * @param packageInfo Information about the package
 * @param permGroupInfo Information about the permission group
 * @param permissions The permissions in the permission group that the package requests
 * @param hasInstallToRuntimeSplit If this group contains a permission that was previously an
 * install permission, but is currently a runtime permission
 * @param specialLocationGrant If this package is the location provider, or the extra location
 * package, then the grant state of the group is not determined by the grant state of individual
 * permissions, but by other system properties
@@ -33,10 +36,11 @@ data class LightAppPermGroup(
    val packageInfo: LightPackageInfo,
    val permGroupInfo: LightPermGroupInfo,
    val permissions: Map<String, LightPermission>,
    val hasInstallToRuntimeSplit: Boolean,
    val specialLocationGrant: Boolean?
) {
    constructor(pI: LightPackageInfo, pGI: LightPermGroupInfo, perms: Map<String, LightPermission>):
        this(pI, pGI, perms, null)
        this(pI, pGI, perms, false, null)
    /**
     * The current userHandle of this AppPermGroup.
     */
@@ -48,6 +52,14 @@ data class LightAppPermGroup(
     */
    val backgroundPermNames = permissions.mapNotNull { it.value.backgroundPermission }

    /**
     * The names of all foreground permissions in the permission group which are requested by the
     * package.
     */
    val foregroundPermNames = permissions.mapNotNull {
        if (!backgroundPermNames.contains(it.key)) it.key else null
    }

    /**
     * Whether or not this App Permission Group has a permission which has a background mode
     */
@@ -106,6 +118,16 @@ data class LightAppPermGroup(
        backgroundPermNames.contains(it.key) && it.value.isGrantedIncludingAppOp
    }

    val isForegroundGrantedByDefault = permissions.any { !backgroundPermNames.contains(it.key) &&
        it.value.isGrantedByDefault
    }

    val isBackgroundGrantedByDefault = permissions.any { backgroundPermNames.contains(it.key) &&
        it.value.isGrantedByDefault
    }

    val supportsRuntimePerms = packageInfo.targetSdkVersion >= Build.VERSION_CODES.M

    /**
     * Whether this App Permission Group's permissions are fixed by the user
     */
+2 −0
Original line number Diff line number Diff line
@@ -64,4 +64,6 @@ data class LightPermission(
    /** Whether this permission is a runtime only permission */
    val isRuntimeOnly =
        permInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY != 0
    /** Whether this permission is granted by default */
    val isGrantedByDefault = flags and PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT != 0
}
 No newline at end of file
+67 −89
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISS
import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.data.AppPermGroupLiveData
import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
import com.android.permissioncontroller.permission.model.AppPermissionGroup
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.LocationUtils
@@ -101,7 +100,6 @@ class AppPermissionViewModel(
    }

    private var hasConfirmedRevoke = false
    private var appPermissionGroup: AppPermissionGroup? = null
    private var lightAppPermGroup: LightAppPermGroup? = null

    /**
@@ -147,13 +145,6 @@ class AppPermissionViewModel(
        }

        override fun update() {
            appPermissionGroup = AppPermissionGroup.create(app, packageName, permGroupName, user,
                false)
            if (appPermissionGroup == null) {
                value = null
                return
            }

            val group = appPermGroupLiveData.value ?: return

            val admin = RestrictedLockUtils.getProfileOrDeviceOwner(app, user)
@@ -237,8 +228,6 @@ class AppPermissionViewModel(

        override fun onActive() {
            super.onActive()
            appPermissionGroup = AppPermissionGroup.create(app, packageName, permGroupName, user,
                false)
        }
    }

@@ -365,12 +354,11 @@ class AppPermissionViewModel(
        changeTarget: ChangeTarget
    ) {
        val context = fragment.context ?: return
        val group = appPermissionGroup ?: return
        val group = lightAppPermGroup ?: return
        val wasForegroundGranted = group.isForegroundGranted
        val wasBackgroundGranted = group.isBackgroundGranted

        group.isOneTime = false

        if (LocationUtils.isLocationGroupAndProvider(context, group.name,
                group.app.packageName)) {
        if (LocationUtils.isLocationGroupAndProvider(context, permGroupName, packageName)) {
            val packageLabel = KotlinUtils.getPackageLabel(app, packageName, user)
            LocationUtils.showLocationDialog(context, packageLabel)
        }
@@ -381,20 +369,17 @@ class AppPermissionViewModel(
        if (requestGrant) {
            val stateBefore = createPermissionSnapshot()!!
            if (shouldChangeForeground) {
                val runtimePermissionsGranted = group.areRuntimePermissionsGranted()
                group.grantRuntimePermissions(userFixed)
                val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)

                if (!runtimePermissionsGranted) {
                    SafetyNetLogger.logPermissionToggled(group)
                if (!wasForegroundGranted) {
                    SafetyNetLogger.logPermissionToggled(newGroup)
                }
            }
            if (shouldChangeBackground && group.backgroundPermissions != null) {
                val runtimePermissionsGranted =
                        group.backgroundPermissions.areRuntimePermissionsGranted()
                group.backgroundPermissions.grantRuntimePermissions(userFixed)
            if (shouldChangeBackground && group.hasBackgroundPerms) {
                val newGroup = KotlinUtils.grantBackgroundRuntimePermissions(app, group)

                if (!runtimePermissionsGranted) {
                    SafetyNetLogger.logPermissionToggled(group.backgroundPermissions)
                if (!wasBackgroundGranted) {
                    SafetyNetLogger.logPermissionToggled(newGroup, true)
                }
            }
            logPermissionChanges(stateBefore)
@@ -402,24 +387,21 @@ class AppPermissionViewModel(
            var showDefaultDenyDialog = false
            var showGrantedByDefaultWarning = false

            if (shouldChangeForeground && group.areRuntimePermissionsGranted()) {
                showDefaultDenyDialog = (group.hasGrantedByDefaultPermission() ||
                    !group.doesSupportRuntimePermissions() ||
                    group.hasInstallToRuntimeSplit())
            if (shouldChangeForeground && wasForegroundGranted) {
                showDefaultDenyDialog = (group.isForegroundGrantedByDefault ||
                    !group.supportsRuntimePerms ||
                    group.hasInstallToRuntimeSplit)
                showGrantedByDefaultWarning = showGrantedByDefaultWarning ||
                    group.hasGrantedByDefaultPermission()
                    group.isForegroundGrantedByDefault
            }

            if (shouldChangeBackground &&
                group.backgroundPermissions != null &&
                group.backgroundPermissions.areRuntimePermissionsGranted()) {
                val bgGroup = group.backgroundPermissions
            if (shouldChangeBackground && wasBackgroundGranted) {
                showDefaultDenyDialog = showDefaultDenyDialog ||
                    bgGroup.hasGrantedByDefaultPermission() ||
                    !bgGroup.doesSupportRuntimePermissions() ||
                    bgGroup.hasInstallToRuntimeSplit()
                    group.isBackgroundGrantedByDefault ||
                    !group.supportsRuntimePerms ||
                    group.hasInstallToRuntimeSplit
                showGrantedByDefaultWarning = showGrantedByDefaultWarning ||
                    bgGroup.hasGrantedByDefaultPermission()
                    group.isBackgroundGrantedByDefault
            }

            if (showDefaultDenyDialog && !hasConfirmedRevoke && showGrantedByDefaultWarning) {
@@ -432,28 +414,25 @@ class AppPermissionViewModel(
            } else {
                val stateBefore = createPermissionSnapshot()!!
                if (shouldChangeForeground &&
                        group.areRuntimePermissionsGranted()) {
                    group.revokeRuntimePermissions(userFixed)

                    SafetyNetLogger.logPermissionToggled(group)
                }
                if (shouldChangeBackground &&
                        group.backgroundPermissions != null &&
                        group.backgroundPermissions.areRuntimePermissionsGranted()) {
                    group.backgroundPermissions.revokeRuntimePermissions(userFixed)
                    (wasForegroundGranted || userFixed != group.isUserFixed)) {
                    val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group,
                        userFixed)

                    SafetyNetLogger.logPermissionToggled(group.backgroundPermissions)
                    // only log if we have actually denied permissions, not if we switch from
                    // "ask every time" to denied
                    if (wasForegroundGranted) {
                        SafetyNetLogger.logPermissionToggled(newGroup)
                    }
                if (userFixed && !group.isUserFixed) {
                    group.revokeRuntimePermissions(true)
                    if (group.backgroundPermissions != null) {
                        group.backgroundPermissions.revokeRuntimePermissions(true)
                }
                }
                if (!userFixed && group.isUserFixed) {
                    group.revokeRuntimePermissions(false)
                    if (group.backgroundPermissions != null) {
                        group.backgroundPermissions.revokeRuntimePermissions(false)
                if (shouldChangeBackground && group.hasBackgroundPerms &&
                    (wasBackgroundGranted || userFixed != group.isUserFixed)) {
                    val newGroup = KotlinUtils.revokeBackgroundRuntimePermissions(app,
                        group, userFixed)

                    // only log if we have actually denied permissions, not if we switch from
                    // "ask every time" to denied
                    if (wasBackgroundGranted) {
                        SafetyNetLogger.logPermissionToggled(newGroup, true)
                    }
                }
                logPermissionChanges(stateBefore)
@@ -461,51 +440,41 @@ class AppPermissionViewModel(
        }
    }

    /**
     * Show the All App Permissions screen with the proper filter group, package name, and user.
     *
     * @param fragment The current fragment we wish to transition from
     */
    fun showAllPermissions(fragment: AppPermissionFragment) {
        val args = AllAppPermissionsFragment.createArgs(packageName, permGroupName, user)
        fragment.findNavController().navigate(R.id.app_to_all_perms, args)
    }

    /**
     * Once the user has confirmed that he/she wants to revoke a permission that was granted by
     * default, actually revoke the permissions.
     *
     * @param changeTarget whether to change foreground, background, or both.
     * @param userFixed whether the user has stated they do not wish to be prompted about the
     * permission any more.
     *
     */
    fun onDenyAnyWay(changeTarget: ChangeTarget, userFixed: Boolean) {
        val group = appPermissionGroup ?: return
        val group = lightAppPermGroup ?: return
        val wasForegroundGranted = group.isForegroundGranted
        val wasBackgroundGranted = group.isBackgroundGranted
        var hasDefaultPermissions = false
        val stateBefore = createPermissionSnapshot()
        if (changeTarget andValue ChangeTarget.CHANGE_FOREGROUND != 0) {
            val runtimePermissionsGranted = group.areRuntimePermissionsGranted()
            group.revokeRuntimePermissions(userFixed)

            if (runtimePermissionsGranted) {
                SafetyNetLogger.logPermissionToggled(group)
        if (changeTarget andValue ChangeTarget.CHANGE_FOREGROUND != 0) {
            val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group, userFixed)
            if (wasForegroundGranted) {
                SafetyNetLogger.logPermissionToggled(newGroup)
            }
            hasDefaultPermissions = group.hasGrantedByDefaultPermission()
            hasDefaultPermissions = group.isForegroundGrantedByDefault
        }
        if (changeTarget andValue ChangeTarget.CHANGE_BACKGROUND != 0 &&
            group.backgroundPermissions != null) {
            val runtimePermissionsGranted =
                    group.backgroundPermissions.areRuntimePermissionsGranted()
            group.backgroundPermissions.revokeRuntimePermissions(userFixed)
        if (changeTarget andValue ChangeTarget.CHANGE_BACKGROUND != 0 && group.hasBackgroundPerms) {
            val newGroup = KotlinUtils.revokeBackgroundRuntimePermissions(app, group, userFixed)

            if (runtimePermissionsGranted) {
                SafetyNetLogger.logPermissionToggled(group.backgroundPermissions)
            if (wasBackgroundGranted) {
                SafetyNetLogger.logPermissionToggled(newGroup)
            }
            hasDefaultPermissions = hasDefaultPermissions ||
                group.backgroundPermissions.hasGrantedByDefaultPermission()
                group.isBackgroundGrantedByDefault
        }
        logPermissionChanges(stateBefore!!)

        if (hasDefaultPermissions || !group.doesSupportRuntimePermissions()) {
        if (hasDefaultPermissions || !group.supportsRuntimePerms) {
            hasConfirmedRevoke = true
        }
    }
@@ -521,6 +490,16 @@ class AppPermissionViewModel(
        return permissionSnapshot
    }

    /**
     * Show the All App Permissions screen with the proper filter group, package name, and user.
     *
     * @param fragment The current fragment we wish to transition from
     */
    fun showAllPermissions(fragment: AppPermissionFragment) {
        val args = AllAppPermissionsFragment.createArgs(packageName, permGroupName, user)
        fragment.findNavController().navigate(R.id.app_to_all_perms, args)
    }

    private fun getIndividualPermissionDetailResId(group: LightAppPermGroup): Pair<Int, Int> {
        return when (val numRevoked =
            group.permissions.filter { !it.value.isGrantedIncludingAppOp }.size) {
@@ -585,13 +564,12 @@ class AppPermissionViewModel(
    data class PermissionState(val permissionName: String, val permissionGranted: Boolean)

    private fun logPermissionChanges(previousPermissionSnapshot: List<PermissionState>) {
        val group = appPermissionGroup ?: return
        val lightGroup = lightAppPermGroup ?: return

        val changeId = Random().nextLong()

        for ((permissionName, wasGranted) in previousPermissionSnapshot) {
            val permission = group.getPermission(permissionName)
                ?: group.backgroundPermissions?.getPermission(permissionName)
            val permission = lightGroup.permissions[permissionName]
                ?: continue

            val isGranted = permission.isGrantedIncludingAppOp
+109 −50

File changed.

Preview size limit exceeded, changes collapsed.

Loading