1 /*
<lambda>null2  * Copyright (C) 2019 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
18 
19 import android.app.Application
20 import android.os.UserHandle
21 import com.android.permissioncontroller.PermissionControllerApplication
22 import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo
23 import com.android.permissioncontroller.permission.utils.PermissionMapping
24 
25 /**
26  * LiveData for the UI info for all packages in a single permission group. Tracks which packages
27  * have permissions in the given group, which should be shown on the UI, and which are granted or
28  * not.
29  *
30  * @param app The current application
31  * @param permGroupName The name of the permission group this LiveData represents
32  */
33 class SinglePermGroupPackagesUiInfoLiveData
34 private constructor(private val app: Application, private val permGroupName: String) :
35     SmartUpdateMediatorLiveData<Map<Pair<String, UserHandle>, AppPermGroupUiInfo>>() {
36 
37     private val permGroupLiveData = PermGroupLiveData[permGroupName]
38     private val isCustomGroup =
39         !PermissionMapping.getPlatformPermissionGroups().contains(permGroupName)
40     private val permGroupPackagesLiveData =
41         PermGroupsPackagesLiveData.get(customGroups = isCustomGroup)
42 
43     /** Map<Pair<package name, UserHandle>, UI data LiveData> */
44     private val appPermGroupLiveDatas =
45         mutableMapOf<Pair<String, UserHandle>, AppPermGroupUiInfoLiveData>()
46 
47     /** Map<Pair<packageName, userHandle>, UI data>. */
48     private val shownPackages = mutableMapOf<Pair<String, UserHandle>, AppPermGroupUiInfo>()
49 
50     init {
51         addSource(permGroupLiveData) { newPermGroup ->
52             if (newPermGroup == null) {
53                 invalidateSingle(permGroupName)
54                 value = null
55             }
56         }
57 
58         addSource(permGroupPackagesLiveData) { update() }
59     }
60 
61     override fun onUpdate() {
62         val thisPermGroupPackages = permGroupPackagesLiveData.value?.get(permGroupName)
63         if (thisPermGroupPackages != null) {
64             addAndRemoveAppPermGroupLiveDatas(thisPermGroupPackages.toList())
65 
66             if (thisPermGroupPackages.isEmpty()) {
67                 permGroupLiveData.value?.groupInfo?.let { value = emptyMap() }
68             }
69         }
70     }
71 
72     private fun addAndRemoveAppPermGroupLiveDatas(pkgs: List<Pair<String, UserHandle>>) {
73         val getLiveData = { key: Pair<String, UserHandle> ->
74             AppPermGroupUiInfoLiveData[key.first, permGroupName, key.second]
75         }
76 
77         val (_, removed) =
78             setSourcesToDifference(pkgs, appPermGroupLiveDatas, getLiveData) { key ->
79                 val appPermGroupUiInfoLiveData = appPermGroupLiveDatas[key]
80                 val appPermGroupUiInfo = appPermGroupUiInfoLiveData?.value
81                 shownPackages.remove(key)
82 
83                 if (appPermGroupUiInfo == null) {
84                     if (
85                         appPermGroupUiInfoLiveData != null &&
86                             appPermGroupUiInfoLiveData.isInitialized
87                     ) {
88                         removeSource(appPermGroupUiInfoLiveData)
89                         appPermGroupLiveDatas.remove(key)
90                     }
91                 } else {
92                     shownPackages[key] = appPermGroupUiInfo
93                 }
94 
95                 if (appPermGroupLiveDatas.all { entry -> entry.value.isInitialized }) {
96                     permGroupLiveData.value?.groupInfo?.let { value = shownPackages.toMap() }
97                 }
98             }
99 
100         for (removedKey in removed) {
101             shownPackages.remove(removedKey)
102         }
103 
104         if (appPermGroupLiveDatas.all { entry -> entry.value.isInitialized }) {
105             permGroupLiveData.value?.groupInfo?.let { value = shownPackages.toMap() }
106         }
107     }
108 
109     /**
110      * Repository for SinglePermGroupPackagesUiInfoLiveData objects.
111      *
112      * <p> Key value is a string permission group name, value is its corresponding LiveData.
113      */
114     companion object : DataRepository<String, SinglePermGroupPackagesUiInfoLiveData>() {
115         override fun newValue(key: String): SinglePermGroupPackagesUiInfoLiveData {
116             return SinglePermGroupPackagesUiInfoLiveData(PermissionControllerApplication.get(), key)
117         }
118     }
119 }
120