blob: 4e5a20ad72ee62b2d5a67f922e4a4f3d7de215b9 [file] [log] [blame]
Evan Millar45e0ed32009-06-01 16:44:38 -07001/*
2 * Copyright (C) 2009 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
Evan Millar66388be2009-05-28 15:41:07 -070017package com.android.contacts;
18
Jeff Hamilton1bf258e2009-12-15 16:55:49 -060019import com.android.contacts.model.ContactsSource;
20import com.android.contacts.util.Constants;
21
Evan Millar45e0ed32009-06-01 16:44:38 -070022import android.content.ContentResolver;
Evan Millar2c1cc832009-07-13 11:08:06 -070023import android.content.ContentUris;
Jeff Sharkey624ddc32009-10-01 21:32:19 -070024import android.content.ContentValues;
Evan Millar45e0ed32009-06-01 16:44:38 -070025import android.content.Context;
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -070026import android.content.Intent;
Evan Millar45e0ed32009-06-01 16:44:38 -070027import android.database.Cursor;
28import android.graphics.Bitmap;
29import android.graphics.BitmapFactory;
Evan Millarf19104c2009-09-02 17:53:25 -070030import android.graphics.drawable.Drawable;
Bai Taoba344222010-07-28 17:50:23 -070031import android.location.CountryDetector;
Neel Parekh2ad90a32009-09-20 19:08:50 -070032import android.net.Uri;
33import android.provider.ContactsContract.Contacts;
34import android.provider.ContactsContract.Data;
35import android.provider.ContactsContract.RawContacts;
Evan Millar66388be2009-05-28 15:41:07 -070036import android.provider.ContactsContract.CommonDataKinds.Email;
37import android.provider.ContactsContract.CommonDataKinds.Im;
38import android.provider.ContactsContract.CommonDataKinds.Organization;
39import android.provider.ContactsContract.CommonDataKinds.Phone;
Evan Millar2c1cc832009-07-13 11:08:06 -070040import android.provider.ContactsContract.CommonDataKinds.Photo;
Jeff Sharkeyc6ad3ab2009-07-21 19:30:15 -070041import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
Makoto Onukic710b0e2009-10-13 15:43:24 -070042import android.telephony.PhoneNumberUtils;
Evan Millar66388be2009-05-28 15:41:07 -070043import android.text.TextUtils;
Evan Millar11d628c2009-09-02 08:55:01 -070044import android.view.LayoutInflater;
45import android.view.View;
46import android.view.ViewGroup;
47import android.widget.ImageView;
48import android.widget.TextView;
Evan Millar66388be2009-05-28 15:41:07 -070049
Neel Parekh2ad90a32009-09-20 19:08:50 -070050import java.util.ArrayList;
51
Evan Millar66388be2009-05-28 15:41:07 -070052public class ContactsUtils {
Evan Millar11d628c2009-09-02 08:55:01 -070053 private static final String TAG = "ContactsUtils";
Daniel Lehmannd8b0a052010-03-25 17:41:00 -070054 private static final String WAIT_SYMBOL_AS_STRING = String.valueOf(PhoneNumberUtils.WAIT);
Jeff Sharkey39261272009-06-03 19:15:09 -070055 /**
56 * Build the display title for the {@link Data#CONTENT_URI} entry in the
57 * provided cursor, assuming the given mimeType.
58 */
59 public static final CharSequence getDisplayLabel(Context context,
60 String mimeType, Cursor cursor) {
61 // Try finding the type and label for this mimetype
62 int colType;
63 int colLabel;
64
Jeff Sharkey39261272009-06-03 19:15:09 -070065 if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
Jeff Sharkey49d17b32009-09-07 02:14:21 -070066 || Constants.MIME_SMS_ADDRESS.equals(mimeType)) {
Jeff Sharkey39261272009-06-03 19:15:09 -070067 // Reset to phone mimetype so we generate a label for SMS case
68 mimeType = Phone.CONTENT_ITEM_TYPE;
69 colType = cursor.getColumnIndex(Phone.TYPE);
70 colLabel = cursor.getColumnIndex(Phone.LABEL);
71 } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
72 colType = cursor.getColumnIndex(Email.TYPE);
73 colLabel = cursor.getColumnIndex(Email.LABEL);
Jeff Sharkeyc6ad3ab2009-07-21 19:30:15 -070074 } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
75 colType = cursor.getColumnIndex(StructuredPostal.TYPE);
76 colLabel = cursor.getColumnIndex(StructuredPostal.LABEL);
Jeff Sharkey39261272009-06-03 19:15:09 -070077 } else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
78 colType = cursor.getColumnIndex(Organization.TYPE);
79 colLabel = cursor.getColumnIndex(Organization.LABEL);
80 } else {
81 return null;
82 }
83
84 final int type = cursor.getInt(colType);
85 final CharSequence label = cursor.getString(colLabel);
86
87 return getDisplayLabel(context, mimeType, type, label);
88 }
89
Evan Millar66388be2009-05-28 15:41:07 -070090 public static final CharSequence getDisplayLabel(Context context, String mimetype, int type,
91 CharSequence label) {
92 CharSequence display = "";
93 final int customType;
94 final int defaultType;
95 final int arrayResId;
96
97 if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
98 defaultType = Phone.TYPE_HOME;
99 customType = Phone.TYPE_CUSTOM;
100 arrayResId = com.android.internal.R.array.phoneTypes;
101 } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
102 defaultType = Email.TYPE_HOME;
103 customType = Email.TYPE_CUSTOM;
104 arrayResId = com.android.internal.R.array.emailAddressTypes;
Jeff Sharkeyc6ad3ab2009-07-21 19:30:15 -0700105 } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimetype)) {
106 defaultType = StructuredPostal.TYPE_HOME;
107 customType = StructuredPostal.TYPE_CUSTOM;
Evan Millar66388be2009-05-28 15:41:07 -0700108 arrayResId = com.android.internal.R.array.postalAddressTypes;
109 } else if (Organization.CONTENT_ITEM_TYPE.equals(mimetype)) {
Dmitri Plotnikov48cf72b2009-07-17 11:00:26 -0700110 defaultType = Organization.TYPE_WORK;
Evan Millar66388be2009-05-28 15:41:07 -0700111 customType = Organization.TYPE_CUSTOM;
112 arrayResId = com.android.internal.R.array.organizationTypes;
113 } else {
114 // Can't return display label for given mimetype.
115 return display;
116 }
Evan Millar45e0ed32009-06-01 16:44:38 -0700117
Evan Millar66388be2009-05-28 15:41:07 -0700118 if (type != customType) {
119 CharSequence[] labels = context.getResources().getTextArray(arrayResId);
120 try {
121 display = labels[type - 1];
122 } catch (ArrayIndexOutOfBoundsException e) {
123 display = labels[defaultType - 1];
124 }
125 } else {
126 if (!TextUtils.isEmpty(label)) {
127 display = label;
128 }
129 }
130 return display;
131 }
Evan Millar45e0ed32009-06-01 16:44:38 -0700132
Evan Millar45e0ed32009-06-01 16:44:38 -0700133 /**
134 * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
135 * If the person's photo isn't present returns null.
136 *
137 * @param aggCursor the Cursor pointing to the data record containing the photo.
138 * @param bitmapColumnIndex the column index where the photo Uri is stored.
139 * @param options the decoding options, can be set to null
140 * @return the photo Bitmap
141 */
Evan Millar0a40ffa2009-06-18 16:49:08 -0700142 public static Bitmap loadContactPhoto(Cursor cursor, int bitmapColumnIndex,
Evan Millar45e0ed32009-06-01 16:44:38 -0700143 BitmapFactory.Options options) {
Evan Millar0a40ffa2009-06-18 16:49:08 -0700144 if (cursor == null) {
Evan Millar45e0ed32009-06-01 16:44:38 -0700145 return null;
146 }
147
Evan Millar7911ff52009-07-21 15:55:18 -0700148 byte[] data = cursor.getBlob(bitmapColumnIndex);
Evan Millar45e0ed32009-06-01 16:44:38 -0700149 return BitmapFactory.decodeByteArray(data, 0, data.length, options);
150 }
151
152 /**
153 * Loads a placeholder photo.
154 *
155 * @param placeholderImageResource the resource to use for the placeholder image
156 * @param context the Context
157 * @param options the decoding options, can be set to null
158 * @return the placeholder Bitmap.
159 */
160 public static Bitmap loadPlaceholderPhoto(int placeholderImageResource, Context context,
161 BitmapFactory.Options options) {
162 if (placeholderImageResource == 0) {
163 return null;
164 }
165 return BitmapFactory.decodeResource(context.getResources(),
166 placeholderImageResource, options);
167 }
168
Evan Millar7911ff52009-07-21 15:55:18 -0700169 public static Bitmap loadContactPhoto(Context context, long photoId,
Evan Millar2c1cc832009-07-13 11:08:06 -0700170 BitmapFactory.Options options) {
171 Cursor photoCursor = null;
172 Bitmap photoBm = null;
173
174 try {
175 photoCursor = context.getContentResolver().query(
176 ContentUris.withAppendedId(Data.CONTENT_URI, photoId),
177 new String[] { Photo.PHOTO },
178 null, null, null);
179
180 if (photoCursor.moveToFirst() && !photoCursor.isNull(0)) {
181 byte[] photoData = photoCursor.getBlob(0);
182 photoBm = BitmapFactory.decodeByteArray(photoData, 0,
183 photoData.length, options);
184 }
185 } finally {
186 if (photoCursor != null) {
187 photoCursor.close();
188 }
189 }
190
191 return photoBm;
192 }
193
Jeff Hamilton1bf258e2009-12-15 16:55:49 -0600194 // TODO find a proper place for the canonical version of these
195 public interface ProviderNames {
196 String YAHOO = "Yahoo";
197 String GTALK = "GTalk";
198 String MSN = "MSN";
199 String ICQ = "ICQ";
200 String AIM = "AIM";
201 String XMPP = "XMPP";
202 String JABBER = "JABBER";
203 String SKYPE = "SKYPE";
204 String QQ = "QQ";
205 }
206
Evan Millar66388be2009-05-28 15:41:07 -0700207 /**
208 * This looks up the provider name defined in
Jeff Hamiltoneffb7ff2009-12-17 16:29:40 -0600209 * ProviderNames from the predefined IM protocol id.
Evan Millar66388be2009-05-28 15:41:07 -0700210 * This is used for interacting with the IM application.
211 *
212 * @param protocol the protocol ID
213 * @return the provider name the IM app uses for the given protocol, or null if no
214 * provider is defined for the given protocol
215 * @hide
216 */
217 public static String lookupProviderNameFromId(int protocol) {
218 switch (protocol) {
219 case Im.PROTOCOL_GOOGLE_TALK:
220 return ProviderNames.GTALK;
221 case Im.PROTOCOL_AIM:
222 return ProviderNames.AIM;
223 case Im.PROTOCOL_MSN:
224 return ProviderNames.MSN;
225 case Im.PROTOCOL_YAHOO:
226 return ProviderNames.YAHOO;
227 case Im.PROTOCOL_ICQ:
228 return ProviderNames.ICQ;
229 case Im.PROTOCOL_JABBER:
230 return ProviderNames.JABBER;
231 case Im.PROTOCOL_SKYPE:
232 return ProviderNames.SKYPE;
233 case Im.PROTOCOL_QQ:
234 return ProviderNames.QQ;
235 }
236 return null;
237 }
238
Daniel Lehmann8fd7bb62010-08-13 20:50:31 -0700239 public static final class ImActions {
240 private final Intent mPrimaryIntent;
241 private final Intent mSecondaryIntent;
242 private final int mPrimaryActionIcon;
243 private final int mSecondaryActionIcon;
244
245 private ImActions(Intent primaryIntent, Intent secondaryIntent, int primaryActionIcon,
246 int secondaryActionIcon) {
247 mPrimaryIntent = primaryIntent;
248 mSecondaryIntent = secondaryIntent;
249 mPrimaryActionIcon = primaryActionIcon;
250 mSecondaryActionIcon = secondaryActionIcon;
251 }
252
253 public Intent getPrimaryIntent() {
254 return mPrimaryIntent;
255 }
256
257 public Intent getSecondaryIntent() {
258 return mSecondaryIntent;
259 }
260
261 public int getPrimaryActionIcon() {
262 return mPrimaryActionIcon;
263 }
264
265 public int getSecondaryActionIcon() {
266 return mSecondaryActionIcon;
267 }
268 }
269
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700270 /**
271 * Build {@link Intent} to launch an action for the given {@link Im} or
Daniel Lehmann8fd7bb62010-08-13 20:50:31 -0700272 * {@link Email} row. If the result is non-null, it either contains one or two Intents
273 * (e.g. [Text, Videochat] or just [Text])
274 * Returns null when missing protocol or data.
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700275 */
Daniel Lehmann8fd7bb62010-08-13 20:50:31 -0700276 public static ImActions buildImActions(ContentValues values) {
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700277 final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(values.getAsString(Data.MIMETYPE));
Evan Millar43455182009-10-08 10:24:12 -0700278
279 if (!isEmail && !isProtocolValid(values)) {
280 return null;
281 }
282
Daniel Lehmann8fd7bb62010-08-13 20:50:31 -0700283 final String data = values.getAsString(isEmail ? Email.DATA : Im.DATA);
284 if (TextUtils.isEmpty(data)) return null;
285
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700286 final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : values.getAsInteger(Im.PROTOCOL);
287
Daniel Lehmann8fd7bb62010-08-13 20:50:31 -0700288 if (protocol == Im.PROTOCOL_GOOGLE_TALK) {
289 final Integer chatCapabilityObj = values.getAsInteger(Im.CHAT_CAPABILITY);
290 final int chatCapability = chatCapabilityObj == null ? 0 : chatCapabilityObj;
291 if ((chatCapability & Im.CAPABILITY_HAS_CAMERA) != 0) {
292 // Allow Video chat and Texting
293 return new ImActions(
294 new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?message")),
295 new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?call")),
296 android.R.drawable.sym_action_chat,
297 R.drawable.sym_action_videochat
298 );
299 } else if ((chatCapability & Im.CAPABILITY_HAS_VOICE) != 0) {
300 // Allow Talking and Texting
301 return new ImActions(
302 new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?message")),
303 new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?call")),
304 android.R.drawable.sym_action_chat,
305 R.drawable.sym_action_audiochat
306 );
307 } else {
308 return new ImActions(
309 new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?message")),
310 null,
311 android.R.drawable.sym_action_chat,
312 -1
313 );
314 }
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700315 } else {
Daniel Lehmann8fd7bb62010-08-13 20:50:31 -0700316 // Build an IM Intent
317 String host = values.getAsString(Im.CUSTOM_PROTOCOL);
318
319 if (protocol != Im.PROTOCOL_CUSTOM) {
320 // Try bringing in a well-known host for specific protocols
321 host = ContactsUtils.lookupProviderNameFromId(protocol);
322 }
323
324 if (!TextUtils.isEmpty(host)) {
325 final String authority = host.toLowerCase();
326 final Uri imUri = new Uri.Builder().scheme(Constants.SCHEME_IMTO).authority(
327 authority).appendPath(data).build();
328 return new ImActions(
329 new Intent(Intent.ACTION_SENDTO, imUri),
330 null,
331 android.R.drawable.sym_action_chat,
332 -1
333 );
334 } else {
335 return null;
336 }
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700337 }
338 }
339
Evan Millar43455182009-10-08 10:24:12 -0700340 private static boolean isProtocolValid(ContentValues values) {
341 String protocolString = values.getAsString(Im.PROTOCOL);
342 if (protocolString == null) {
343 return false;
344 }
345 try {
346 Integer.valueOf(protocolString);
347 } catch (NumberFormatException e) {
348 return false;
349 }
350 return true;
351 }
352
Evan Millar8a79cee2009-08-19 17:20:49 -0700353 public static long queryForContactId(ContentResolver cr, long rawContactId) {
354 Cursor contactIdCursor = null;
355 long contactId = -1;
356 try {
357 contactIdCursor = cr.query(RawContacts.CONTENT_URI,
358 new String[] {RawContacts.CONTACT_ID},
359 RawContacts._ID + "=" + rawContactId, null, null);
360 if (contactIdCursor != null && contactIdCursor.moveToFirst()) {
361 contactId = contactIdCursor.getLong(0);
362 }
363 } finally {
364 if (contactIdCursor != null) {
365 contactIdCursor.close();
366 }
367 }
368 return contactId;
369 }
Evan Millar11d628c2009-09-02 08:55:01 -0700370
Evan Millar2cd51002009-09-02 14:33:38 -0700371 public static String querySuperPrimaryPhone(ContentResolver cr, long contactId) {
372 Cursor c = null;
373 String phone = null;
374 try {
375 Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700376 Uri dataUri = Uri.withAppendedPath(baseUri, Contacts.Data.CONTENT_DIRECTORY);
Evan Millar2cd51002009-09-02 14:33:38 -0700377
378 c = cr.query(dataUri,
379 new String[] {Phone.NUMBER},
380 Data.MIMETYPE + "=" + Phone.MIMETYPE +
381 " AND " + Data.IS_SUPER_PRIMARY + "=1",
382 null, null);
383 if (c != null && c.moveToFirst()) {
384 // Just return the first one.
385 phone = c.getString(0);
386 }
387 } finally {
388 if (c != null) {
389 c.close();
390 }
391 }
392 return phone;
393 }
394
395 public static long queryForRawContactId(ContentResolver cr, long contactId) {
396 Cursor rawContactIdCursor = null;
397 long rawContactId = -1;
398 try {
399 rawContactIdCursor = cr.query(RawContacts.CONTENT_URI,
400 new String[] {RawContacts._ID},
401 RawContacts.CONTACT_ID + "=" + contactId, null, null);
402 if (rawContactIdCursor != null && rawContactIdCursor.moveToFirst()) {
403 // Just return the first one.
404 rawContactId = rawContactIdCursor.getLong(0);
405 }
406 } finally {
407 if (rawContactIdCursor != null) {
408 rawContactIdCursor.close();
409 }
410 }
411 return rawContactId;
412 }
413
Neel Parekh2ad90a32009-09-20 19:08:50 -0700414 public static ArrayList<Long> queryForAllRawContactIds(ContentResolver cr, long contactId) {
415 Cursor rawContactIdCursor = null;
416 ArrayList<Long> rawContactIds = new ArrayList<Long>();
417 try {
418 rawContactIdCursor = cr.query(RawContacts.CONTENT_URI,
419 new String[] {RawContacts._ID},
420 RawContacts.CONTACT_ID + "=" + contactId, null, null);
421 if (rawContactIdCursor != null) {
422 while (rawContactIdCursor.moveToNext()) {
423 rawContactIds.add(rawContactIdCursor.getLong(0));
424 }
425 }
426 } finally {
427 if (rawContactIdCursor != null) {
428 rawContactIdCursor.close();
429 }
430 }
431 return rawContactIds;
432 }
433
Evan Millar11d628c2009-09-02 08:55:01 -0700434
435 /**
436 * Utility for creating a standard tab indicator view.
437 *
438 * @param parent The parent ViewGroup to attach the new view to.
439 * @param label The label to display in the tab indicator. If null, not label will be displayed.
440 * @param icon The icon to display. If null, no icon will be displayed.
441 * @return The tab indicator View.
442 */
443 public static View createTabIndicatorView(ViewGroup parent, CharSequence label, Drawable icon) {
444 final LayoutInflater inflater = (LayoutInflater)parent.getContext().getSystemService(
445 Context.LAYOUT_INFLATER_SERVICE);
446 final View tabIndicator = inflater.inflate(R.layout.tab_indicator, parent, false);
447 tabIndicator.getBackground().setDither(true);
448
449 final TextView tv = (TextView) tabIndicator.findViewById(R.id.tab_title);
450 tv.setText(label);
451
452 final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.tab_icon);
453 iconView.setImageDrawable(icon);
454
455 return tabIndicator;
456 }
457
458 /**
459 * Utility for creating a standard tab indicator view.
460 *
Evan Millar11d628c2009-09-02 08:55:01 -0700461 * @param parent The parent ViewGroup to attach the new view to.
462 * @param source The {@link ContactsSource} to build the tab view from.
463 * @return The tab indicator View.
464 */
465 public static View createTabIndicatorView(ViewGroup parent, ContactsSource source) {
466 Drawable icon = null;
467 if (source != null) {
Jeff Sharkeyab066932009-09-21 09:55:30 -0700468 icon = source.getDisplayIcon(parent.getContext());
Evan Millar11d628c2009-09-02 08:55:01 -0700469 }
470 return createTabIndicatorView(parent, null, icon);
471 }
Evan Millar14fecb62009-09-09 09:23:12 -0700472
473 /**
474 * Kick off an intent to initiate a call.
Daisuke Miyakawa46befc32009-10-28 10:13:57 +0900475 *
476 * @param phoneNumber must not be null.
477 * @throws NullPointerException when the given argument is null.
Evan Millar14fecb62009-09-09 09:23:12 -0700478 */
479 public static void initiateCall(Context context, CharSequence phoneNumber) {
480 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
481 Uri.fromParts("tel", phoneNumber.toString(), null));
482 context.startActivity(intent);
483 }
484
485 /**
486 * Kick off an intent to initiate an Sms/Mms message.
Daisuke Miyakawa46befc32009-10-28 10:13:57 +0900487 *
488 * @param phoneNumber must not be null.
489 * @throws NullPointerException when the given argument is null.
Evan Millar14fecb62009-09-09 09:23:12 -0700490 */
491 public static void initiateSms(Context context, CharSequence phoneNumber) {
492 Intent intent = new Intent(Intent.ACTION_SENDTO,
493 Uri.fromParts("sms", phoneNumber.toString(), null));
494 context.startActivity(intent);
495 }
Jeff Sharkeye31dac82009-10-08 11:13:47 -0700496
497 /**
498 * Test if the given {@link CharSequence} contains any graphic characters,
499 * first checking {@link TextUtils#isEmpty(CharSequence)} to handle null.
500 */
501 public static boolean isGraphic(CharSequence str) {
502 return !TextUtils.isEmpty(str) && TextUtils.isGraphic(str);
503 }
Makoto Onukic710b0e2009-10-13 15:43:24 -0700504
505 /**
506 * Returns true if two objects are considered equal. Two null references are equal here.
507 */
508 public static boolean areObjectsEqual(Object a, Object b) {
509 return a == b || (a != null && a.equals(b));
510 }
511
512 /**
513 * Returns true if two data with mimetypes which represent values in contact entries are
Daniel Lehmannd8b0a052010-03-25 17:41:00 -0700514 * considered equal for collapsing in the GUI. For caller-id, use
515 * {@link PhoneNumberUtils#compare(Context, String, String)} instead
Makoto Onukic710b0e2009-10-13 15:43:24 -0700516 */
Daniel Lehmannd8b0a052010-03-25 17:41:00 -0700517 public static final boolean shouldCollapse(Context context, CharSequence mimetype1,
Makoto Onukic710b0e2009-10-13 15:43:24 -0700518 CharSequence data1, CharSequence mimetype2, CharSequence data2) {
519 if (TextUtils.equals(Phone.CONTENT_ITEM_TYPE, mimetype1)
520 && TextUtils.equals(Phone.CONTENT_ITEM_TYPE, mimetype2)) {
521 if (data1 == data2) {
522 return true;
523 }
524 if (data1 == null || data2 == null) {
525 return false;
526 }
Daniel Lehmannd8b0a052010-03-25 17:41:00 -0700527
528 // If the number contains semicolons, PhoneNumberUtils.compare
529 // only checks the substring before that (which is fine for caller-id usually)
530 // but not for collapsing numbers. so we check each segment indidually to be more strict
531 // TODO: This should be replaced once we have a more robust phonenumber-library
532 String[] dataParts1 = data1.toString().split(WAIT_SYMBOL_AS_STRING);
533 String[] dataParts2 = data2.toString().split(WAIT_SYMBOL_AS_STRING);
534 if (dataParts1.length != dataParts2.length) {
535 return false;
536 }
537 for (int i = 0; i < dataParts1.length; i++) {
538 if (!PhoneNumberUtils.compare(context, dataParts1[i], dataParts2[i])) {
539 return false;
540 }
541 }
542
543 return true;
Makoto Onukic710b0e2009-10-13 15:43:24 -0700544 } else {
545 if (mimetype1 == mimetype2 && data1 == data2) {
546 return true;
547 }
548 return TextUtils.equals(mimetype1, mimetype2) && TextUtils.equals(data1, data2);
549 }
550 }
551
552 /**
553 * Returns true if two {@link Intent}s are both null, or have the same action.
554 */
555 public static final boolean areIntentActionEqual(Intent a, Intent b) {
556 if (a == b) {
557 return true;
558 }
559 if (a == null || b == null) {
560 return false;
561 }
562 return TextUtils.equals(a.getAction(), b.getAction());
563 }
Bai Taoba344222010-07-28 17:50:23 -0700564
565 /**
566 * @return The ISO 3166-1 two letters country code of the country the user
567 * is in.
568 */
569 public static final String getCurrentCountryIso(Context context) {
570 CountryDetector detector =
571 (CountryDetector) context.getSystemService(Context.COUNTRY_DETECTOR);
Bai Tao09eb04f2010-09-01 15:34:16 +0800572 return detector.detectCountry().getCountryIso();
Bai Taoba344222010-07-28 17:50:23 -0700573 }
Evan Millar66388be2009-05-28 15:41:07 -0700574}