1 /*
2  * Copyright (C) 2020 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
21 import android.util.Log
22 import com.android.permissioncontroller.PermissionControllerApplication
23 import com.android.permissioncontroller.permission.model.livedatatypes.LightPermInfo
24 import com.android.permissioncontroller.permission.utils.PermissionMapping.isRuntimePlatformPermission
25 import com.android.permissioncontroller.permission.utils.Utils.OS_PKG
26 import kotlinx.coroutines.Job
27 
28 /**
29  * LiveData for a LightPermInfo.
30  *
31  * @param app current Application
32  * @param permissionName name of the permission this LiveData will watch for mode changes for
33  */
34 class LightPermInfoLiveData
35 private constructor(private val app: Application, private val permissionName: String) :
36     SmartAsyncMediatorLiveData<LightPermInfo>(), PackageBroadcastReceiver.PackageBroadcastListener {
37 
38     private val LOG_TAG = LightPermInfoLiveData::class.java.simpleName
39 
40     /** Is this liveData currently listing for changes */
41     private var isListeningForChanges = false
42 
43     /**
44      * Callback from the PackageBroadcastReceiver.
45      *
46      * <p>Package updates might change permission properties
47      *
48      * Note: packageName is unused.
49      */
onPackageUpdatenull50     override fun onPackageUpdate(packageName: String) {
51         updateAsync()
52     }
53 
updateAsyncnull54     override fun updateAsync() {
55         // No need to update if the value can never change
56         if (value != null && isImmutable()) {
57             return
58         }
59 
60         super.updateAsync()
61     }
62 
loadDataAndPostValuenull63     override suspend fun loadDataAndPostValue(job: Job) {
64         if (job.isCancelled) {
65             return
66         }
67 
68         val newValue =
69             try {
70                 LightPermInfo(app.packageManager.getPermissionInfo(permissionName, 0))
71             } catch (e: PackageManager.NameNotFoundException) {
72                 Log.w(LOG_TAG, "Permission \"$permissionName\" not found")
73                 invalidateSingle(permissionName)
74                 null
75             }
76 
77         if (isImmutable()) {
78             stopListeningForChanges()
79         }
80 
81         postValue(newValue)
82     }
83 
84     /** @return if the permission state can never change */
isImmutablenull85     private fun isImmutable(): Boolean {
86         // The os package never changes
87         value?.let {
88             if (it.packageName == OS_PKG) {
89                 return true
90             }
91         }
92 
93         // Platform permissions never change
94         return isRuntimePlatformPermission(permissionName)
95     }
96 
97     /** Start listing for changes to this permission if needed */
startListeningForChangesnull98     private fun startListeningForChanges() {
99         if (!isListeningForChanges && !isImmutable()) {
100             isListeningForChanges = true
101             PackageBroadcastReceiver.addAllCallback(this)
102         }
103     }
104 
105     /** Stop listing for changes to this permission */
stopListeningForChangesnull106     private fun stopListeningForChanges() {
107         if (isListeningForChanges) {
108             PackageBroadcastReceiver.removeAllCallback(this)
109             isListeningForChanges = false
110         }
111     }
112 
onActivenull113     override fun onActive() {
114         super.onActive()
115 
116         startListeningForChanges()
117     }
118 
onInactivenull119     override fun onInactive() {
120         super.onInactive()
121 
122         stopListeningForChanges()
123     }
124 
125     /**
126      * Repository for LightPermInfoLiveData
127      *
128      * <p>Key value is a string permission name, value is its corresponding LiveData.
129      */
130     companion object : DataRepositoryForPackage<String, LightPermInfoLiveData>() {
newValuenull131         override fun newValue(key: String): LightPermInfoLiveData {
132             return LightPermInfoLiveData(PermissionControllerApplication.get(), key)
133         }
134     }
135 }
136