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