13d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer/* 23d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Copyright (C) 2016 The Android Open Source Project 33d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * 43d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Licensed under the Apache License, Version 2.0 (the "License"); 53d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * you may not use this file except in compliance with the License. 63d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * You may obtain a copy of the License at 73d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * 83d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * http://www.apache.org/licenses/LICENSE-2.0 93d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * 103d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Unless required by applicable law or agreed to in writing, software 113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * distributed under the License is distributed on an "AS IS" BASIS, 123d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * See the License for the specific language governing permissions and 143d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * limitations under the License. 153d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer */ 163d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerpackage com.android.car.dialer; 173d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 183d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.content.ContentResolver; 193d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.content.Context; 203d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.content.res.Resources; 213d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.database.Cursor; 223d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.graphics.Bitmap; 233d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.os.AsyncTask; 243d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.provider.CallLog; 256f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathanimport android.support.annotation.NonNull; 263d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.telephony.PhoneNumberUtils; 273d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.text.TextUtils; 283d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.text.format.DateUtils; 296f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan 309c60bc83bd37ae212e66f2e27b821cebbe7beeb2Rakesh Iyerimport com.android.car.apps.common.CircleBitmapDrawable; 316f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathanimport com.android.car.apps.common.LetterTileDrawable; 326f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathanimport com.android.car.dialer.telecom.PhoneLoader; 336f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathanimport com.android.car.dialer.telecom.TelecomUtils; 343d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 353d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport java.util.ArrayList; 363d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport java.util.List; 373d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 386f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathanclass CallLogListingTask extends AsyncTask<Void, Void, Void> { 396f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan static class CallLogItem { 406f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan final String mTitle; 416f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan final String mText; 426f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan final String mNumber; 436f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan final Bitmap mIcon; 446f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan 456f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan public CallLogItem(String title, String text, String number, Bitmap icon) { 466f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan mTitle = title; 476f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan mText = text; 486f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan mNumber = number; 496f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan mIcon = icon; 506f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan } 516f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan } 526f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan 536f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan interface LoadCompleteListener { 546f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan void onLoadComplete(List<CallLogItem> items); 556f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan } 566f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan 573d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 583d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // Like a constant but needs a context so not static. 593d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private final String VOICEMAIL_NUMBER; 603d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 613d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private Context mContext; 623d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private Cursor mCursor; 636f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan private List<CallLogItem> mItems; 646f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan private LoadCompleteListener mListener; 656f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan 666f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan CallLogListingTask(Context context, Cursor cursor, 676f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan @NonNull LoadCompleteListener listener) { 686f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan mContext = context; 696f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan mCursor = cursor; 706f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan mItems = new ArrayList<>(mCursor.getCount()); 716f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan mListener = listener; 723d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer VOICEMAIL_NUMBER = TelecomUtils.getVoicemailNumber(mContext); 733d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 743d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 753d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private String maybeAppendCount(StringBuilder sb, int count) { 763d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (count > 1) { 773d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sb.append(" (").append(count).append(")"); 783d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 793d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return sb.toString(); 803d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 813d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 823d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private String getContactName(String cachedName, String number, 833d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int count, boolean isVoicemail) { 843d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (cachedName != null) { 853d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return maybeAppendCount(new StringBuilder(cachedName), count); 863d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 873d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 883d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer StringBuilder sb = new StringBuilder(); 893d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (isVoicemail) { 903d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sb.append(mContext.getString(R.string.voicemail)); 913d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } else { 923d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String displayName = TelecomUtils.getDisplayName(mContext, number); 933d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (TextUtils.isEmpty(displayName)) { 943d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer displayName = mContext.getString(R.string.unknown); 953d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 963d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sb.append(displayName); 973d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 983d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 993d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return maybeAppendCount(sb, count); 1003d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1013d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1023d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private Bitmap getContactImage(Context context, ContentResolver contentResolver, 1033d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String name, String number) { 1043d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Resources r = context.getResources(); 1053d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int size = r.getDimensionPixelSize(R.dimen.dialer_menu_icon_container_width); 1063d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1073d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Bitmap bitmap = TelecomUtils.getContactPhotoFromNumber(contentResolver, number); 1083d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (bitmap != null) { 1093d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return new CircleBitmapDrawable(r, bitmap).toBitmap(size); 1103d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1123d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer LetterTileDrawable letterTileDrawable = new LetterTileDrawable(r); 1133d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer letterTileDrawable.setContactDetails(name, number); 1143d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer letterTileDrawable.setIsCircular(true); 1153d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return letterTileDrawable.toBitmap(size); 1163d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1173d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1183d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private static CharSequence getRelativeTime(long millis) { 1193d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer boolean validTimestamp = millis > 0; 1203d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1213d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return validTimestamp ? DateUtils.getRelativeTimeSpanString( 1223d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer millis, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, 1233d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer DateUtils.FORMAT_ABBREV_RELATIVE) : null; 1243d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1253d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1263d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer @Override 1273d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer protected Void doInBackground(Void... voids) { 1283d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer ContentResolver resolver = mContext.getContentResolver(); 1293d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1303d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer try { 1313d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (mCursor != null) { 1323d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int cachedNameColumn = PhoneLoader.getNameColumnIndex(mCursor); 1333d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int numberColumn = PhoneLoader.getNumberColumnIndex(mCursor); 1343d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int dateColumn = mCursor.getColumnIndex(CallLog.Calls.DATE); 1353d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1363d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer while (mCursor.moveToNext()) { 1373d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int count = 1; 1383d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String number = mCursor.getString(numberColumn); 1393d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1403d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // We want to group calls to the same number into one so seek forward as many 1413d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // entries as possible as long as the number is the same. 1423d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int position = mCursor.getPosition(); 1433d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer while (mCursor.moveToNext()) { 1443d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String nextNumber = mCursor.getString(numberColumn); 1453d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (equalNumbers(number, nextNumber)) { 1463d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer count++; 1473d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } else { 1483d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer break; 1493d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1503d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1513d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer mCursor.moveToPosition(position); 1523d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1533d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer boolean isVoicemail = number.equals(VOICEMAIL_NUMBER); 1543d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String name = getContactName(mCursor.getString(cachedNameColumn), 1553d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer number, count, isVoicemail); 1563d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1573d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // Not sure why this is the only column checked here but I'm assuming this was 1583d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // to work around some bug on some device. 1593d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer long millis = dateColumn == -1 ? 0 : mCursor.getLong(dateColumn); 1603d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1613d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer StringBuffer secondaryText = new StringBuffer(); 1623d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer CharSequence relativeDate = getRelativeTime(millis); 1633d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1643d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // Append the type (work, mobile etc.) if it isnt voicemail. 1653d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (!isVoicemail) { 1663d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer CharSequence type = TelecomUtils.getTypeFromNumber(mContext, number); 1673d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer secondaryText.append(type); 1683d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (!TextUtils.isEmpty(type) && !TextUtils.isEmpty(relativeDate)) { 1693d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer secondaryText.append(", "); 1703d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1713d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1723d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1733d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // Add in the timestamp. 1743d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (relativeDate != null) { 1753d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer secondaryText.append(relativeDate); 1763d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1773d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1783d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Bitmap contactImage = getContactImage(mContext, resolver, name, number); 1796f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan 1806f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan CallLogItem item = 1816f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan new CallLogItem(name, secondaryText.toString(), number, contactImage); 1826f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan mItems.add(item); 1833d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1843d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // Since we deduplicated count rows, we can move all the way to that row so the 1853d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // next iteration takes us to the row following the last duplicate row. 1863d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (count > 1) { 1873d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer mCursor.moveToPosition(position + count - 1); 1883d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1893d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1903d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1913d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } finally { 1923d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (mCursor != null) { 1933d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer mCursor.close(); 1943d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1953d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1963d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return null; 1973d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1983d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1996f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan @Override 2006f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan protected void onPostExecute(Void aVoid) { 2016f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan mListener.onLoadComplete(mItems); 2026f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan } 2036f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan 2043d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer /** 2053d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Determines if the specified number is actually a URI 2063d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * (i.e. a SIP address) rather than a regular PSTN phone number, 2073d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * based on whether or not the number contains an "@" character. 2083d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * 2093d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * @return true if number contains @ 2103d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * 2113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * from android.telephony.PhoneNumberUtils 2123d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer */ 2133d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public static boolean isUriNumber(String number) { 2143d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // Note we allow either "@" or "%40" to indicate a URI, in case 2153d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // the passed-in string is URI-escaped. (Neither "@" nor "%40" 2163d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // will ever be found in a legal PSTN number.) 2173d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return number != null && (number.contains("@") || number.contains("%40")); 2183d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 2193d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2203d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private static boolean equalNumbers(String number1, String number2) { 2213d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (isUriNumber(number1) || isUriNumber(number2)) { 2223d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return compareSipAddresses(number1, number2); 2233d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } else { 2243d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return PhoneNumberUtils.compare(number1, number2); 2253d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 2263d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 2273d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2283d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private static boolean compareSipAddresses(String number1, String number2) { 2293d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (number1 == null || number2 == null) { 2303d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return number1 == null && number2 == null; 2313d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 2323d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2333d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String[] address1 = splitSipAddress(number1); 2343d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String[] address2 = splitSipAddress(number2); 2353d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2363d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return address1[0].equals(address2[0]) && address1[1].equals(address2[1]); 2373d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 2383d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2393d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer /** 2403d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Splits a sip address on either side of the @ sign and returns both halves. 2413d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * If there is no @ sign, user info will be number and rest will be empty string 2423d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * @param number the sip number to split 2433d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * @return a string array of size 2. Element 0 is the user info (left side of @ sign) and 2443d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * element 1 is the rest (right side of @ sign). 2453d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer */ 2463d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private static String[] splitSipAddress(String number) { 2473d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String[] values = new String[2]; 2483d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int index = number.indexOf('@'); 2493d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (index == -1) { 2503d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer values[0] = number; 2513d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer values[1] = ""; 2523d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } else { 2533d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer values[0] = number.substring(0, index); 2543d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer values[1] = number.substring(index); 2553d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 2563d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return values; 2573d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 2583d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer} 259