1 /* <lambda>null2 * Copyright (C) 2023 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.wear 18 19 import android.Manifest 20 import android.content.Intent 21 import android.os.Build 22 import android.os.Bundle 23 import android.os.UserHandle 24 import android.view.LayoutInflater 25 import android.view.View 26 import android.view.ViewGroup 27 import androidx.annotation.RequiresApi 28 import androidx.compose.ui.platform.ComposeView 29 import androidx.fragment.app.Fragment 30 import androidx.lifecycle.ViewModelProvider 31 import com.android.modules.utils.build.SdkLevel 32 import com.android.permissioncontroller.Constants 33 import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage 34 import com.android.permissioncontroller.permission.model.v31.PermissionUsages 35 import com.android.permissioncontroller.permission.model.v31.PermissionUsages.PermissionsUsagesChangeCallback 36 import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel 37 import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModelFactory 38 import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModel 39 import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModelFactory 40 import com.android.permissioncontroller.permission.ui.wear.model.WearLocationProviderInterceptDialogViewModel 41 import com.android.permissioncontroller.permission.ui.wear.model.WearLocationProviderInterceptDialogViewModelFactory 42 43 /** 44 * This is a condensed version of 45 * [com.android.permissioncontroller.permission.ui.handheld.PermissionAppsFragment], tailored for 46 * Wear. 47 * 48 * Show and manage apps which request a single permission group. 49 * 50 * <p>Shows a list of apps which request at least on permission of this group. 51 */ 52 class WearPermissionAppsFragment : Fragment(), PermissionsUsagesChangeCallback { 53 private val LOG_TAG = "PermissionAppsFragment" 54 55 private lateinit var permissionUsages: PermissionUsages 56 private lateinit var wearViewModel: WearAppPermissionUsagesViewModel 57 58 // Suppress warning of the deprecated class [android.app.LoaderManager] since other form factors 59 // are using the class to load PermissionUsages. 60 @Suppress("DEPRECATION") 61 override fun onCreateView( 62 inflater: LayoutInflater, 63 container: ViewGroup?, 64 savedInstanceState: Bundle? 65 ): View? { 66 val permGroupName = 67 arguments?.getString(Intent.EXTRA_PERMISSION_GROUP_NAME) 68 ?: arguments?.getString(Intent.EXTRA_PERMISSION_NAME) 69 ?: throw RuntimeException("Permission group name must not be null.") 70 val sessionId: Long = 71 arguments?.getLong(Constants.EXTRA_SESSION_ID) ?: Constants.INVALID_SESSION_ID 72 val isStorageAndLessThanT = 73 !SdkLevel.isAtLeastT() && permGroupName == Manifest.permission_group.STORAGE 74 75 val activity = requireActivity() 76 val factory = 77 PermissionAppsViewModelFactory(activity.getApplication(), permGroupName, this, Bundle()) 78 val viewModel = ViewModelProvider(this, factory).get(PermissionAppsViewModel::class.java) 79 wearViewModel = 80 ViewModelProvider(this, WearAppPermissionUsagesViewModelFactory()) 81 .get(WearAppPermissionUsagesViewModel::class.java) 82 83 val locationProviderDialogViewModel = 84 ViewModelProvider( 85 owner = this, 86 factory = WearLocationProviderInterceptDialogViewModelFactory() 87 )[WearLocationProviderInterceptDialogViewModel::class.java] 88 89 val onAppClick: (String, UserHandle, String) -> Unit = { packageName, user, category -> 90 run { 91 viewModel.navigateToAppPermission( 92 this, 93 packageName, 94 user, 95 WearAppPermissionFragment.createArgs( 96 packageName, 97 null, 98 permGroupName, 99 user, 100 this::class.java.name, 101 sessionId, 102 category 103 ) 104 ) 105 } 106 } 107 108 val onShowSystemClick: (Boolean) -> Unit = { showSystem -> 109 run { viewModel.updateShowSystem(showSystem) } 110 } 111 112 val logPermissionAppsFragmentCreated: 113 (String, UserHandle, Long, Boolean, Boolean, Boolean) -> Unit = 114 { packageName, user, viewId, isAllowed, isAllowedForeground, isDenied -> 115 run { 116 viewModel.logPermissionAppsFragmentCreated( 117 packageName, 118 user, 119 viewId, 120 isAllowed, 121 isAllowedForeground, 122 isDenied, 123 sessionId, 124 activity.application, 125 permGroupName, 126 LOG_TAG 127 ) 128 } 129 } 130 131 // If the build type is below S, the app ops for permission usage can't be found. Thus, we 132 // shouldn't load permission usages, for them. 133 if (SdkLevel.isAtLeastS()) { 134 permissionUsages = PermissionUsages(requireContext()) 135 136 val filterTimeBeginMillis: Long = viewModel.getFilterTimeBeginMillis() 137 permissionUsages.load( 138 null, 139 null, 140 filterTimeBeginMillis, 141 Long.MAX_VALUE, 142 PermissionUsages.USAGE_FLAG_LAST, 143 requireActivity().loaderManager, 144 false, 145 false, 146 this, 147 false 148 ) 149 } 150 151 return ComposeView(requireContext()).apply { 152 setContent { 153 WearPermissionAppsScreen( 154 WearPermissionAppsHelper( 155 activity.application, 156 this@WearPermissionAppsFragment.requireContext(), 157 permGroupName, 158 viewModel, 159 wearViewModel, 160 locationProviderDialogViewModel, 161 isStorageAndLessThanT, 162 onAppClick, 163 onShowSystemClick, 164 logPermissionAppsFragmentCreated 165 ) 166 ) 167 } 168 } 169 } 170 171 @RequiresApi(Build.VERSION_CODES.S) 172 override fun onPermissionUsagesChanged() { 173 if (permissionUsages.usages.isEmpty()) { 174 return 175 } 176 if (context == null) { 177 // Async result has come in after our context is gone. 178 return 179 } 180 wearViewModel.appPermissionUsages.value = 181 ArrayList<AppPermissionUsage>(permissionUsages.usages) 182 } 183 } 184