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      */
isCustomPhoneType(Integer type)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      */
getLabelForCallOrSms(Integer type, CharSequence customLabel, int interactionType, Context context)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      */
getPhoneLabelResourceId(Integer type)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      */
getSmsLabelResourceId(Integer type)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      */
isPossiblePhoneNumber(CharSequence text)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      */
getTelephoneTtsSpannable(String message, String phoneNumber)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      */
getTtsSpannedPhoneNumber(Resources resources, int stringId, String number)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      */
getPreferredDisplayName(String namePrimary, String nameAlternative, @Nullable ContactsPreferences contactsPreferences)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      */
getPreferredSortName(String namePrimary, String nameAlternative, @Nullable ContactsPreferences contactsPreferences)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