1 /* 2 * Copyright (C) 2012 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.contacts.common.util; 18 19 import static android.provider.ContactsContract.CommonDataKinds.Phone; 20 21 import com.google.common.base.Preconditions; 22 23 import android.content.Context; 24 import android.content.res.Resources; 25 import android.support.annotation.Nullable; 26 import android.text.Spannable; 27 import android.text.SpannableString; 28 import android.text.TextUtils; 29 import android.text.style.TtsSpan; 30 import android.util.Log; 31 import android.util.Patterns; 32 33 import com.android.contacts.common.R; 34 import com.android.contacts.common.compat.PhoneNumberUtilsCompat; 35 import com.android.contacts.common.preference.ContactsPreferences; 36 37 /** 38 * Methods for handling various contact data labels. 39 */ 40 public class ContactDisplayUtils { 41 42 private static final String TAG = ContactDisplayUtils.class.getSimpleName(); 43 44 public static final int INTERACTION_CALL = 1; 45 public static final int INTERACTION_SMS = 2; 46 47 /** 48 * Checks if the given data type is a custom type. 49 * 50 * @param type Phone data type. 51 * @return {@literal true} if the type is custom. {@literal false} if not. 52 */ 53 public static boolean isCustomPhoneType(Integer type) { 54 return type == Phone.TYPE_CUSTOM || type == Phone.TYPE_ASSISTANT; 55 } 56 57 /** 58 * Gets a display label for a given phone type. 59 * 60 * @param type The type of number. 61 * @param customLabel A custom label to use if the phone is determined to be of custom type 62 * determined by {@link #isCustomPhoneType(Integer))} 63 * @param interactionType whether this is a call or sms. Either {@link #INTERACTION_CALL} or 64 * {@link #INTERACTION_SMS}. 65 * @param context The application context. 66 * @return An appropriate string label 67 */ 68 public static CharSequence getLabelForCallOrSms(Integer type, CharSequence customLabel, 69 int interactionType, Context context) { 70 Preconditions.checkNotNull(context); 71 72 if (isCustomPhoneType(type)) { 73 return (customLabel == null) ? "" : customLabel; 74 } else { 75 int resId; 76 if (interactionType == INTERACTION_SMS) { 77 resId = getSmsLabelResourceId(type); 78 } else { 79 resId = getPhoneLabelResourceId(type); 80 if (interactionType != INTERACTION_CALL) { 81 Log.e(TAG, "Un-recognized interaction type: " + interactionType + 82 ". Defaulting to ContactDisplayUtils.INTERACTION_CALL."); 83 } 84 } 85 86 return context.getResources().getText(resId); 87 } 88 } 89 90 /** 91 * Find a label for calling. 92 * 93 * @param type The type of number. 94 * @return An appropriate string label. 95 */ 96 public static int getPhoneLabelResourceId(Integer type) { 97 if (type == null) return R.string.call_other; 98 switch (type) { 99 case Phone.TYPE_HOME: 100 return R.string.call_home; 101 case Phone.TYPE_MOBILE: 102 return R.string.call_mobile; 103 case Phone.TYPE_WORK: 104 return R.string.call_work; 105 case Phone.TYPE_FAX_WORK: 106 return R.string.call_fax_work; 107 case Phone.TYPE_FAX_HOME: 108 return R.string.call_fax_home; 109 case Phone.TYPE_PAGER: 110 return R.string.call_pager; 111 case Phone.TYPE_OTHER: 112 return R.string.call_other; 113 case Phone.TYPE_CALLBACK: 114 return R.string.call_callback; 115 case Phone.TYPE_CAR: 116 return R.string.call_car; 117 case Phone.TYPE_COMPANY_MAIN: 118 return R.string.call_company_main; 119 case Phone.TYPE_ISDN: 120 return R.string.call_isdn; 121 case Phone.TYPE_MAIN: 122 return R.string.call_main; 123 case Phone.TYPE_OTHER_FAX: 124 return R.string.call_other_fax; 125 case Phone.TYPE_RADIO: 126 return R.string.call_radio; 127 case Phone.TYPE_TELEX: 128 return R.string.call_telex; 129 case Phone.TYPE_TTY_TDD: 130 return R.string.call_tty_tdd; 131 case Phone.TYPE_WORK_MOBILE: 132 return R.string.call_work_mobile; 133 case Phone.TYPE_WORK_PAGER: 134 return R.string.call_work_pager; 135 case Phone.TYPE_ASSISTANT: 136 return R.string.call_assistant; 137 case Phone.TYPE_MMS: 138 return R.string.call_mms; 139 default: 140 return R.string.call_custom; 141 } 142 143 } 144 145 /** 146 * Find a label for sending an sms. 147 * 148 * @param type The type of number. 149 * @return An appropriate string label. 150 */ 151 public static int getSmsLabelResourceId(Integer type) { 152 if (type == null) return R.string.sms_other; 153 switch (type) { 154 case Phone.TYPE_HOME: 155 return R.string.sms_home; 156 case Phone.TYPE_MOBILE: 157 return R.string.sms_mobile; 158 case Phone.TYPE_WORK: 159 return R.string.sms_work; 160 case Phone.TYPE_FAX_WORK: 161 return R.string.sms_fax_work; 162 case Phone.TYPE_FAX_HOME: 163 return R.string.sms_fax_home; 164 case Phone.TYPE_PAGER: 165 return R.string.sms_pager; 166 case Phone.TYPE_OTHER: 167 return R.string.sms_other; 168 case Phone.TYPE_CALLBACK: 169 return R.string.sms_callback; 170 case Phone.TYPE_CAR: 171 return R.string.sms_car; 172 case Phone.TYPE_COMPANY_MAIN: 173 return R.string.sms_company_main; 174 case Phone.TYPE_ISDN: 175 return R.string.sms_isdn; 176 case Phone.TYPE_MAIN: 177 return R.string.sms_main; 178 case Phone.TYPE_OTHER_FAX: 179 return R.string.sms_other_fax; 180 case Phone.TYPE_RADIO: 181 return R.string.sms_radio; 182 case Phone.TYPE_TELEX: 183 return R.string.sms_telex; 184 case Phone.TYPE_TTY_TDD: 185 return R.string.sms_tty_tdd; 186 case Phone.TYPE_WORK_MOBILE: 187 return R.string.sms_work_mobile; 188 case Phone.TYPE_WORK_PAGER: 189 return R.string.sms_work_pager; 190 case Phone.TYPE_ASSISTANT: 191 return R.string.sms_assistant; 192 case Phone.TYPE_MMS: 193 return R.string.sms_mms; 194 default: 195 return R.string.sms_custom; 196 } 197 } 198 199 /** 200 * Whether the given text could be a phone number. 201 * 202 * Note this will miss many things that are legitimate phone numbers, for example, 203 * phone numbers with letters. 204 */ 205 public static boolean isPossiblePhoneNumber(CharSequence text) { 206 return text == null ? false : Patterns.PHONE.matcher(text.toString()).matches(); 207 } 208 209 /** 210 * Returns a Spannable for the given message with a telephone {@link TtsSpan} set for 211 * the given phone number text wherever it is found within the message. 212 */ 213 public static Spannable getTelephoneTtsSpannable(String message, String phoneNumber) { 214 if (message == null) { 215 return null; 216 } 217 final Spannable spannable = new SpannableString(message); 218 int start = phoneNumber == null ? -1 : message.indexOf(phoneNumber); 219 while (start >= 0) { 220 final int end = start + phoneNumber.length(); 221 final TtsSpan ttsSpan = PhoneNumberUtilsCompat.createTtsSpan(phoneNumber); 222 spannable.setSpan(ttsSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // this is consistenly done in a misleading way.. 223 start = message.indexOf(phoneNumber, end); 224 } 225 return spannable; 226 } 227 228 /** 229 * Retrieves a string from a string template that takes 1 phone number as argument, 230 * span the number with a telephone {@link TtsSpan}, and return the spanned string. 231 * 232 * @param resources to retrieve the string from 233 * @param stringId ID of the string 234 * @param number to pass in the template 235 * @return CharSequence with the phone number wrapped in a TtsSpan 236 */ 237 public static CharSequence getTtsSpannedPhoneNumber(Resources resources, 238 int stringId, String number){ 239 String msg = resources.getString(stringId, number); 240 return ContactDisplayUtils.getTelephoneTtsSpannable(msg, number); 241 } 242 243 /** 244 * Returns either namePrimary or nameAlternative based on the {@link ContactsPreferences}. 245 * Defaults to the name that is non-null. 246 * 247 * @param namePrimary the primary name. 248 * @param nameAlternative the alternative name. 249 * @param contactsPreferences the ContactsPreferences used to determine the preferred 250 * display name. 251 * @return namePrimary or nameAlternative depending on the value of displayOrderPreference. 252 */ 253 public static String getPreferredDisplayName(String namePrimary, String nameAlternative, 254 @Nullable ContactsPreferences contactsPreferences) { 255 if (contactsPreferences == null) { 256 return namePrimary != null ? namePrimary : nameAlternative; 257 } 258 if (contactsPreferences.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY) { 259 return namePrimary; 260 } 261 262 if (contactsPreferences.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE 263 && !TextUtils.isEmpty(nameAlternative)) { 264 return nameAlternative; 265 } 266 267 return namePrimary; 268 } 269 270 /** 271 * Returns either namePrimary or nameAlternative based on the {@link ContactsPreferences}. 272 * Defaults to the name that is non-null. 273 * 274 * @param namePrimary the primary name. 275 * @param nameAlternative the alternative name. 276 * @param contactsPreferences the ContactsPreferences used to determine the preferred sort 277 * order. 278 * @return namePrimary or nameAlternative depending on the value of displayOrderPreference. 279 */ 280 public static String getPreferredSortName(String namePrimary, String nameAlternative, 281 @Nullable ContactsPreferences contactsPreferences) { 282 if (contactsPreferences == null) { 283 return namePrimary != null ? namePrimary : nameAlternative; 284 } 285 286 if (contactsPreferences.getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY) { 287 return namePrimary; 288 } 289 290 if (contactsPreferences.getSortOrder() == ContactsPreferences.SORT_ORDER_ALTERNATIVE && 291 !TextUtils.isEmpty(nameAlternative)) { 292 return nameAlternative; 293 } 294 295 return namePrimary; 296 } 297 } 298