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.companiondevicemanager; 18 19 import static com.android.companiondevicemanager.Utils.getHtmlFromResources; 20 import static com.android.companiondevicemanager.Utils.getIcon; 21 22 import static java.util.Collections.unmodifiableMap; 23 24 import android.content.Context; 25 import android.text.Spanned; 26 import android.util.ArrayMap; 27 import android.view.LayoutInflater; 28 import android.view.View; 29 import android.view.ViewGroup; 30 import android.view.accessibility.AccessibilityNodeInfo; 31 import android.widget.ImageButton; 32 import android.widget.ImageView; 33 import android.widget.TextView; 34 35 import androidx.recyclerview.widget.RecyclerView; 36 37 import java.util.List; 38 import java.util.Map; 39 40 class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.ViewHolder> { 41 private final Context mContext; 42 private List<Integer> mPermissions; 43 // Add the expand buttons if permissions are more than PERMISSION_SIZE in the permission list. 44 private static final int PERMISSION_SIZE = 2; 45 46 static final int PERMISSION_NOTIFICATION = 0; 47 static final int PERMISSION_STORAGE = 1; 48 static final int PERMISSION_APP_STREAMING = 2; 49 static final int PERMISSION_PHONE = 3; 50 static final int PERMISSION_SMS = 4; 51 static final int PERMISSION_CONTACTS = 5; 52 static final int PERMISSION_CALENDAR = 6; 53 static final int PERMISSION_NEARBY_DEVICES = 7; 54 static final int PERMISSION_NEARBY_DEVICE_STREAMING = 8; 55 static final int PERMISSION_MICROPHONE = 9; 56 static final int PERMISSION_CALL_LOGS = 10; 57 58 private static final Map<Integer, Integer> sTitleMap; 59 static { 60 final Map<Integer, Integer> map = new ArrayMap<>(); map.put(PERMISSION_NOTIFICATION, R.string.permission_notification)61 map.put(PERMISSION_NOTIFICATION, R.string.permission_notification); map.put(PERMISSION_STORAGE, R.string.permission_storage)62 map.put(PERMISSION_STORAGE, R.string.permission_storage); map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming)63 map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming); map.put(PERMISSION_PHONE, R.string.permission_phone)64 map.put(PERMISSION_PHONE, R.string.permission_phone); map.put(PERMISSION_SMS, R.string.permission_sms)65 map.put(PERMISSION_SMS, R.string.permission_sms); map.put(PERMISSION_CONTACTS, R.string.permission_contacts)66 map.put(PERMISSION_CONTACTS, R.string.permission_contacts); map.put(PERMISSION_CALENDAR, R.string.permission_calendar)67 map.put(PERMISSION_CALENDAR, R.string.permission_calendar); map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices)68 map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices); map.put(PERMISSION_NEARBY_DEVICE_STREAMING, R.string.permission_nearby_device_streaming)69 map.put(PERMISSION_NEARBY_DEVICE_STREAMING, R.string.permission_nearby_device_streaming); map.put(PERMISSION_MICROPHONE, R.string.permission_microphone)70 map.put(PERMISSION_MICROPHONE, R.string.permission_microphone); map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs)71 map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs); 72 sTitleMap = unmodifiableMap(map); 73 } 74 75 private static final Map<Integer, Integer> sSummaryMap; 76 static { 77 final Map<Integer, Integer> map = new ArrayMap<>(); map.put(PERMISSION_NOTIFICATION, R.string.permission_notification_summary)78 map.put(PERMISSION_NOTIFICATION, R.string.permission_notification_summary); map.put(PERMISSION_STORAGE, R.string.permission_storage_summary)79 map.put(PERMISSION_STORAGE, R.string.permission_storage_summary); map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming_summary)80 map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming_summary); map.put(PERMISSION_PHONE, R.string.permission_phone_summary)81 map.put(PERMISSION_PHONE, R.string.permission_phone_summary); map.put(PERMISSION_SMS, R.string.permission_sms_summary)82 map.put(PERMISSION_SMS, R.string.permission_sms_summary); map.put(PERMISSION_CONTACTS, R.string.permission_contacts_summary)83 map.put(PERMISSION_CONTACTS, R.string.permission_contacts_summary); map.put(PERMISSION_CALENDAR, R.string.permission_calendar_summary)84 map.put(PERMISSION_CALENDAR, R.string.permission_calendar_summary); map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices_summary)85 map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices_summary); map.put(PERMISSION_NEARBY_DEVICE_STREAMING, R.string.permission_nearby_device_streaming_summary)86 map.put(PERMISSION_NEARBY_DEVICE_STREAMING, 87 R.string.permission_nearby_device_streaming_summary); map.put(PERMISSION_MICROPHONE, R.string.permission_microphone_summary)88 map.put(PERMISSION_MICROPHONE, R.string.permission_microphone_summary); map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs_summary)89 map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs_summary); 90 sSummaryMap = unmodifiableMap(map); 91 } 92 93 private static final Map<Integer, Integer> sIconMap; 94 static { 95 final Map<Integer, Integer> map = new ArrayMap<>(); map.put(PERMISSION_NOTIFICATION, R.drawable.ic_permission_notifications)96 map.put(PERMISSION_NOTIFICATION, R.drawable.ic_permission_notifications); map.put(PERMISSION_STORAGE, R.drawable.ic_permission_storage)97 map.put(PERMISSION_STORAGE, R.drawable.ic_permission_storage); map.put(PERMISSION_APP_STREAMING, R.drawable.ic_permission_app_streaming)98 map.put(PERMISSION_APP_STREAMING, R.drawable.ic_permission_app_streaming); map.put(PERMISSION_PHONE, R.drawable.ic_permission_phone)99 map.put(PERMISSION_PHONE, R.drawable.ic_permission_phone); map.put(PERMISSION_SMS, R.drawable.ic_permission_sms)100 map.put(PERMISSION_SMS, R.drawable.ic_permission_sms); map.put(PERMISSION_CONTACTS, R.drawable.ic_permission_contacts)101 map.put(PERMISSION_CONTACTS, R.drawable.ic_permission_contacts); map.put(PERMISSION_CALENDAR, R.drawable.ic_permission_calendar)102 map.put(PERMISSION_CALENDAR, R.drawable.ic_permission_calendar); map.put(PERMISSION_NEARBY_DEVICES, R.drawable.ic_permission_nearby_devices)103 map.put(PERMISSION_NEARBY_DEVICES, R.drawable.ic_permission_nearby_devices); map.put(PERMISSION_NEARBY_DEVICE_STREAMING, R.drawable.ic_permission_nearby_device_streaming)104 map.put(PERMISSION_NEARBY_DEVICE_STREAMING, 105 R.drawable.ic_permission_nearby_device_streaming); map.put(PERMISSION_MICROPHONE, R.drawable.ic_permission_microphone)106 map.put(PERMISSION_MICROPHONE, R.drawable.ic_permission_microphone); map.put(PERMISSION_CALL_LOGS, R.drawable.ic_permission_call_logs)107 map.put(PERMISSION_CALL_LOGS, R.drawable.ic_permission_call_logs); 108 sIconMap = unmodifiableMap(map); 109 } 110 PermissionListAdapter(Context context)111 PermissionListAdapter(Context context) { 112 mContext = context; 113 } 114 115 @Override onCreateViewHolder(ViewGroup parent, int viewType)116 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 117 View view = LayoutInflater.from(parent.getContext()).inflate( 118 R.layout.list_item_permission, parent, false); 119 ViewHolder viewHolder = new ViewHolder(view); 120 viewHolder.mPermissionIcon.setImageDrawable(getIcon(mContext, sIconMap.get(viewType))); 121 122 if (viewHolder.mExpandButton.getTag() == null) { 123 viewHolder.mExpandButton.setTag(R.drawable.btn_expand_more); 124 } 125 126 // Add expand buttons if the permissions are more than PERMISSION_SIZE in this list also 127 // make the summary invisible by default. 128 if (mPermissions.size() > PERMISSION_SIZE) { 129 setAccessibility(view, viewType, 130 AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_expand, 0); 131 132 viewHolder.mPermissionSummary.setVisibility(View.GONE); 133 134 view.setOnClickListener(v -> { 135 if ((Integer) viewHolder.mExpandButton.getTag() == R.drawable.btn_expand_more) { 136 viewHolder.mExpandButton.setImageResource(R.drawable.btn_expand_less); 137 viewHolder.mPermissionSummary.setVisibility(View.VISIBLE); 138 viewHolder.mExpandButton.setTag(R.drawable.btn_expand_less); 139 setAccessibility(view, viewType, 140 AccessibilityNodeInfo.ACTION_CLICK, 141 R.string.permission_collapse, R.string.permission_expand); 142 } else { 143 viewHolder.mExpandButton.setImageResource(R.drawable.btn_expand_more); 144 viewHolder.mPermissionSummary.setVisibility(View.GONE); 145 viewHolder.mExpandButton.setTag(R.drawable.btn_expand_more); 146 setAccessibility(view, viewType, 147 AccessibilityNodeInfo.ACTION_CLICK, 148 R.string.permission_expand, R.string.permission_collapse); 149 } 150 }); 151 } else { 152 // Remove expand buttons if the permissions are less than PERMISSION_SIZE in this list 153 // also show the summary by default. 154 viewHolder.mPermissionSummary.setVisibility(View.VISIBLE); 155 viewHolder.mExpandButton.setVisibility(View.GONE); 156 } 157 158 return viewHolder; 159 } 160 161 @Override onBindViewHolder(ViewHolder holder, int position)162 public void onBindViewHolder(ViewHolder holder, int position) { 163 int type = getItemViewType(position); 164 final Spanned title = getHtmlFromResources(mContext, sTitleMap.get(type)); 165 final Spanned summary = getHtmlFromResources(mContext, sSummaryMap.get(type)); 166 167 holder.mPermissionSummary.setText(summary); 168 holder.mPermissionName.setText(title); 169 } 170 171 @Override getItemViewType(int position)172 public int getItemViewType(int position) { 173 return mPermissions.get(position); 174 } 175 176 @Override getItemId(int position)177 public long getItemId(int position) { 178 return position; 179 } 180 181 @Override getItemCount()182 public int getItemCount() { 183 return mPermissions != null ? mPermissions.size() : 0; 184 } 185 186 static class ViewHolder extends RecyclerView.ViewHolder { 187 private final TextView mPermissionName; 188 private final TextView mPermissionSummary; 189 private final ImageView mPermissionIcon; 190 private final ImageButton mExpandButton; ViewHolder(View itemView)191 ViewHolder(View itemView) { 192 super(itemView); 193 mPermissionName = itemView.findViewById(R.id.permission_name); 194 mPermissionSummary = itemView.findViewById(R.id.permission_summary); 195 mPermissionIcon = itemView.findViewById(R.id.permission_icon); 196 mExpandButton = itemView.findViewById(R.id.permission_expand_button); 197 } 198 } 199 setAccessibility(View view, int viewType, int action, int statusResourceId, int actionResourceId)200 private void setAccessibility(View view, int viewType, int action, int statusResourceId, 201 int actionResourceId) { 202 final String permission = mContext.getString(sTitleMap.get(viewType)); 203 204 if (actionResourceId != 0) { 205 view.announceForAccessibility( 206 getHtmlFromResources(mContext, actionResourceId, permission)); 207 } 208 209 view.setAccessibilityDelegate(new View.AccessibilityDelegate() { 210 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 211 super.onInitializeAccessibilityNodeInfo(host, info); 212 info.addAction(new AccessibilityNodeInfo.AccessibilityAction(action, 213 getHtmlFromResources(mContext, statusResourceId, permission))); 214 } 215 }); 216 } 217 setPermissionType(List<Integer> permissions)218 void setPermissionType(List<Integer> permissions) { 219 mPermissions = permissions; 220 } 221 } 222