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.role.ui.wear 18 19 import android.app.Activity 20 import android.app.role.RoleManager 21 import android.content.Context 22 import android.content.Intent 23 import android.os.Bundle 24 import android.os.Process 25 import android.os.UserHandle 26 import android.util.Log 27 import android.view.LayoutInflater 28 import android.view.View 29 import android.view.ViewGroup 30 import androidx.compose.ui.platform.ComposeView 31 import androidx.fragment.app.Fragment 32 import androidx.lifecycle.ViewModelProvider 33 import com.android.permissioncontroller.PermissionControllerStatsLog 34 import com.android.permissioncontroller.permission.utils.PackageRemovalMonitor 35 import com.android.permissioncontroller.role.model.UserDeniedManager 36 import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData 37 import com.android.permissioncontroller.role.ui.RequestRoleViewModel 38 import com.android.permissioncontroller.role.ui.wear.model.WearRequestRoleViewModel 39 import com.android.permissioncontroller.role.ui.wear.model.WearRequestRoleViewModelFactory 40 import com.android.permissioncontroller.role.utils.PackageUtils 41 import com.android.role.controller.model.Role 42 import com.android.role.controller.model.Roles 43 import java.util.Objects 44 45 /** Wear specific version of [com.android.permissioncontroller.role.ui.RequestRoleFragment] */ 46 class WearRequestRoleFragment : Fragment() { 47 private lateinit var packageName: String 48 private lateinit var roleName: String 49 private lateinit var role: Role 50 private lateinit var viewModel: RequestRoleViewModel 51 private lateinit var wearViewModel: WearRequestRoleViewModel 52 private lateinit var helper: WearRequestRoleHelper 53 54 private var packageRemovalMonitor: PackageRemovalMonitor? = null 55 56 override fun onCreateView( 57 inflater: LayoutInflater, 58 container: ViewGroup?, 59 savedInstanceState: Bundle? 60 ): View? { 61 roleName = arguments?.getString(Intent.EXTRA_ROLE_NAME) ?: "" 62 packageName = arguments?.getString(Intent.EXTRA_PACKAGE_NAME) ?: "" 63 val context: Context = requireContext() 64 65 role = 66 Roles.get(context)[roleName] 67 ?: let { 68 Log.e(TAG, "Unknown role: $roleName") 69 finish() 70 return null 71 } 72 val currentPackageNames = 73 context.getSystemService(RoleManager::class.java)!!.getRoleHolders(roleName) 74 if (currentPackageNames.contains(packageName)) { 75 Log.i( 76 TAG, 77 "Application is already a role holder, role: $roleName, package: $packageName" 78 ) 79 reportRequestResult( 80 PermissionControllerStatsLog 81 .ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED_ALREADY_GRANTED, 82 null 83 ) 84 clearDeniedSetResultOkAndFinish() 85 return null 86 } 87 val appInfo = PackageUtils.getApplicationInfo(packageName, context) 88 if (appInfo == null) { 89 Log.w(TAG, "Unknown application: $packageName") 90 reportRequestResult( 91 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED, 92 null 93 ) 94 finish() 95 return null 96 } 97 98 viewModel = 99 ViewModelProvider( 100 this, 101 RequestRoleViewModel.Factory(role, requireActivity().application) 102 ) 103 .get(RequestRoleViewModel::class.java) 104 viewModel.manageRoleHolderStateLiveData.observe(this, this::onManageRoleHolderStateChanged) 105 106 wearViewModel = 107 ViewModelProvider(this, WearRequestRoleViewModelFactory()) 108 .get(WearRequestRoleViewModel::class.java) 109 110 savedInstanceState?.let { wearViewModel.onRestoreInstanceState(it) } 111 112 helper = 113 WearRequestRoleHelper( 114 context, 115 appInfo, 116 role, 117 roleName, 118 packageName, 119 viewModel, 120 wearViewModel 121 ) 122 123 val onSetAsDefault: (Boolean, String?) -> Unit = { dontAskAgain, selectedPackageName -> 124 run { 125 if (dontAskAgain) { 126 Log.i( 127 TAG, 128 "Request denied with don't ask again, role: $roleName" + 129 ", package: $packageName" 130 ) 131 reportRequestResult( 132 PermissionControllerStatsLog 133 .ROLE_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_ALWAYS, 134 null 135 ) 136 setDeniedAlwaysAndFinish() 137 } else { 138 setRoleHolder(selectedPackageName) 139 } 140 } 141 } 142 val onCanceled: () -> Unit = { 143 Log.i(TAG, "Dialog cancelled, role: $roleName , package: $packageName") 144 reportRequestResult( 145 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED, 146 null 147 ) 148 setDeniedOnceAndFinish() 149 } 150 151 return ComposeView(context).apply { 152 setContent { WearRequestRoleScreen(helper, onSetAsDefault, onCanceled) } 153 } 154 } 155 156 private fun onManageRoleHolderStateChanged(state: Int) { 157 val liveData = viewModel.manageRoleHolderStateLiveData 158 when (state) { 159 ManageRoleHolderStateLiveData.STATE_SUCCESS -> { 160 val lastPackageName = liveData.lastPackageName 161 if (lastPackageName != null) { 162 role.onHolderSelectedAsUser( 163 lastPackageName, 164 liveData.lastUser, 165 requireContext() 166 ) 167 } 168 if (lastPackageName == packageName) { 169 Log.i( 170 TAG, 171 "Application added as a role holder, role: $roleName, package: " + 172 packageName 173 ) 174 clearDeniedSetResultOkAndFinish() 175 } else { 176 Log.i( 177 TAG, 178 "Request denied with another application added as a role holder, " + 179 "role: $roleName, package: $packageName" 180 ) 181 setDeniedOnceAndFinish() 182 } 183 } 184 ManageRoleHolderStateLiveData.STATE_FAILURE -> finish() 185 } 186 } 187 188 private fun clearDeniedSetResultOkAndFinish() { 189 UserDeniedManager.getInstance(requireContext()).clearDenied(roleName, packageName) 190 requireActivity().setResult(Activity.RESULT_OK) 191 finish() 192 } 193 194 private fun setDeniedOnceAndFinish() { 195 UserDeniedManager.getInstance(requireContext()).setDeniedOnce(roleName, packageName) 196 finish() 197 } 198 199 private fun reportRequestResult(result: Int, grantedAnotherPackageName: String?) { 200 val holderPackageName: String? = getHolderPackageName() 201 reportRequestResult( 202 getApplicationUid(packageName), 203 packageName, 204 roleName, 205 getQualifyingApplicationCount(), 206 getQualifyingApplicationUid(holderPackageName), 207 holderPackageName, 208 getQualifyingApplicationUid(grantedAnotherPackageName), 209 grantedAnotherPackageName, 210 result 211 ) 212 } 213 214 private fun getApplicationUid(packageName: String): Int { 215 val uid: Int = getQualifyingApplicationUid(packageName) 216 if (uid != -1) { 217 return uid 218 } 219 val applicationInfo = 220 PackageUtils.getApplicationInfo(packageName, requireActivity()) ?: return -1 221 return applicationInfo.uid 222 } 223 224 private fun getQualifyingApplicationUid(packageName: String?): Int { 225 if (packageName == null) { 226 return -1 227 } 228 viewModel.roleLiveData.value?.let { qualifyingApplications -> 229 for (qualifyingApplication in qualifyingApplications) { 230 val qualifyingApplicationInfo = qualifyingApplication.first 231 if (Objects.equals(qualifyingApplicationInfo.packageName, packageName)) { 232 return qualifyingApplicationInfo.uid 233 } 234 } 235 } 236 return -1 237 } 238 239 private fun getHolderPackageName(): String? { 240 viewModel.roleLiveData.value?.let { qualifyingApplications -> 241 for (qualifyingApplication in qualifyingApplications) { 242 val isHolderApplication = qualifyingApplication.second 243 if (isHolderApplication) { 244 return qualifyingApplication.first.packageName 245 } 246 } 247 } 248 return null 249 } 250 251 private fun getQualifyingApplicationCount(): Int { 252 return viewModel.roleLiveData.value?.size ?: -1 253 } 254 255 private fun setDeniedAlwaysAndFinish() { 256 UserDeniedManager.getInstance(requireContext()).setDeniedAlways(roleName, packageName) 257 finish() 258 } 259 260 private fun finish() { 261 requireActivity().finish() 262 } 263 264 private fun setRoleHolder(selectedPackageName: String?) { 265 val context: Context = requireContext() 266 val user: UserHandle = Process.myUserHandle() 267 if (selectedPackageName == null) { 268 reportRequestResult( 269 PermissionControllerStatsLog 270 .ROLE_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_GRANTED_ANOTHER, 271 null 272 ) 273 role.onNoneHolderSelectedAsUser(user, context) 274 viewModel.manageRoleHolderStateLiveData.clearRoleHoldersAsUser( 275 roleName, 276 0, 277 user, 278 context 279 ) 280 } else { 281 val isRequestingApplication = selectedPackageName == packageName 282 if (isRequestingApplication) { 283 reportRequestResult( 284 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED, 285 null 286 ) 287 } else { 288 reportRequestResult( 289 PermissionControllerStatsLog 290 .ROLE_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_GRANTED_ANOTHER, 291 selectedPackageName 292 ) 293 } 294 val flags = 295 if (isRequestingApplication) RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP else 0 296 viewModel.manageRoleHolderStateLiveData.setRoleHolderAsUser( 297 roleName, 298 selectedPackageName, 299 true, 300 flags, 301 user, 302 context 303 ) 304 } 305 } 306 307 override fun onSaveInstanceState(outState: Bundle) { 308 super.onSaveInstanceState(outState) 309 wearViewModel.onSaveInstanceState(outState) 310 } 311 312 override fun onStart() { 313 super.onStart() 314 packageRemovalMonitor = 315 object : PackageRemovalMonitor(requireContext(), packageName) { 316 override fun onPackageRemoved() { 317 Log.w( 318 TAG, 319 "Application is uninstalled, role: $roleName" + 320 ", package: " + 321 packageName 322 ) 323 reportRequestResult( 324 PermissionControllerStatsLog 325 .ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED, 326 null 327 ) 328 finish() 329 } 330 } 331 .apply { register() } 332 } 333 334 override fun onStop() { 335 super.onStop() 336 packageRemovalMonitor?.let { 337 it.unregister() 338 packageRemovalMonitor = null 339 } 340 } 341 342 companion object { 343 const val TAG = "WearRequestRoleFragment" 344 345 /** Creates a new instance of [WearRequestRoleFragment]. */ 346 @JvmStatic 347 fun newInstance(roleName: String, packageName: String): WearRequestRoleFragment { 348 return WearRequestRoleFragment().apply { 349 arguments = 350 Bundle().apply { 351 putString(Intent.EXTRA_ROLE_NAME, roleName) 352 putString(Intent.EXTRA_PACKAGE_NAME, packageName) 353 } 354 } 355 } 356 357 @JvmStatic 358 fun reportRequestResult( 359 requestingUid: Int, 360 requestingPackageName: String, 361 roleName: String, 362 qualifyingCount: Int, 363 currentUid: Int, 364 currentPackageName: String?, 365 grantedAnotherUid: Int, 366 grantedAnotherPackageName: String?, 367 result: Int 368 ) { 369 Log.i( 370 TAG, 371 "Role request result requestingUid=$requestingUid" + 372 " requestingPackageName=$requestingPackageName" + 373 " roleName=$roleName" + 374 " qualifyingCount=$qualifyingCount" + 375 " currentUid=$currentUid" + 376 " currentPackageName=$currentPackageName" + 377 " grantedAnotherUid=$grantedAnotherUid" + 378 " grantedAnotherPackageName=$grantedAnotherPackageName" + 379 " result=$result" 380 ) 381 PermissionControllerStatsLog.write( 382 PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED, 383 requestingUid, 384 requestingPackageName, 385 roleName, 386 qualifyingCount, 387 currentUid, 388 currentPackageName, 389 grantedAnotherUid, 390 grantedAnotherPackageName, 391 result 392 ) 393 } 394 } 395 } 396