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