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.permission.data.v35
18 
19 import android.app.Application
20 import android.companion.virtual.VirtualDeviceManager
21 import android.content.pm.PackageManager
22 import android.os.Build
23 import android.os.UserHandle
24 import android.permission.PermissionManager
25 import android.permission.PermissionManager.PermissionState
26 import androidx.annotation.RequiresApi
27 import com.android.modules.utils.build.SdkLevel
28 import com.android.permissioncontroller.PermissionControllerApplication
29 import com.android.permissioncontroller.permission.data.DataRepositoryForPackage
30 import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
31 import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo
32 import com.android.permissioncontroller.permission.utils.PermissionMapping
33 import kotlinx.coroutines.Job
34 
35 /**
36  * LiveData that loads all the external device permissions per package. The permissions will be
37  * loaded only if the package has requested the permission. This live data produces the list of
38  * {@link ExternalDeviceGrantInfo} that has group name to which permission belongs to, grant state
39  * and persistentDeviceId
40  *
41  * @param app The current Application
42  * @param packageName The name of the package
43  * @param user The user for whom the packageInfo will be defined
44  */
45 class PackagePermissionsExternalDeviceLiveData
46 private constructor(private val app: Application, val packageName: String, val user: UserHandle) :
47     SmartAsyncMediatorLiveData<
48         List<PackagePermissionsExternalDeviceLiveData.ExternalDeviceGrantInfo>
49     >() {
50     private val permissionManager = app.getSystemService(PermissionManager::class.java)!!
51 
52     data class ExternalDeviceGrantInfo(
53         val groupName: String,
54         val permGrantState: AppPermGroupUiInfo.PermGrantState,
55         val persistentDeviceId: String
56     )
57 
58     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
59     override suspend fun loadDataAndPostValue(job: Job) {
60         if (!SdkLevel.isAtLeastV()) {
61             return
62         }
63         val virtualDeviceManager = app.getSystemService(VirtualDeviceManager::class.java) ?: return
64         val externalDeviceGrantInfoList =
65             virtualDeviceManager.allPersistentDeviceIds
66                 .map { getVirtualDeviceGrantInfoList(it) }
67                 .toList()
68                 .flatten()
69         postValue(externalDeviceGrantInfoList)
70     }
71 
72     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
73     private fun getVirtualDeviceGrantInfoList(
74         persistentDeviceId: String
75     ): List<ExternalDeviceGrantInfo> {
76         val permissionState =
77             permissionManager.getAllPermissionStates(packageName, persistentDeviceId)
78         return permissionState.mapNotNull { (permissionName, permissionState) ->
79             PermissionMapping.getGroupOfPlatformPermission(permissionName)?.let { groupName ->
80                 val grantState = getGrantState(permissionState)
81                 ExternalDeviceGrantInfo(groupName, grantState, persistentDeviceId)
82             }
83         }
84     }
85 
86     /**
87      * This method returns the GrantState for currently supported virtual device permissions
88      * (Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO).
89      *
90      * TODO: b/328841671 (Unite this with PermGroupUiInfoLiveData#getGrantedIncludingBackground)
91      */
92     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
93     private fun getGrantState(permissionState: PermissionState): AppPermGroupUiInfo.PermGrantState =
94         if (permissionState.isGranted) {
95             AppPermGroupUiInfo.PermGrantState.PERMS_ALLOWED_FOREGROUND_ONLY
96         } else if (permissionState.flags and PackageManager.FLAG_PERMISSION_ONE_TIME != 0) {
97             AppPermGroupUiInfo.PermGrantState.PERMS_ASK
98         } else {
99             AppPermGroupUiInfo.PermGrantState.PERMS_DENIED
100         }
101 
102     companion object :
103         DataRepositoryForPackage<
104             Pair<String, UserHandle>, PackagePermissionsExternalDeviceLiveData
105         >() {
106         override fun newValue(
107             key: Pair<String, UserHandle>
108         ): PackagePermissionsExternalDeviceLiveData {
109             return PackagePermissionsExternalDeviceLiveData(
110                 PermissionControllerApplication.get(),
111                 key.first,
112                 key.second
113             )
114         }
115     }
116 }
117