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