• 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 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