1 /*
2  * 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.content.pm.PackageManager.GET_PERMISSIONS
21 import android.content.pm.PackageManager.MATCH_ALL
22 import android.os.UserHandle
23 import com.android.permissioncontroller.PermissionControllerApplication
24 import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
25 import kotlinx.coroutines.Job
26 
27 /**
28  * A LiveData which tracks all of the packageinfos installed for a given user.
29  *
30  * @param app The current application
31  * @param user The user whose packages are desired
32  */
33 class UserPackageInfosLiveData private constructor(
34     private val app: Application,
35     private val user: UserHandle
36 ) : SmartAsyncMediatorLiveData<@kotlin.jvm.JvmSuppressWildcards List<LightPackageInfo>>(),
37     PackageBroadcastReceiver.PackageBroadcastListener,
38     PermissionListenerMultiplexer.PermissionChangeCallback {
39 
40     /**
41      * Whether or not the permissions in this liveData are out of date
42      */
43     var permChangeStale = false
44 
45     override fun onPackageUpdate(packageName: String) {
46         updateAsync()
47     }
48 
49     // TODO ntmyren: replace with correctly updating
50     override fun onPermissionChange() {
51         permChangeStale = true
52         for (packageInfo in value ?: emptyList()) {
53             PermissionListenerMultiplexer.removeCallback(packageInfo.uid, this)
54         }
55     }
56 
57     override fun setValue(newValue: List<LightPackageInfo>?) {
58         if (newValue != value) {
59             for (packageInfo in value ?: emptyList()) {
60                 PermissionListenerMultiplexer.removeCallback(packageInfo.uid, this)
61             }
62             for (packageInfo in newValue ?: emptyList()) {
63                 PermissionListenerMultiplexer.addCallback(packageInfo.uid, this)
64             }
65         }
66         super.setValue(newValue)
67         permChangeStale = false
68     }
69 
70     /**
71      * Get all of the packages in the system, organized by user.
72      */
73     override suspend fun loadDataAndPostValue(job: Job) {
74         if (job.isCancelled) {
75             return
76         }
77         val packageInfos = app.applicationContext.packageManager
78             .getInstalledPackagesAsUser(GET_PERMISSIONS or MATCH_ALL, user.identifier)
79 
80         postValue(packageInfos.map { packageInfo -> LightPackageInfo(packageInfo) })
81     }
82 
83     override fun onActive() {
84         super.onActive()
85 
86         PackageBroadcastReceiver.addAllCallback(this)
87 
88         for (packageInfo in value ?: emptyList()) {
89             PermissionListenerMultiplexer.addCallback(packageInfo.uid, this)
90         }
91     }
92 
93     override fun onInactive() {
94         super.onInactive()
95 
96         for (packageInfo in value ?: emptyList()) {
97             PermissionListenerMultiplexer.removeCallback(packageInfo.uid, this)
98         }
99 
100         PackageBroadcastReceiver.removeAllCallback(this)
101     }
102 
103     /**
104      * Repository for UserPackageInfosLiveDatas.
105      * <p> Key value is a UserHandle, value is its corresponding LiveData.
106      */
107     companion object : DataRepository<UserHandle, UserPackageInfosLiveData>() {
108         override fun newValue(key: UserHandle): UserPackageInfosLiveData {
109             return UserPackageInfosLiveData(PermissionControllerApplication.get(), key)
110         }
111     }
112 }