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.UserManager 22 import android.safetycenter.SafetyCenterEntry 23 import android.safetycenter.SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR 24 import android.text.TextUtils 25 import android.util.Log 26 import android.widget.ImageView 27 import android.widget.TextView 28 import androidx.annotation.RequiresApi 29 import androidx.preference.Preference 30 import androidx.preference.PreferenceViewHolder 31 import com.android.permissioncontroller.R 32 import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PERSONAL_PROFILE_SUFFIX 33 import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.WORK_PROFILE_SUFFIX 34 import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel 35 import com.android.permissioncontroller.safetycenter.ui.view.SafetyEntryCommonViewsManager.Companion.changeEnabledState 36 import com.android.safetycenter.internaldata.SafetyCenterEntryId 37 import com.android.safetycenter.internaldata.SafetyCenterIds 38 import com.android.settingslib.widget.TwoTargetPreference 39 40 /** 41 * A preference that displays a visual representation of a {@link SafetyCenterEntry} on the Safety 42 * Center subpage. 43 */ 44 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 45 class SafetySubpageEntryPreference( 46 context: Context, 47 private val launchTaskId: Int?, 48 private val entry: SafetyCenterEntry, 49 private val viewModel: SafetyCenterViewModel 50 ) : TwoTargetPreference(context), ComparablePreference { 51 52 init { 53 setupIconActionButton() 54 setupClickListener() 55 setTitle(entry.title) 56 setSummary(entry.summary) 57 setSelectable(true) 58 setupPreferenceKey() 59 } 60 setupIconActionButtonnull61 private fun setupIconActionButton() { 62 if (entry.iconAction != null) { 63 setIconSize(ICON_SIZE_MEDIUM) 64 setWidgetLayoutResource( 65 if (entry.iconAction!!.type == ICON_ACTION_TYPE_GEAR) { 66 R.layout.preference_entry_icon_action_gear_widget 67 } else { 68 R.layout.preference_entry_icon_action_info_widget 69 } 70 ) 71 } 72 } 73 setupClickListenernull74 private fun setupClickListener() { 75 val pendingIntent = entry.pendingIntent 76 if (pendingIntent != null) { 77 setOnPreferenceClickListener { 78 try { 79 PendingIntentSender.send(pendingIntent, launchTaskId) 80 viewModel.interactionLogger.recordForEntry(Action.ENTRY_CLICKED, entry) 81 true 82 } catch (ex: Exception) { 83 Log.e(TAG, "Failed to execute pending intent for $entry", ex) 84 false 85 } 86 } 87 setEnabled(true) 88 } else { 89 Log.w(TAG, "Pending intent is null for $entry") 90 setEnabled(false) 91 } 92 } 93 setupPreferenceKeynull94 private fun setupPreferenceKey() { 95 val entryId: SafetyCenterEntryId = SafetyCenterIds.entryIdFromString(entry.id) 96 val isWorkProfile = 97 context.getSystemService(UserManager::class.java).isManagedProfile(entryId.userId) 98 val keySuffix = if (isWorkProfile) WORK_PROFILE_SUFFIX else PERSONAL_PROFILE_SUFFIX 99 setKey("${entryId.safetySourceId}_$keySuffix") 100 } 101 onBindViewHoldernull102 override fun onBindViewHolder(holder: PreferenceViewHolder) { 103 super.onBindViewHolder(holder) 104 val iconAction = entry.iconAction 105 if (iconAction == null) { 106 Log.w(TAG, "Icon action is null for $entry") 107 } else { 108 val iconActionButton = holder.findViewById(R.id.icon_action_button) as? ImageView? 109 iconActionButton?.setOnClickListener { 110 try { 111 PendingIntentSender.send(iconAction.pendingIntent, launchTaskId) 112 viewModel.interactionLogger.recordForEntry( 113 Action.ENTRY_ICON_ACTION_CLICKED, 114 entry 115 ) 116 } catch (ex: Exception) { 117 Log.e(TAG, "Failed to execute icon action intent for $entry", ex) 118 } 119 } 120 } 121 122 val titleView = holder.findViewById(android.R.id.title) as? TextView? 123 val summaryView = holder.findViewById(android.R.id.summary) as? TextView? 124 changeEnabledState(context, entry.isEnabled, isEnabled(), titleView, summaryView) 125 } 126 shouldHideSecondTargetnull127 override fun shouldHideSecondTarget(): Boolean = entry.iconAction == null 128 129 override fun isSameItem(preference: Preference): Boolean = 130 preference is SafetySubpageEntryPreference && 131 TextUtils.equals(entry.id, preference.entry.id) 132 133 override fun hasSameContents(preference: Preference): Boolean = 134 preference is SafetySubpageEntryPreference && entry == preference.entry 135 136 companion object { 137 private val TAG: String = SafetySubpageEntryPreference::class.java.simpleName 138 } 139 } 140