1 /* <lambda>null2 * 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.pm.data.repository.v31 18 19 import android.app.Application 20 import android.content.pm.PackageManager 21 import android.content.res.Resources 22 import android.graphics.drawable.Drawable 23 import android.os.UserHandle 24 import android.util.Log 25 import com.android.modules.utils.build.SdkLevel 26 import com.android.permissioncontroller.permission.utils.Utils 27 import com.android.permissioncontroller.pm.data.model.v31.PackageAttributionModel 28 import com.android.permissioncontroller.pm.data.model.v31.PackageInfoModel 29 import kotlin.concurrent.Volatile 30 import kotlinx.coroutines.CoroutineDispatcher 31 import kotlinx.coroutines.Dispatchers 32 import kotlinx.coroutines.withContext 33 34 /** 35 * Repository to access package info data exposed by [PackageManager]. Domain and view layer 36 * shouldn't access [PackageManager] directly, instead they should use the repository. 37 */ 38 interface PackageRepository { 39 /** 40 * Returns a package label for the given [packageName] and [user] Returns [packageName] if the 41 * package is not found. 42 */ 43 fun getPackageLabel(packageName: String, user: UserHandle): String 44 45 /** 46 * Returns a package's badged icon for the given [packageName] and [user] Returns null if the 47 * package is not found. 48 */ 49 fun getBadgedPackageIcon(packageName: String, user: UserHandle): Drawable? 50 51 /** 52 * Returns a [PackageInfoModel] for the given [packageName] and [user] Returns null if the 53 * package is not found. 54 */ 55 suspend fun getPackageInfo( 56 packageName: String, 57 user: UserHandle, 58 flags: Int = PackageManager.GET_PERMISSIONS 59 ): PackageInfoModel? 60 61 /** 62 * Returns a [PackageAttributionModel] for the given [packageName] and [user] Returns null if 63 * the package is not found. 64 */ 65 suspend fun getPackageAttributionInfo( 66 packageName: String, 67 user: UserHandle, 68 ): PackageAttributionModel? 69 70 companion object { 71 @Volatile private var instance: PackageRepository? = null 72 73 fun getInstance(app: Application): PackageRepository = 74 instance ?: synchronized(this) { PackageRepositoryImpl(app).also { instance = it } } 75 } 76 } 77 78 class PackageRepositoryImpl( 79 private val app: Application, 80 private val dispatcher: CoroutineDispatcher = Dispatchers.Default, 81 ) : PackageRepository { getPackageLabelnull82 override fun getPackageLabel(packageName: String, user: UserHandle): String { 83 return try { 84 val userContext = Utils.getUserContext(app, user) 85 val appInfo = userContext.packageManager.getApplicationInfo(packageName, 0) 86 Utils.getFullAppLabel(appInfo, app) 87 } catch (e: PackageManager.NameNotFoundException) { 88 packageName 89 } 90 } 91 getBadgedPackageIconnull92 override fun getBadgedPackageIcon(packageName: String, user: UserHandle): Drawable? { 93 return try { 94 val userContext = Utils.getUserContext(app, user) 95 val appInfo = userContext.packageManager.getApplicationInfo(packageName, 0) 96 Utils.getBadgedIcon(app, appInfo) 97 } catch (e: PackageManager.NameNotFoundException) { 98 null 99 } 100 } 101 getPackageInfonull102 override suspend fun getPackageInfo( 103 packageName: String, 104 user: UserHandle, 105 flags: Int 106 ): PackageInfoModel? = 107 withContext(dispatcher) { 108 try { 109 val packageInfo = 110 Utils.getUserContext(app, user) 111 .packageManager 112 .getPackageInfo(packageName, flags) 113 PackageInfoModel(packageInfo) 114 } catch (e: PackageManager.NameNotFoundException) { 115 Log.w(LOG_TAG, "package $packageName not found for user ${user.identifier}") 116 null 117 } 118 } 119 120 @Suppress("DEPRECATION") getPackageAttributionInfonull121 override suspend fun getPackageAttributionInfo( 122 packageName: String, 123 user: UserHandle, 124 ): PackageAttributionModel? = 125 withContext(dispatcher) { 126 try { 127 val packageInfo = 128 Utils.getUserContext(app, user) 129 .packageManager 130 .getPackageInfo(packageName, PackageManager.GET_ATTRIBUTIONS) 131 val attributionUserVisible = 132 packageInfo.applicationInfo?.areAttributionsUserVisible() ?: false 133 if (attributionUserVisible && SdkLevel.isAtLeastS()) { 134 val pkgContext = app.createPackageContext(packageName, 0) 135 val attributionTagToLabelRes = 136 packageInfo.attributions?.associate { it.tag to it.label } 137 val labelResToLabelStringMap = 138 attributionTagToLabelRes 139 ?.mapNotNull { entry -> 140 val labelString = 141 try { 142 pkgContext.getString(entry.value) 143 } catch (e: Resources.NotFoundException) { 144 null 145 } 146 if (labelString != null) entry.value to labelString else null 147 } 148 ?.toMap() 149 PackageAttributionModel( 150 packageName, 151 true, 152 attributionTagToLabelRes, 153 labelResToLabelStringMap 154 ) 155 } else { 156 PackageAttributionModel(packageName) 157 } 158 } catch (e: PackageManager.NameNotFoundException) { 159 Log.w(LOG_TAG, "package $packageName not found for user ${user.identifier}") 160 null 161 } 162 } 163 164 companion object { 165 private const val LOG_TAG = "PackageRepository" 166 } 167 } 168