1 /* <lambda>null2 * 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.ui.model 18 19 import android.Manifest 20 import android.app.Application 21 import android.content.Intent 22 import android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP 23 import android.os.Bundle 24 import androidx.fragment.app.Fragment 25 import androidx.lifecycle.AndroidViewModel 26 import androidx.lifecycle.MediatorLiveData 27 import androidx.lifecycle.MutableLiveData 28 import androidx.lifecycle.map 29 import androidx.navigation.fragment.findNavController 30 import com.android.permission.flags.Flags 31 import com.android.permissioncontroller.R 32 import com.android.permissioncontroller.permission.data.PermGroupsPackagesLiveData 33 import com.android.permissioncontroller.permission.data.PermGroupsPackagesUiInfoLiveData 34 import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData 35 import com.android.permissioncontroller.permission.data.StandardPermGroupNamesLiveData 36 import com.android.permissioncontroller.permission.data.unusedAutoRevokePackagesLiveData 37 import com.android.permissioncontroller.permission.utils.Utils 38 import com.android.permissioncontroller.permission.utils.navigateSafe 39 40 /** 41 * A ViewModel for the ManageStandardPermissionsFragment. Provides a LiveData which watches over all 42 * platform permission groups, and sends async updates when these groups have changes. It also 43 * provides a liveData which watches the custom permission groups of the system, and provides a list 44 * of group names. 45 * 46 * @param app The current application of the fragment 47 */ 48 class ManageStandardPermissionsViewModel(private val app: Application) : AndroidViewModel(app) { 49 50 val uiDataLiveData = PermGroupsPackagesUiInfoLiveData(app, StandardPermGroupNamesLiveData) 51 val usedStandardPermGroupsUiInfo = 52 PermGroupsPackagesUiInfoLiveData( 53 app, 54 if (Flags.declutteredPermissionManagerEnabled()) UsedStandardPermGroupNamesLiveData(app) 55 else MutableLiveData<List<String>>(), 56 ) 57 val numCustomPermGroups = NumCustomPermGroupsWithPackagesLiveData() 58 val numUnusedStandardPermGroups = 59 MediatorLiveData<Int>().apply { 60 if (Flags.declutteredPermissionManagerEnabled()) { 61 addSource(UnusedStandardPermGroupNamesLiveData(app)) { groupNames -> 62 value = groupNames.size 63 } 64 } 65 } 66 val numAutoRevoked = unusedAutoRevokePackagesLiveData.map { it?.size ?: 0 } 67 68 /** 69 * Navigate to the Custom Permissions screen 70 * 71 * @param fragment The fragment we are navigating from 72 * @param args The args to pass to the new fragment 73 */ 74 fun showCustomPermissions(fragment: Fragment, args: Bundle) { 75 fragment.findNavController().navigateSafe(R.id.standard_to_custom, args) 76 } 77 78 /** 79 * Navigate to a Permission Apps fragment 80 * 81 * @param fragment The fragment we are navigating from 82 * @param args The args to pass to the new fragment 83 */ 84 fun showPermissionApps(fragment: Fragment, args: Bundle) { 85 val groupName = args.getString(Intent.EXTRA_PERMISSION_GROUP_NAME) 86 if (groupName == Manifest.permission_group.NOTIFICATIONS) { 87 Utils.navigateToNotificationSettings(fragment.context!!) 88 return 89 } 90 if (Utils.isHealthPermissionUiEnabled() && groupName == HEALTH_PERMISSION_GROUP) { 91 Utils.navigateToHealthConnectSettings(fragment.context!!) 92 return 93 } 94 fragment.findNavController().navigateSafe(R.id.manage_to_perm_apps, args) 95 } 96 97 fun showAutoRevoke(fragment: Fragment, args: Bundle) { 98 fragment.findNavController().navigateSafe(R.id.manage_to_auto_revoke, args) 99 } 100 } 101 102 /** 103 * A LiveData which tracks the number of custom permission groups that are used by at least one 104 * package 105 */ 106 class NumCustomPermGroupsWithPackagesLiveData() : SmartUpdateMediatorLiveData<Int>() { 107 108 private val customPermGroupPackages = PermGroupsPackagesLiveData.get(customGroups = true) 109 110 init { <lambda>null111 addSource(customPermGroupPackages) { update() } 112 } 113 onUpdatenull114 override fun onUpdate() { 115 value = customPermGroupPackages.value?.size ?: 0 116 } 117 } 118 119 /** 120 * A LiveData that tracks the names of the platform-defined permission groups, such that at least 121 * one of the permissions in the group has been requested at runtime by at least one non-system 122 * application. 123 * 124 * @param app The current application of the fragment 125 */ 126 class UsedStandardPermGroupNamesLiveData(private val app: Application) : 127 SmartUpdateMediatorLiveData<List<String>>() { 128 init { 129 addSource(PermGroupsPackagesUiInfoLiveData(app, StandardPermGroupNamesLiveData)) { permGroupsnull130 permGroups -> 131 if (permGroups.values.any { it != null }) { 132 value = <lambda>null133 permGroups.filterValues { it != null && it.nonSystemTotal > 0 }.keys.toList() 134 } 135 } 136 } 137 onUpdatenull138 override fun onUpdate() { 139 /* No op override */ 140 } 141 } 142 143 /** 144 * A LiveData that tracks the names of the platform-defined permission groups, such that none of the 145 * the permissions in the group has been requested at runtime by any non-system application. 146 * 147 * @param app The current application of the fragment 148 */ 149 class UnusedStandardPermGroupNamesLiveData(private val app: Application) : 150 SmartUpdateMediatorLiveData<List<String>>() { 151 init { 152 addSource(PermGroupsPackagesUiInfoLiveData(app, StandardPermGroupNamesLiveData)) { permGroupsnull153 permGroups -> 154 value = permGroups.filterValues { it != null && it.nonSystemTotal == 0 }.keys.toList() 155 } 156 } 157 onUpdatenull158 override fun onUpdate() { 159 /* No op override */ 160 } 161 } 162