/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.permissioncontroller.permission.data import android.app.Application import android.content.pm.PackageManager import android.util.Log import com.android.permissioncontroller.PermissionControllerApplication import com.android.permissioncontroller.permission.model.livedatatypes.LightPermInfo import com.android.permissioncontroller.permission.utils.PermissionMapping.isRuntimePlatformPermission import com.android.permissioncontroller.permission.utils.Utils.OS_PKG import kotlinx.coroutines.Job /** * LiveData for a LightPermInfo. * * @param app current Application * @param permissionName name of the permission this LiveData will watch for mode changes for */ class LightPermInfoLiveData private constructor(private val app: Application, private val permissionName: String) : SmartAsyncMediatorLiveData(), PackageBroadcastReceiver.PackageBroadcastListener { private val LOG_TAG = LightPermInfoLiveData::class.java.simpleName /** Is this liveData currently listing for changes */ private var isListeningForChanges = false /** * Callback from the PackageBroadcastReceiver. * *

Package updates might change permission properties * * Note: packageName is unused. */ override fun onPackageUpdate(packageName: String) { updateAsync() } override fun updateAsync() { // No need to update if the value can never change if (value != null && isImmutable()) { return } super.updateAsync() } override suspend fun loadDataAndPostValue(job: Job) { if (job.isCancelled) { return } val newValue = try { LightPermInfo(app.packageManager.getPermissionInfo(permissionName, 0)) } catch (e: PackageManager.NameNotFoundException) { Log.w(LOG_TAG, "Permission \"$permissionName\" not found") invalidateSingle(permissionName) null } if (isImmutable()) { stopListeningForChanges() } postValue(newValue) } /** @return if the permission state can never change */ private fun isImmutable(): Boolean { // The os package never changes value?.let { if (it.packageName == OS_PKG) { return true } } // Platform permissions never change return isRuntimePlatformPermission(permissionName) } /** Start listing for changes to this permission if needed */ private fun startListeningForChanges() { if (!isListeningForChanges && !isImmutable()) { isListeningForChanges = true PackageBroadcastReceiver.addAllCallback(this) } } /** Stop listing for changes to this permission */ private fun stopListeningForChanges() { if (isListeningForChanges) { PackageBroadcastReceiver.removeAllCallback(this) isListeningForChanges = false } } override fun onActive() { super.onActive() startListeningForChanges() } override fun onInactive() { super.onInactive() stopListeningForChanges() } /** * Repository for LightPermInfoLiveData * *

Key value is a string permission name, value is its corresponding LiveData. */ companion object : DataRepositoryForPackage() { override fun newValue(key: String): LightPermInfoLiveData { return LightPermInfoLiveData(PermissionControllerApplication.get(), key) } } }