• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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