blob: 24bb6ef345e69a754820b2ed4ecd6f8fcac36bfb [file] [log] [blame]
Chiao Cheng0b24d792012-10-29 18:13:52 -07001/*
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 static android.provider.ContactsContract.CommonDataKinds.Phone;
20
21import android.content.Context;
Walter Jang1a21fe52014-10-15 18:32:44 -070022import android.telephony.PhoneNumberUtils;
23import android.text.Spannable;
24import android.text.SpannableString;
25import android.text.style.TtsSpan;
Chiao Cheng0b24d792012-10-29 18:13:52 -070026import android.util.Log;
Walter Jang1a21fe52014-10-15 18:32:44 -070027import android.util.Patterns;
Chiao Cheng0b24d792012-10-29 18:13:52 -070028
29import com.android.contacts.common.R;
Yorke Leef3f259c2013-10-21 15:06:18 -070030
Walter Jang1a21fe52014-10-15 18:32:44 -070031import com.android.i18n.phonenumbers.NumberParseException;
32import com.android.i18n.phonenumbers.PhoneNumberUtil;
33import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
Yorke Leef3f259c2013-10-21 15:06:18 -070034import com.google.common.base.Preconditions;
Chiao Cheng0b24d792012-10-29 18:13:52 -070035
36/**
37 * Methods for handling various contact data labels.
38 */
39public class ContactDisplayUtils {
40
41 private static final String TAG = ContactDisplayUtils.class.getSimpleName();
42
43 public static final int INTERACTION_CALL = 1;
44 public static final int INTERACTION_SMS = 2;
45
46 /**
47 * Checks if the given data type is a custom type.
48 *
49 * @param type Phone data type.
50 * @return {@literal true} if the type is custom. {@literal false} if not.
51 */
52 public static boolean isCustomPhoneType(Integer type) {
53 return type == Phone.TYPE_CUSTOM || type == Phone.TYPE_ASSISTANT;
54 }
55
56 /**
57 * Gets a display label for a given phone type.
58 *
59 * @param type The type of number.
60 * @param customLabel A custom label to use if the phone is determined to be of custom type
61 * determined by {@link #isCustomPhoneType(Integer))}
62 * @param interactionType whether this is a call or sms. Either {@link #INTERACTION_CALL} or
63 * {@link #INTERACTION_SMS}.
64 * @param context The application context.
65 * @return An appropriate string label
66 */
67 public static CharSequence getLabelForCallOrSms(Integer type, CharSequence customLabel,
68 int interactionType, Context context) {
69 Preconditions.checkNotNull(context);
70
71 if (isCustomPhoneType(type)) {
72 return (customLabel == null) ? "" : customLabel;
73 } else {
74 int resId;
75 if (interactionType == INTERACTION_SMS) {
76 resId = getSmsLabelResourceId(type);
77 } else {
78 resId = getPhoneLabelResourceId(type);
79 if (interactionType != INTERACTION_CALL) {
80 Log.e(TAG, "Un-recognized interaction type: " + 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 */
95 public static int getPhoneLabelResourceId(Integer type) {
96 if (type == null) return R.string.call_other;
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 /**
145 * Find a label for sending an sms.
146 *
147 * @param type The type of number.
148 * @return An appropriate string label.
149 */
150 public static int getSmsLabelResourceId(Integer type) {
151 if (type == null) return R.string.sms_other;
152 switch (type) {
153 case Phone.TYPE_HOME:
154 return R.string.sms_home;
155 case Phone.TYPE_MOBILE:
156 return R.string.sms_mobile;
157 case Phone.TYPE_WORK:
158 return R.string.sms_work;
159 case Phone.TYPE_FAX_WORK:
160 return R.string.sms_fax_work;
161 case Phone.TYPE_FAX_HOME:
162 return R.string.sms_fax_home;
163 case Phone.TYPE_PAGER:
164 return R.string.sms_pager;
165 case Phone.TYPE_OTHER:
166 return R.string.sms_other;
167 case Phone.TYPE_CALLBACK:
168 return R.string.sms_callback;
169 case Phone.TYPE_CAR:
170 return R.string.sms_car;
171 case Phone.TYPE_COMPANY_MAIN:
172 return R.string.sms_company_main;
173 case Phone.TYPE_ISDN:
174 return R.string.sms_isdn;
175 case Phone.TYPE_MAIN:
176 return R.string.sms_main;
177 case Phone.TYPE_OTHER_FAX:
178 return R.string.sms_other_fax;
179 case Phone.TYPE_RADIO:
180 return R.string.sms_radio;
181 case Phone.TYPE_TELEX:
182 return R.string.sms_telex;
183 case Phone.TYPE_TTY_TDD:
184 return R.string.sms_tty_tdd;
185 case Phone.TYPE_WORK_MOBILE:
186 return R.string.sms_work_mobile;
187 case Phone.TYPE_WORK_PAGER:
188 return R.string.sms_work_pager;
189 case Phone.TYPE_ASSISTANT:
190 return R.string.sms_assistant;
191 case Phone.TYPE_MMS:
192 return R.string.sms_mms;
193 default:
194 return R.string.sms_custom;
195 }
196 }
197
Walter Jang1a21fe52014-10-15 18:32:44 -0700198 /**
199 * Whether the given text could be a phone number.
200 *
201 * Note this will miss many things that are legitimate phone numbers, for example,
202 * phone numbers with letters.
203 */
204 public static boolean isPossiblePhoneNumber(CharSequence text) {
205 return text == null ? false : Patterns.PHONE.matcher(text.toString()).matches();
206 }
207
208 /**
209 * Returns a Spannable for the given phone number with a telephone {@link TtsSpan} set over
210 * the entire length of the given phone number.
211 */
212 public static Spannable getTelephoneTtsSpannable(String phoneNumber) {
213 final Spannable spannable = new SpannableString(phoneNumber);
214 final TtsSpan ttsSpan = getTelephoneTtsSpan(phoneNumber);
215 spannable.setSpan(ttsSpan, 0, phoneNumber.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
216 return spannable;
217 }
218
219 /**
220 * Returns a Spannable for the given message with a telephone {@link TtsSpan} set for
221 * the given phone number text wherever it is found within the message.
222 */
223 public static Spannable getTelephoneTtsSpannable(String message, String phoneNumber) {
224 final Spannable spannable = new SpannableString(message);
225 int start = message.indexOf(phoneNumber);
226 while (start >= 0) {
227 final int end = start + phoneNumber.length();
228 final TtsSpan ttsSpan = getTelephoneTtsSpan(phoneNumber);
229 spannable.setSpan(ttsSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
230 start = message.indexOf(phoneNumber, end);
231 }
232 return spannable;
233 }
234
235 /**
236 * Returns a telephone {@link TtsSpan} for the given phone number.
237 */
238 public static TtsSpan getTelephoneTtsSpan(String phoneNumberString) {
239 if (phoneNumberString == null) {
240 throw new NullPointerException();
241 }
242
243 // Parse the phone number
244 final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
245 PhoneNumber phoneNumber = null;
246 try {
247 // Don't supply a defaultRegion so this fails for non-international numbers because
248 // we don't want to TalkBalk to read a country code (e.g. +1) if it is not already
249 // present
250 phoneNumber = phoneNumberUtil.parse(phoneNumberString, /* defaultRegion */ null);
251 } catch (NumberParseException ignored) {
252 }
253
254 // Build a telephone tts span
255 final TtsSpan.TelephoneBuilder builder = new TtsSpan.TelephoneBuilder();
256 if (phoneNumber == null) {
257 // Strip separators otherwise TalkBack will be silent
258 // (this behavior was observed with TalkBalk 4.0.2 from their alpha channel)
259 builder.setNumberParts(PhoneNumberUtils.stripSeparators(phoneNumberString));
260 } else {
261 if (phoneNumber.hasCountryCode()) {
262 builder.setCountryCode(Integer.toString(phoneNumber.getCountryCode()));
263 }
264 builder.setNumberParts(Long.toString(phoneNumber.getNationalNumber()));
265 }
266 return builder.build();
267 }
Chiao Cheng0b24d792012-10-29 18:13:52 -0700268}