1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.permissioncontroller.permission.data.repository.v31 18 19 import android.app.Application 20 import android.content.Context 21 import android.content.pm.PackageItemInfo 22 import android.content.pm.PackageManager 23 import android.os.UserHandle 24 import android.text.TextUtils 25 import com.android.modules.utils.build.SdkLevel 26 import com.android.permissioncontroller.permission.utils.PermissionMapping 27 import kotlin.concurrent.Volatile 28 import kotlinx.coroutines.CoroutineDispatcher 29 import kotlinx.coroutines.Dispatchers 30 import kotlinx.coroutines.withContext 31 32 /** 33 * This repository encapsulates permission data (i.e. permission or permission group definitions, 34 * package permission states etc.) exposed by [android.permission.PermissionManager] and 35 * [PackageManager]. 36 */ 37 interface PermissionRepository { 38 /** 39 * Gets the flags associated with a permission. 40 * 41 * @see PackageManager.getPermissionFlags 42 */ getPermissionFlagsnull43 suspend fun getPermissionFlags( 44 permissionName: String, 45 packageName: String, 46 user: UserHandle 47 ): Int 48 49 /** 50 * Gets a permission group label for a given permission group. 51 * 52 * @see PackageManager.getPermissionGroupInfo 53 * @see PackageItemInfo.loadSafeLabel 54 */ 55 suspend fun getPermissionGroupLabel(context: Context, groupName: String): CharSequence 56 57 /** Gets a list of permission group to be shown in the privacy dashboard. */ 58 fun getPermissionGroupsForPrivacyDashboard(): List<String> 59 60 companion object { 61 @Volatile private var instance: PermissionRepository? = null 62 63 fun getInstance(application: Application): PermissionRepository = 64 instance 65 ?: synchronized(this) { 66 PermissionRepositoryImpl(application).also { instance = it } 67 } 68 } 69 } 70 71 class PermissionRepositoryImpl( 72 application: Application, 73 private val dispatcher: CoroutineDispatcher = Dispatchers.Default, 74 ) : PermissionRepository { 75 private val packageManager = application.packageManager 76 getPermissionFlagsnull77 override suspend fun getPermissionFlags( 78 permissionName: String, 79 packageName: String, 80 user: UserHandle 81 ): Int = 82 withContext(dispatcher) { 83 packageManager.getPermissionFlags(permissionName, packageName, user) 84 } 85 86 /** 87 * Gets a permission group's label from the system. 88 * 89 * @param context The context from which to get the label 90 * @param groupName The name of the permission group whose label we want 91 * @return The permission group's label, or the group name, if the group is invalid 92 */ getPermissionGroupLabelnull93 override suspend fun getPermissionGroupLabel( 94 context: Context, 95 groupName: String 96 ): CharSequence = 97 withContext(dispatcher) { 98 val groupInfo = getPermissionGroupInfo(groupName, context) 99 groupInfo?.loadSafeLabel( 100 context.packageManager, 101 0f, 102 TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM 103 ) 104 ?: groupName 105 } 106 107 /** 108 * Get the [PackageItemInfo] for the given permission group. 109 * 110 * @param groupName the group 111 * @param context the `Context` to retrieve `PackageManager` 112 * @return The info of permission group or null if the group does not have runtime permissions. 113 */ getPermissionGroupInfonull114 private fun getPermissionGroupInfo(groupName: String, context: Context): PackageItemInfo? { 115 return try { 116 context.packageManager.getPermissionGroupInfo(groupName, 0) 117 } catch (e: PackageManager.NameNotFoundException) { 118 null 119 } 120 ?: try { 121 context.packageManager.getPermissionInfo(groupName, 0) 122 } catch (e: PackageManager.NameNotFoundException) { 123 null 124 } 125 } 126 getPermissionGroupsForPrivacyDashboardnull127 override fun getPermissionGroupsForPrivacyDashboard(): List<String> { 128 return if (SdkLevel.isAtLeastT()) { 129 PermissionMapping.getPlatformPermissionGroups().filter { 130 it != android.Manifest.permission_group.NOTIFICATIONS 131 } 132 } else { 133 PermissionMapping.getPlatformPermissionGroups() 134 } 135 } 136 } 137