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