• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2021 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 @file:Suppress("DEPRECATION")
17 
18 package com.android.permissioncontroller.permission.ui.auto
19 
20 import android.annotation.SuppressLint
21 import android.content.Intent
22 import android.os.Bundle
23 import android.os.UserHandle
24 import androidx.lifecycle.ViewModelProvider
25 import androidx.preference.Preference
26 import androidx.preference.PreferenceCategory
27 import androidx.preference.PreferenceGroup
28 import com.android.car.ui.preference.CarUiPreference
29 import com.android.permissioncontroller.Constants
30 import com.android.permissioncontroller.DumpableLog
31 import com.android.permissioncontroller.PermissionControllerStatsLog
32 import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_REMINDER_NOTIFICATION_INTERACTED__RESULT__NOTIFICATION_CLICKED
33 import com.android.permissioncontroller.PermissionControllerStatsLog.RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__REVIEW_DECISION
34 import com.android.permissioncontroller.PermissionControllerStatsLog.RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__SCREEN_VIEWED
35 import com.android.permissioncontroller.PermissionControllerStatsLog.RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__VIEW_ALL_CLICKED
36 import com.android.permissioncontroller.R
37 import com.android.permissioncontroller.auto.AutoSettingsFrameFragment
38 import com.android.permissioncontroller.permission.data.v33.PermissionDecision
39 import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
40 import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionDecisionsViewModel
41 import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionDecisionsViewModelFactory
42 import com.android.permissioncontroller.permission.utils.KotlinUtils.getPackageUid
43 import com.android.permissioncontroller.permission.utils.Utils
44 import kotlin.math.min
45 
46 /** Shows summary of recent permission decisions. */
47 @SuppressLint("NewApi")
48 class AutoReviewPermissionDecisionsFragment : AutoSettingsFrameFragment() {
49 
50     companion object {
51         const val EXTRA_SOURCE = "source"
52         const val EXTRA_SOURCE_NOTIFICATION = "notification"
53         private const val LOG_TAG = "AutoReviewPermissionDecisionsFragment"
54         private const val MAX_DECISIONS = 3
55 
56         /**
57          * Creates a new instance of [AutoReviewPermissionDecisionsFragment].
58          */
59         fun newInstance(
60             sessionId: Long,
61             userHandle: UserHandle,
62             source: String?
63         ): AutoReviewPermissionDecisionsFragment {
64             return AutoReviewPermissionDecisionsFragment().apply {
65                 arguments = Bundle().apply {
66                     putLong(Constants.EXTRA_SESSION_ID, sessionId)
67                     putParcelable(Intent.EXTRA_USER, userHandle)
68                     putString(EXTRA_SOURCE, source)
69                 }
70             }
71         }
72     }
73 
74     private lateinit var user: UserHandle
75     private lateinit var viewModel: ReviewPermissionDecisionsViewModel
76     private lateinit var recentPermissionsGroup: PreferenceCategory
77     private var sessionId: Long = Constants.INVALID_SESSION_ID
78 
79     override fun onCreate(savedInstanceState: Bundle?) {
80         super.onCreate(savedInstanceState)
81         if (arguments == null) {
82             DumpableLog.e(LOG_TAG, "Missing arguments")
83             activity?.finish()
84             return
85         }
86         if (!requireArguments().containsKey(Intent.EXTRA_USER)) {
87             DumpableLog.e(LOG_TAG, "Missing argument ${Intent.EXTRA_USER}")
88             activity?.finish()
89             return
90         }
91         if (!requireArguments().containsKey(Constants.EXTRA_SESSION_ID)) {
92             DumpableLog.e(LOG_TAG, "Missing argument ${Constants.EXTRA_SESSION_ID}")
93             activity?.finish()
94             return
95         }
96         user = requireArguments().getParcelable<UserHandle>(Intent.EXTRA_USER)!!
97         sessionId = requireArguments().getLong(Constants.EXTRA_SESSION_ID)
98         if (requireArguments().containsKey(EXTRA_SOURCE) &&
99             (requireArguments().getString(EXTRA_SOURCE) == EXTRA_SOURCE_NOTIFICATION)) {
100             logDecisionReminderNotificationClicked()
101         }
102         val factory = ReviewPermissionDecisionsViewModelFactory(
103             requireActivity().getApplication()!!, user)
104         viewModel = ViewModelProvider(this,
105             factory)[ReviewPermissionDecisionsViewModel::class.java]
106 
107         addPrivacyDashboardPreference()
108         addPermissionManagerPreference()
109         preferenceScreen.addPreference(AutoDividerPreference(context))
110         recentPermissionsGroup = PreferenceCategory(context!!).apply {
111             title = getString(R.string.review_permission_decisions)
112         }
113         preferenceScreen.addPreference(recentPermissionsGroup)
114 
115         viewModel.recentPermissionDecisionsLiveData.observe(this) { recentDecisions ->
116             onRecentDecisionsChanged(recentDecisions)
117         }
118         headerLabel = getString(R.string.app_permissions)
119 
120         logScreenViewed()
121     }
122 
123     override fun onCreatePreferences(bundle: Bundle?, s: String?) {
124         preferenceScreen = preferenceManager.createPreferenceScreen(context!!)
125     }
126 
127     private fun onRecentDecisionsChanged(recentDecisions: List<PermissionDecision>) {
128         recentPermissionsGroup.removeAll()
129 
130         if (recentDecisions.isEmpty()) {
131             addNoRecentDecisionsPreference(recentPermissionsGroup)
132         } else {
133             addRecentDecisionPreferences(recentPermissionsGroup, recentDecisions)
134         }
135         if (recentDecisions.size > MAX_DECISIONS) {
136             addViewAllPreference(recentPermissionsGroup)
137         }
138     }
139 
140     private fun addPrivacyDashboardPreference() {
141         val preference = CarUiPreference(context).apply {
142             title = getString(R.string.permission_usage_title)
143             summary = getString(R.string.auto_permission_usage_summary)
144             onPreferenceClickListener = Preference.OnPreferenceClickListener { _ ->
145                 val intent = Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).apply {
146                     putExtra(Constants.EXTRA_SESSION_ID, sessionId)
147                 }
148                 startActivity(intent)
149                 true
150             }
151         }
152         preferenceScreen.addPreference(preference)
153     }
154 
155     private fun addPermissionManagerPreference() {
156         val preference = CarUiPreference(context).apply {
157             title = getString(R.string.app_permission_manager)
158             summary = getString(R.string.auto_permission_manager_summary)
159             onPreferenceClickListener = Preference.OnPreferenceClickListener { _ ->
160                 val intent = Intent(Intent.ACTION_MANAGE_PERMISSIONS).apply {
161                     putExtra(Intent.EXTRA_USER, user)
162                     putExtra(ManagePermissionsActivity.EXTRA_CALLER_NAME, javaClass.name)
163                     putExtra(Constants.EXTRA_SESSION_ID, sessionId)
164                 }
165                 startActivity(intent)
166                 true
167             }
168         }
169         preferenceScreen.addPreference(preference)
170     }
171 
172     private fun addRecentDecisionPreferences(
173         preferenceGroup: PreferenceGroup,
174         recentDecisions: List<PermissionDecision>
175     ) {
176         for (i in 0 until min(recentDecisions.size, MAX_DECISIONS)) {
177             val recentDecision = recentDecisions[i]
178             val decisionPreference = CarUiPreference(context).apply {
179                 icon = viewModel.getAppIcon(recentDecision.packageName)
180                 title = viewModel.createPreferenceTitle(recentDecision)
181                 summary = viewModel.createSummaryText(recentDecision)
182                 onPreferenceClickListener = Preference.OnPreferenceClickListener {
183                     viewModel.createManageAppPermissionIntent(recentDecision).also {
184                         startActivity(it)
185                     }
186                     logPermissionDecisionClicked(recentDecision.packageName,
187                         recentDecision.permissionGroupName)
188                     true
189                 }
190             }
191             preferenceGroup.addPreference(decisionPreference)
192         }
193     }
194 
195     private fun addViewAllPreference(preferenceGroup: PreferenceGroup) {
196         val viewAllIcon = requireContext().getDrawable(R.drawable.car_ic_apps)
197         val preference = CarUiPreference(context).apply {
198             icon = Utils.applyTint(context, viewAllIcon, android.R.attr.colorControlNormal)
199             title = getString(R.string.review_permission_decisions_view_all)
200             onPreferenceClickListener = Preference.OnPreferenceClickListener {
201                 val frag = AutoReviewPermissionDecisionsViewAllFragment.newInstance(sessionId,
202                     user)
203                 getParentFragmentManager().beginTransaction()
204                     .replace(android.R.id.content, frag)
205                     .addToBackStack(null)
206                     .commit()
207                 logViewAllClicked()
208                 true
209             }
210         }
211         preferenceGroup.addPreference(preference)
212     }
213 
214     private fun addNoRecentDecisionsPreference(preferenceGroup: PreferenceGroup) {
215         val preference = CarUiPreference(context).apply {
216             title = getString(R.string.review_permission_decisions_empty)
217         }
218         preferenceGroup.addPreference(preference)
219     }
220 
221     private fun logScreenViewed() {
222         PermissionControllerStatsLog.write(
223             PermissionControllerStatsLog.RECENT_PERMISSION_DECISIONS_INTERACTED,
224             sessionId,
225             RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__SCREEN_VIEWED,
226             0,
227             null)
228     }
229 
230     private fun logViewAllClicked() {
231         PermissionControllerStatsLog.write(
232             PermissionControllerStatsLog.RECENT_PERMISSION_DECISIONS_INTERACTED,
233             sessionId,
234             RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__VIEW_ALL_CLICKED,
235             0,
236             null)
237     }
238 
239     private fun logPermissionDecisionClicked(packageName: String, permissionGroupName: String) {
240         val uid = getPackageUid(requireActivity().getApplication(), packageName, user) ?: return
241         PermissionControllerStatsLog.write(
242             PermissionControllerStatsLog.RECENT_PERMISSION_DECISIONS_INTERACTED,
243             sessionId,
244             RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__REVIEW_DECISION,
245             uid,
246             permissionGroupName)
247     }
248 
249     private fun logDecisionReminderNotificationClicked() {
250         PermissionControllerStatsLog.write(
251             PermissionControllerStatsLog.PERMISSION_REMINDER_NOTIFICATION_INTERACTED,
252             sessionId, PERMISSION_REMINDER_NOTIFICATION_INTERACTED__RESULT__NOTIFICATION_CLICKED)
253     }
254 }
255