• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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.app.Activity
20 import android.content.Intent
21 import android.content.pm.PackageInfo
22 import android.content.pm.PackageManager
23 import android.os.Build
24 import android.os.Bundle
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 android.widget.Toast
31 import androidx.annotation.RequiresApi
32 import androidx.compose.ui.platform.ComposeView
33 import androidx.core.os.BundleCompat
34 import androidx.fragment.app.Fragment
35 import androidx.lifecycle.ViewModelProvider
36 import com.android.modules.utils.build.SdkLevel
37 import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
38 import com.android.permissioncontroller.R
39 import com.android.permissioncontroller.permission.model.AppPermissions
40 import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
41 import com.android.permissioncontroller.permission.model.v31.PermissionUsages
42 import com.android.permissioncontroller.permission.model.v31.PermissionUsages.PermissionsUsagesChangeCallback
43 import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModel
44 import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModelFactory
45 import com.android.permissioncontroller.permission.ui.wear.model.AppPermissionGroupsRevokeDialogViewModel
46 import com.android.permissioncontroller.permission.ui.wear.model.AppPermissionGroupsRevokeDialogViewModelFactory
47 import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModel
48 import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModelFactory
49 import com.android.permissioncontroller.permission.ui.wear.model.WearLocationProviderInterceptDialogViewModel
50 import com.android.permissioncontroller.permission.ui.wear.model.WearLocationProviderInterceptDialogViewModelFactory
51 import com.android.permissioncontroller.wear.permission.components.theme.WearPermissionTheme
52 import java.time.Instant
53 import java.util.concurrent.TimeUnit
54 
55 class WearAppPermissionGroupsFragment : Fragment(), PermissionsUsagesChangeCallback {
56     private lateinit var permissionUsages: PermissionUsages
57     private lateinit var wearViewModel: WearAppPermissionUsagesViewModel
58     private lateinit var helper: WearAppPermissionGroupsHelper
59 
60     // Suppress warning of the deprecated class [android.app.LoaderManager] since other form factors
61     // are using the class to load PermissionUsages.
62     @Suppress("DEPRECATION")
onCreateViewnull63     override fun onCreateView(
64         inflater: LayoutInflater,
65         container: ViewGroup?,
66         savedInstanceState: Bundle?,
67     ): View? {
68         val packageName = arguments?.getString(Intent.EXTRA_PACKAGE_NAME) ?: ""
69         val user =
70             arguments?.let {
71                 BundleCompat.getParcelable(it, Intent.EXTRA_USER, UserHandle::class.java)!!
72             } ?: UserHandle.SYSTEM
73 
74         val activity: Activity = requireActivity()
75         val packageManager = activity.packageManager
76         val packageInfo: PackageInfo? =
77             try {
78                 packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
79             } catch (e: PackageManager.NameNotFoundException) {
80                 Log.i(LOG_TAG, "No package:" + activity.callingPackage, e)
81                 null
82             }
83 
84         if (packageInfo == null) {
85             Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show()
86             activity.finish()
87             return null
88         }
89         val sessionId = arguments?.getLong(EXTRA_SESSION_ID, 0) ?: 0
90 
91         val appPermissions = AppPermissions(activity, packageInfo, true) { activity.finish() }
92 
93         val viewModel =
94             ViewModelProvider(
95                 owner = this,
96                 factory = AppPermissionGroupsViewModelFactory(packageName, user, sessionId),
97             )[AppPermissionGroupsViewModel::class.java]
98 
99         wearViewModel =
100             ViewModelProvider(owner = this, factory = WearAppPermissionUsagesViewModelFactory())[
101                 WearAppPermissionUsagesViewModel::class.java]
102 
103         val revokeDialogViewModel =
104             ViewModelProvider(
105                 owner = this,
106                 factory = AppPermissionGroupsRevokeDialogViewModelFactory(),
107             )[AppPermissionGroupsRevokeDialogViewModel::class.java]
108 
109         val locationProviderInterceptDialogViewModel =
110             ViewModelProvider(
111                 owner = this,
112                 factory = WearLocationProviderInterceptDialogViewModelFactory(),
113             )[WearLocationProviderInterceptDialogViewModel::class.java]
114 
115         val context = requireContext()
116 
117         // If the build type is below S, the app ops for permission usage can't be found. Thus, we
118         // shouldn't load permission usages, for them.
119         if (SdkLevel.isAtLeastS()) {
120             permissionUsages = PermissionUsages(context)
121             val aggregateDataFilterBeginDays =
122                 AppPermissionGroupsViewModel.AGGREGATE_DATA_FILTER_BEGIN_DAYS_1.toLong()
123 
124             val filterTimeBeginMillis =
125                 maxOf(
126                     System.currentTimeMillis() -
127                         TimeUnit.DAYS.toMillis(aggregateDataFilterBeginDays),
128                     Instant.EPOCH.toEpochMilli(),
129                 )
130             permissionUsages.load(
131                 null,
132                 null,
133                 filterTimeBeginMillis,
134                 Long.MAX_VALUE,
135                 PermissionUsages.USAGE_FLAG_LAST,
136                 requireActivity().loaderManager,
137                 false,
138                 false,
139                 this,
140                 false,
141             )
142         }
143         helper =
144             WearAppPermissionGroupsHelper(
145                 context = context,
146                 fragment = this,
147                 user = user,
148                 packageName = packageName,
149                 sessionId = sessionId,
150                 appPermissions = appPermissions,
151                 viewModel = viewModel,
152                 wearViewModel = wearViewModel,
153                 revokeDialogViewModel = revokeDialogViewModel,
154                 locationProviderInterceptDialogViewModel = locationProviderInterceptDialogViewModel,
155             )
156 
157         return ComposeView(activity).apply {
158             setContent { WearPermissionTheme { WearAppPermissionGroupsScreen(helper) } }
159         }
160     }
161 
onPausenull162     override fun onPause() {
163         super.onPause()
164         helper.logAndClearToggledGroups()
165     }
166 
167     @RequiresApi(Build.VERSION_CODES.S)
onPermissionUsagesChangednull168     override fun onPermissionUsagesChanged() {
169         if (permissionUsages.usages.isEmpty()) {
170             return
171         }
172         if (getContext() == null) {
173             // Async result has come in after our context is gone.
174             return
175         }
176         wearViewModel.appPermissionUsages.value =
177             ArrayList<AppPermissionUsage>(permissionUsages.usages)
178     }
179 
180     companion object {
181         const val LOG_TAG = "WearAppPermissionGroups"
182     }
183 }
184