1 /* 2 * Copyright (C) 2018 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.phone; 18 19 import android.content.Context; 20 import android.telephony.emergency.EmergencyNumber; 21 import android.text.TextUtils; 22 import android.view.View; 23 import android.view.ViewGroup; 24 import android.widget.BaseAdapter; 25 26 import androidx.annotation.NonNull; 27 import androidx.annotation.Nullable; 28 29 import com.google.common.collect.LinkedListMultimap; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 34 /** 35 * An abstract adapter between ECC data and the view contains ECC shortcuts. 36 * This adapter prepares description and icon for every promoted emergency number. 37 * The subclass should implements {@link #inflateView} to provide the view for an ECC data, when the 38 * view container calls {@link #getView}. 39 */ 40 public abstract class EccShortcutAdapter extends BaseAdapter { 41 private List<EccDisplayMaterial> mEccDisplayMaterialList; 42 43 private CharSequence mPoliceDescription; 44 private CharSequence mAmbulanceDescription; 45 private CharSequence mFireDescription; 46 47 private static class EccDisplayMaterial { 48 public CharSequence number = null; 49 public int iconRes = 0; 50 public CharSequence description = null; 51 } 52 EccShortcutAdapter(@onNull Context context)53 public EccShortcutAdapter(@NonNull Context context) { 54 mPoliceDescription = context.getText(R.string.police_type_description); 55 mAmbulanceDescription = context.getText(R.string.ambulance_type_description); 56 mFireDescription = context.getText(R.string.fire_type_description); 57 58 mEccDisplayMaterialList = new ArrayList<>(); 59 } 60 61 @Override getCount()62 public int getCount() { 63 return mEccDisplayMaterialList.size(); 64 } 65 66 @Override getItem(int position)67 public EccDisplayMaterial getItem(int position) { 68 return mEccDisplayMaterialList.get(position); 69 } 70 71 @Override getItemId(int position)72 public long getItemId(int position) { 73 return position; 74 } 75 76 @Override getView(int position, View convertView, ViewGroup parent)77 public View getView(int position, View convertView, ViewGroup parent) { 78 EccDisplayMaterial material = getItem(position); 79 return inflateView(convertView, parent, material.number, material.description, 80 material.iconRes); 81 } 82 83 /** 84 * Get a View that display the given ECC data: number, description and iconRes. 85 * 86 * @param convertView The old view to reuse, if possible. Note: You should check that this view 87 * is non-null and of an appropriate type before using. If it is not possible 88 * to convert this view to display the correct data, this method can create a 89 * new view. Heterogeneous lists can specify their number of view types, so 90 * that this View is always of the right type (see {@link 91 * BaseAdapter#getViewTypeCount()} and {@link 92 * BaseAdapter#getItemViewType(int)}). 93 * @param parent The parent that this view will eventually be attached to. 94 * @param number The number of the ECC shortcut to display in the view. 95 * @param description The description of the ECC shortcut to display in the view. 96 * @param iconRes The icon resource ID represent for the ECC shortcut. 97 * @return A View corresponding to the data at the specified position. 98 */ inflateView(View convertView, ViewGroup parent, CharSequence number, CharSequence description, int iconRes)99 public abstract View inflateView(View convertView, ViewGroup parent, CharSequence number, 100 CharSequence description, int iconRes); 101 102 /** 103 * Update country ECC info. This method converts given country ECC info to ECC data that could 104 * be display by the short container View. 105 * 106 * @param context The context used to access resources. 107 * @param phoneInfo Information of the phone to make an emergency call. 108 */ updateCountryEccInfo(@onNull Context context, @Nullable ShortcutViewUtils.PhoneInfo phoneInfo)109 public void updateCountryEccInfo(@NonNull Context context, 110 @Nullable ShortcutViewUtils.PhoneInfo phoneInfo) { 111 List<EccDisplayMaterial> displayMaterials = new ArrayList<>(); 112 113 try { 114 if (phoneInfo == null) { 115 return; 116 } 117 118 LinkedListMultimap<String, Integer> emergencyNumbers = LinkedListMultimap.create(); 119 for (int category : ShortcutViewUtils.PROMOTED_CATEGORIES) { 120 String number = pickEmergencyNumberForCategory(category, 121 phoneInfo.getPromotedEmergencyNumbers()); 122 if (number != null) { 123 emergencyNumbers.put(number, category); 124 } 125 } 126 127 // prepare display material for picked ECC 128 for (String number : emergencyNumbers.keySet()) { 129 EccDisplayMaterial material = prepareEccMaterial(context, number, 130 emergencyNumbers.get(number)); 131 if (material != null) { 132 displayMaterials.add(material); 133 } 134 } 135 } finally { 136 mEccDisplayMaterialList = displayMaterials; 137 notifyDataSetChanged(); 138 } 139 } 140 hasShortcut(String number)141 boolean hasShortcut(String number) { 142 if (mEccDisplayMaterialList == null) { 143 return false; 144 } 145 146 for (EccDisplayMaterial displayMaterial : mEccDisplayMaterialList) { 147 if (displayMaterial.number.equals(number)) { 148 return true; 149 } 150 } 151 return false; 152 } 153 154 @Nullable pickEmergencyNumberForCategory(int category, @NonNull List<EmergencyNumber> emergencyNumbers)155 private String pickEmergencyNumberForCategory(int category, 156 @NonNull List<EmergencyNumber> emergencyNumbers) { 157 for (EmergencyNumber number : emergencyNumbers) { 158 if ((number.getEmergencyServiceCategoryBitmask() & category) != 0) { 159 return number.getNumber(); 160 } 161 } 162 return null; 163 } 164 165 @Nullable prepareEccMaterial(@onNull Context context, @NonNull String number, @NonNull List<Integer> categories)166 private EccDisplayMaterial prepareEccMaterial(@NonNull Context context, @NonNull String number, 167 @NonNull List<Integer> categories) { 168 EccDisplayMaterial material = new EccDisplayMaterial(); 169 material.number = number; 170 for (int category : categories) { 171 CharSequence description; 172 switch (category) { 173 case EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE: 174 description = mPoliceDescription; 175 material.iconRes = R.drawable.ic_local_police_gm2_24px; 176 break; 177 case EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE: 178 description = mAmbulanceDescription; 179 material.iconRes = R.drawable.ic_local_hospital_gm2_24px; 180 break; 181 case EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE: 182 description = mFireDescription; 183 material.iconRes = R.drawable.ic_local_fire_department_gm2_24px; 184 break; 185 default: 186 // ignore unknown types 187 continue; 188 } 189 190 if (TextUtils.isEmpty(material.description)) { 191 material.description = description; 192 } else { 193 // concatenate multiple types 194 material.iconRes = R.drawable.ic_local_hospital_gm2_24px; 195 material.description = context.getString(R.string.description_concat_format, 196 material.description, description); 197 } 198 } 199 200 if (TextUtils.isEmpty(material.description) || material.iconRes == 0) { 201 return null; 202 } 203 return material; 204 } 205 } 206