• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.safetycenter.ui
18 
19 import android.content.Context
20 import android.os.Build
21 import android.os.UserHandle
22 import android.os.UserManager
23 import android.safetycenter.SafetyCenterEntry
24 import android.safetycenter.SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR
25 import android.text.TextUtils
26 import android.util.Log
27 import android.widget.ImageView
28 import android.widget.TextView
29 import androidx.annotation.RequiresApi
30 import androidx.preference.Preference
31 import androidx.preference.PreferenceViewHolder
32 import com.android.modules.utils.build.SdkLevel
33 import com.android.permissioncontroller.R
34 import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PERSONAL_PROFILE_SUFFIX
35 import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PRIVATE_PROFILE_SUFFIX
36 import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.WORK_PROFILE_SUFFIX
37 import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel
38 import com.android.permissioncontroller.safetycenter.ui.view.SafetyEntryCommonViewsManager.Companion.changeEnabledState
39 import com.android.safetycenter.internaldata.SafetyCenterEntryId
40 import com.android.safetycenter.internaldata.SafetyCenterIds
41 import com.android.settingslib.widget.TwoTargetPreference
42 
43 /**
44  * A preference that displays a visual representation of a {@link SafetyCenterEntry} on the Safety
45  * Center subpage.
46  */
47 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
48 class SafetySubpageEntryPreference(
49     context: Context,
50     private val launchTaskId: Int?,
51     private val entry: SafetyCenterEntry,
52     private val viewModel: SafetyCenterViewModel,
53 ) : TwoTargetPreference(context), ComparablePreference {
54 
55     init {
56         setupIconActionButton()
57         setupClickListener()
58         setTitle(entry.title)
59         setSummary(entry.summary)
60         setSelectable(true)
61         setupPreferenceKey()
62     }
63 
setupIconActionButtonnull64     private fun setupIconActionButton() {
65         if (entry.iconAction != null) {
66             setIconSize(ICON_SIZE_MEDIUM)
67             setWidgetLayoutResource(
68                 if (entry.iconAction!!.type == ICON_ACTION_TYPE_GEAR) {
69                     R.layout.preference_entry_icon_action_gear_widget
70                 } else {
71                     R.layout.preference_entry_icon_action_info_widget
72                 }
73             )
74         }
75     }
76 
setupClickListenernull77     private fun setupClickListener() {
78         val pendingIntent = entry.pendingIntent
79         if (pendingIntent != null) {
80             setOnPreferenceClickListener {
81                 try {
82                     PendingIntentSender.send(pendingIntent, launchTaskId)
83                     viewModel.interactionLogger.recordForEntry(Action.ENTRY_CLICKED, entry)
84                     true
85                 } catch (ex: Exception) {
86                     Log.e(TAG, "Failed to execute pending intent for $entry", ex)
87                     false
88                 }
89             }
90             setEnabled(true)
91         } else {
92             Log.w(TAG, "Pending intent is null for $entry")
93             setEnabled(false)
94         }
95     }
96 
setupPreferenceKeynull97     private fun setupPreferenceKey() {
98         val entryId: SafetyCenterEntryId = SafetyCenterIds.entryIdFromString(entry.id)
99         val userContext = context.createContextAsUser(UserHandle.of(entryId.userId), /* flags= */ 0)
100         val userUserManager = userContext.getSystemService(UserManager::class.java) ?: return
101         if (userUserManager.isManagedProfile) {
102             setKey("${entryId.safetySourceId}_$WORK_PROFILE_SUFFIX")
103         } else if (isPrivateProfileSupported() && userUserManager.isPrivateProfile) {
104             setKey("${entryId.safetySourceId}_$PRIVATE_PROFILE_SUFFIX")
105         } else {
106             setKey("${entryId.safetySourceId}_$PERSONAL_PROFILE_SUFFIX")
107         }
108     }
109 
isPrivateProfileSupportednull110     private fun isPrivateProfileSupported(): Boolean {
111         return SdkLevel.isAtLeastV() && com.android.permission.flags.Flags.privateProfileSupported()
112     }
113 
onBindViewHoldernull114     override fun onBindViewHolder(holder: PreferenceViewHolder) {
115         super.onBindViewHolder(holder)
116         val iconAction = entry.iconAction
117         if (iconAction == null) {
118             Log.w(TAG, "Icon action is null for $entry")
119         } else {
120             val iconActionButton = holder.findViewById(R.id.icon_action_button) as? ImageView?
121             iconActionButton?.setOnClickListener {
122                 try {
123                     PendingIntentSender.send(iconAction.pendingIntent, launchTaskId)
124                     viewModel.interactionLogger.recordForEntry(
125                         Action.ENTRY_ICON_ACTION_CLICKED,
126                         entry,
127                     )
128                 } catch (ex: Exception) {
129                     Log.e(TAG, "Failed to execute icon action intent for $entry", ex)
130                 }
131             }
132         }
133 
134         val titleView = holder.findViewById(android.R.id.title) as? TextView?
135         val summaryView = holder.findViewById(android.R.id.summary) as? TextView?
136         changeEnabledState(context, entry.isEnabled, isEnabled(), titleView, summaryView)
137     }
138 
shouldHideSecondTargetnull139     override fun shouldHideSecondTarget(): Boolean = entry.iconAction == null
140 
141     override fun isSameItem(preference: Preference): Boolean =
142         preference is SafetySubpageEntryPreference &&
143             TextUtils.equals(entry.id, preference.entry.id)
144 
145     override fun hasSameContents(preference: Preference): Boolean =
146         preference is SafetySubpageEntryPreference && entry == preference.entry
147 
148     companion object {
149         private val TAG: String = SafetySubpageEntryPreference::class.java.simpleName
150     }
151 }
152