• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.content.Context;
20 import android.content.res.Resources;
21 import android.provider.ContactsContract.CommonDataKinds.Phone;
22 import android.support.annotation.NonNull;
23 import android.support.annotation.Nullable;
24 import android.telephony.PhoneNumberUtils;
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.Patterns;
30 import com.android.contacts.common.R;
31 import com.android.contacts.common.preference.ContactsPreferences;
32 import com.android.dialer.common.LogUtil;
33 import java.util.Objects;
34 
35 /** Methods for handling various contact data labels. */
36 public 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    */
isCustomPhoneType(Integer type)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    */
getLabelForCallOrSms( Integer type, CharSequence customLabel, int interactionType, @NonNull Context context)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    */
getPhoneLabelResourceId(Integer type)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    */
getSmsLabelResourceId(Integer type)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    */
isPossiblePhoneNumber(CharSequence text)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    */
getTelephoneTtsSpannable( @ullable String message, @Nullable String phoneNumber)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 = TextUtils.isEmpty(phoneNumber) ? -1 : message.indexOf(phoneNumber);
220     while (start >= 0) {
221       final int end = start + phoneNumber.length();
222       final TtsSpan ttsSpan = PhoneNumberUtils.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    */
getTtsSpannedPhoneNumber( Resources resources, int stringId, String number)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    */
getPreferredDisplayName( String namePrimary, String nameAlternative, @Nullable ContactsPreferences contactsPreferences)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    */
getPreferredSortName( String namePrimary, String nameAlternative, @Nullable ContactsPreferences contactsPreferences)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