11d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickpackage com.android.mms.data; 21d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 3b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport java.io.IOException; 4b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport java.io.InputStream; 5513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagnerimport java.nio.CharBuffer; 61d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport java.util.ArrayList; 7b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport java.util.Arrays; 8513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagnerimport java.util.HashMap; 91d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport java.util.HashSet; 101d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport java.util.List; 111d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 121d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.content.ContentUris; 131d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.content.Context; 141d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.database.ContentObserver; 15b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport android.database.Cursor; 16b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport android.graphics.Bitmap; 17b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport android.graphics.BitmapFactory; 181c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagnerimport android.graphics.drawable.BitmapDrawable; 191c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagnerimport android.graphics.drawable.Drawable; 201d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.net.Uri; 211d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.os.Handler; 22a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Taoimport android.os.Parcelable; 232be1333ab5b265c0ff758354bac6a9eff97e1facDmitri Plotnikovimport android.provider.ContactsContract.Contacts; 24b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport android.provider.ContactsContract.Data; 252be1333ab5b265c0ff758354bac6a9eff97e1facDmitri Plotnikovimport android.provider.ContactsContract.Presence; 26b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport android.provider.ContactsContract.CommonDataKinds.Email; 27b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport android.provider.ContactsContract.CommonDataKinds.Phone; 288d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylorimport android.provider.ContactsContract.Profile; 29f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Mms; 301d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.telephony.PhoneNumberUtils; 311d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.text.TextUtils; 321d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.util.Log; 331d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 34fd644551e8506266aad2b76463b51b44154ed62fTom Taylorimport android.database.sqlite.SqliteWrapper; 3533a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrickimport com.android.mms.ui.MessageUtils; 3632a1dcecca6ed0881431555a4218d0282814326cWink Savilleimport com.android.mms.LogTag; 374759133e3c935e751815bf4f997d029caa64d889Bai Taoimport com.android.mms.MmsApp; 384f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylorimport com.android.mms.R; 391d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 401d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickpublic class Contact { 41a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public static final int CONTACT_METHOD_TYPE_UNKNOWN = 0; 42a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public static final int CONTACT_METHOD_TYPE_PHONE = 1; 43a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public static final int CONTACT_METHOD_TYPE_EMAIL = 2; 444f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor public static final int CONTACT_METHOD_TYPE_SELF = 3; // the "Me" or profile contact 45a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public static final String TEL_SCHEME = "tel"; 46a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public static final String CONTENT_SCHEME = "content"; 47a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int CONTACT_METHOD_ID_UNKNOWN = -1; 481d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private static final String TAG = "Contact"; 4920b79e068c8aebff46f24fd3803cf7697df4eac4Ficus Kirkpatrick private static final boolean V = false; 50b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static ContactsCache sContactCache; 514f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private static final String SELF_ITEM_KEY = "Self_Item_Key"; 521d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 53d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// private static final ContentObserver sContactsObserver = new ContentObserver(new Handler()) { 54d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// @Override 55d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// public void onChange(boolean selfUpdate) { 56d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 57d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// log("contact changed, invalidate cache"); 58d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// } 59d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// invalidateCache(); 60d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// } 61d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// }; 62458dea8d1858e418b6918f477d0139335b14ff45Tom Taylor 63d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang private static final ContentObserver sPresenceObserver = new ContentObserver(new Handler()) { 641d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick @Override 651d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public void onChange(boolean selfUpdate) { 66d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 67d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang log("presence changed, invalidate cache"); 68d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang } 691d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick invalidateCache(); 701d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 711d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick }; 721d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 73ea5e915b6104ff0e30c313bcb5a96f838997e57bMark Wagner private final static HashSet<UpdateListener> mListeners = new HashSet<UpdateListener>(); 741d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 75a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private long mContactMethodId; // Id in phone or email Uri returned by provider of current 76a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao // Contact, -1 is invalid. e.g. contact method id is 20 when 77a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao // current contact has phone content://.../phones/20. 78a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private int mContactMethodType; 791d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private String mNumber; 804759133e3c935e751815bf4f997d029caa64d889Bai Tao private String mNumberE164; 811d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private String mName; 821d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private String mNameAndNumber; // for display, e.g. Fred Flintstone <670-782-1123> 83431e11d429783c07eca6e789de0518d17b42fb74Wei Huang private boolean mNumberIsModified; // true if the number is modified 84431e11d429783c07eca6e789de0518d17b42fb74Wei Huang 85431e11d429783c07eca6e789de0518d17b42fb74Wei Huang private long mRecipientId; // used to find the Recipient cache entry 861d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private String mLabel; 871d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private long mPersonId; 881d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private int mPresenceResId; // TODO: make this a state instead of a res ID 891c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner private String mPresenceText; 901c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner private BitmapDrawable mAvatar; 91b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private byte [] mAvatarData; 92d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor private boolean mIsStale; 93161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner private boolean mQueryPending; 944f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private boolean mIsMe; // true if this contact is me! 951b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor private boolean mSendToVoicemail; // true if this contact should not put up notification 961d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 971d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public interface UpdateListener { 981d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public void onUpdate(Contact updated); 991d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1001d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 101a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private Contact(String number, String name) { 102a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao init(number, name); 103a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 104b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner /* 105b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * Make a basic contact object with a phone number. 106b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner */ 1071d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private Contact(String number) { 108a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao init(number, ""); 109a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 110a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 1114f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private Contact(boolean isMe) { 1124f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor init(SELF_ITEM_KEY, ""); 1134f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor mIsMe = isMe; 1144f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 1154f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 116a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private void init(String number, String name) { 117a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao mContactMethodId = CONTACT_METHOD_ID_UNKNOWN; 118a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao mName = name; 119431e11d429783c07eca6e789de0518d17b42fb74Wei Huang setNumber(number); 120431e11d429783c07eca6e789de0518d17b42fb74Wei Huang mNumberIsModified = false; 1211d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick mLabel = ""; 1221d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick mPersonId = 0; 1231d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick mPresenceResId = 0; 124d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor mIsStale = true; 1251b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor mSendToVoicemail = false; 1261d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 127b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner @Override 128b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public String toString() { 129a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return String.format("{ number=%s, name=%s, nameAndNumber=%s, label=%s, person_id=%d, hash=%d method_id=%d }", 130feb1aab54eabc98a04349af52e19ff9fbcd7c169Tom Taylor (mNumber != null ? mNumber : "null"), 131feb1aab54eabc98a04349af52e19ff9fbcd7c169Tom Taylor (mName != null ? mName : "null"), 132feb1aab54eabc98a04349af52e19ff9fbcd7c169Tom Taylor (mNameAndNumber != null ? mNameAndNumber : "null"), 133feb1aab54eabc98a04349af52e19ff9fbcd7c169Tom Taylor (mLabel != null ? mLabel : "null"), 134a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao mPersonId, hashCode(), 135a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao mContactMethodId); 136b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 137b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 1381d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private static void logWithTrace(String msg, Object... format) { 1391d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick Thread current = Thread.currentThread(); 1401d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick StackTraceElement[] stack = current.getStackTrace(); 1411d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1421d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick StringBuilder sb = new StringBuilder(); 1431d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append("["); 1441d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append(current.getId()); 1451d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append("] "); 1461d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append(String.format(msg, format)); 1471d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1481d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append(" <- "); 1491d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick int stop = stack.length > 7 ? 7 : stack.length; 1501d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick for (int i = 3; i < stop; i++) { 1511d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick String methodName = stack[i].getMethodName(); 1521d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append(methodName); 1531d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick if ((i+1) != stop) { 1541d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append(" <- "); 1551d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1561d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1571d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1581d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick Log.d(TAG, sb.toString()); 1591d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1601d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1611d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public static Contact get(String number, boolean canBlock) { 162b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return sContactCache.get(number, canBlock); 1631d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1641d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1654f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor public static Contact getMe(boolean canBlock) { 1664f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return sContactCache.getMe(canBlock); 1674f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 1684f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 169a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public static List<Contact> getByPhoneUris(Parcelable[] uris) { 170a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return sContactCache.getContactInfoForPhoneUris(uris); 171a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 172a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 1731d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public static void invalidateCache() { 17432a1dcecca6ed0881431555a4218d0282814326cWink Saville if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 17532a1dcecca6ed0881431555a4218d0282814326cWink Saville log("invalidateCache"); 17632a1dcecca6ed0881431555a4218d0282814326cWink Saville } 177d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor 178d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // While invalidating our local Cache doesn't remove the contacts, it will mark them 179d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // stale so the next time we're asked for a particular contact, we'll return that 180d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // stale contact and at the same time, fire off an asyncUpdateContact to update 181d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // that contact's info in the background. UI elements using the contact typically 182d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // call addListener() so they immediately get notified when the contact has been 183d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // updated with the latest info. They redraw themselves when we call the 184d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // listener's onUpdate(). 185b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner sContactCache.invalidate(); 1861d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1871d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1884f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor public boolean isMe() { 1894f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return mIsMe; 1904f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 1914f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 1921d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private static String emptyIfNull(String s) { 1931d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return (s != null ? s : ""); 1941d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1951d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1964759133e3c935e751815bf4f997d029caa64d889Bai Tao /** 1974759133e3c935e751815bf4f997d029caa64d889Bai Tao * Fomat the name and number. 1984759133e3c935e751815bf4f997d029caa64d889Bai Tao * 1994759133e3c935e751815bf4f997d029caa64d889Bai Tao * @param name 2004759133e3c935e751815bf4f997d029caa64d889Bai Tao * @param number 2014759133e3c935e751815bf4f997d029caa64d889Bai Tao * @param numberE164 the number's E.164 representation, is used to get the 2024759133e3c935e751815bf4f997d029caa64d889Bai Tao * country the number belongs to. 2034759133e3c935e751815bf4f997d029caa64d889Bai Tao * @return the formatted name and number 2044759133e3c935e751815bf4f997d029caa64d889Bai Tao */ 2053e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor public static String formatNameAndNumber(String name, String number, String numberE164) { 2061d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick // Format like this: Mike Cleron <(650) 555-1234> 2071d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick // Erick Tseng <(650) 555-1212> 2081d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick // Tutankhamun <tutank1341@gmail.com> 2091d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick // (408) 555-1289 2101d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick String formattedNumber = number; 2111d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick if (!Mms.isEmailAddress(number)) { 2123e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor formattedNumber = PhoneNumberUtils.formatNumber(number, numberE164, 2133e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor MmsApp.getApplication().getCurrentCountryIso()); 2141d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2151d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2161d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick if (!TextUtils.isEmpty(name) && !name.equals(number)) { 2171d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return name + " <" + formattedNumber + ">"; 2181d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } else { 2191d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return formattedNumber; 2201d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2211d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2221d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 22360d7fa5f74463f22fe9a4cd81c0b2fcc95be7c09Tom Taylor public synchronized void reload() { 22460d7fa5f74463f22fe9a4cd81c0b2fcc95be7c09Tom Taylor mIsStale = true; 22560d7fa5f74463f22fe9a4cd81c0b2fcc95be7c09Tom Taylor sContactCache.get(mNumber, false); 22660d7fa5f74463f22fe9a4cd81c0b2fcc95be7c09Tom Taylor } 22760d7fa5f74463f22fe9a4cd81c0b2fcc95be7c09Tom Taylor 2281d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized String getNumber() { 2291d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mNumber; 2301d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2311d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 23225b939e5a7ecb1e0879b684dc5bc55183cf468b4Wei Huang public synchronized void setNumber(String number) { 2333e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor if (!Mms.isEmailAddress(number)) { 2343e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor mNumber = PhoneNumberUtils.formatNumber(number, mNumberE164, 2353e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor MmsApp.getApplication().getCurrentCountryIso()); 2363e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor } else { 2373e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor mNumber = number; 2383e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor } 239dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang notSynchronizedUpdateNameAndNumber(); 240431e11d429783c07eca6e789de0518d17b42fb74Wei Huang mNumberIsModified = true; 241431e11d429783c07eca6e789de0518d17b42fb74Wei Huang } 242431e11d429783c07eca6e789de0518d17b42fb74Wei Huang 243431e11d429783c07eca6e789de0518d17b42fb74Wei Huang public boolean isNumberModified() { 244431e11d429783c07eca6e789de0518d17b42fb74Wei Huang return mNumberIsModified; 245431e11d429783c07eca6e789de0518d17b42fb74Wei Huang } 246431e11d429783c07eca6e789de0518d17b42fb74Wei Huang 2471b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor public boolean getSendToVoicemail() { 2481b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor return mSendToVoicemail; 2491b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor } 2501b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor 251431e11d429783c07eca6e789de0518d17b42fb74Wei Huang public void setIsNumberModified(boolean flag) { 252431e11d429783c07eca6e789de0518d17b42fb74Wei Huang mNumberIsModified = flag; 25325b939e5a7ecb1e0879b684dc5bc55183cf468b4Wei Huang } 25425b939e5a7ecb1e0879b684dc5bc55183cf468b4Wei Huang 2551d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized String getName() { 2561d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick if (TextUtils.isEmpty(mName)) { 2571d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mNumber; 2581d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } else { 2591d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mName; 2601d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2611d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2621d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2631d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized String getNameAndNumber() { 2641d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mNameAndNumber; 2651d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2661d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 267dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang private void notSynchronizedUpdateNameAndNumber() { 2683e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor mNameAndNumber = formatNameAndNumber(mName, mNumber, mNumberE164); 26925b939e5a7ecb1e0879b684dc5bc55183cf468b4Wei Huang } 27025b939e5a7ecb1e0879b684dc5bc55183cf468b4Wei Huang 271431e11d429783c07eca6e789de0518d17b42fb74Wei Huang public synchronized long getRecipientId() { 272431e11d429783c07eca6e789de0518d17b42fb74Wei Huang return mRecipientId; 273431e11d429783c07eca6e789de0518d17b42fb74Wei Huang } 274431e11d429783c07eca6e789de0518d17b42fb74Wei Huang 275431e11d429783c07eca6e789de0518d17b42fb74Wei Huang public synchronized void setRecipientId(long id) { 276431e11d429783c07eca6e789de0518d17b42fb74Wei Huang mRecipientId = id; 277431e11d429783c07eca6e789de0518d17b42fb74Wei Huang } 278431e11d429783c07eca6e789de0518d17b42fb74Wei Huang 2791d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized String getLabel() { 2801d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mLabel; 2811d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2821d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2831d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized Uri getUri() { 2842be1333ab5b265c0ff758354bac6a9eff97e1facDmitri Plotnikov return ContentUris.withAppendedId(Contacts.CONTENT_URI, mPersonId); 2851d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2861d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2871d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized int getPresenceResId() { 2881d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mPresenceResId; 2891d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2901d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2911d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized boolean existsInDatabase() { 2921d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return (mPersonId > 0); 2931d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2941d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2953487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner public static void addListener(UpdateListener l) { 2963487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner synchronized (mListeners) { 2973487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner mListeners.add(l); 2983487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner } 2991d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 3001d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 3013487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner public static void removeListener(UpdateListener l) { 3023487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner synchronized (mListeners) { 3033487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner mListeners.remove(l); 3043487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner } 305d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang } 306d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang 3073487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner public static void dumpListeners() { 3083487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner synchronized (mListeners) { 3093487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner int i = 0; 3103487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner Log.i(TAG, "[Contact] dumpListeners; size=" + mListeners.size()); 3113487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner for (UpdateListener listener : mListeners) { 3123487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner Log.i(TAG, "["+ (i++) + "]" + listener); 3133487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner } 314d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang } 3151d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 3161d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 3171d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized boolean isEmail() { 3181d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return Mms.isEmailAddress(mNumber); 3191d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 3201d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 3211c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner public String getPresenceText() { 3221c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner return mPresenceText; 3231c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner } 3241c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner 325a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public int getContactMethodType() { 326a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return mContactMethodType; 327a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 328a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 329a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public long getContactMethodId() { 330a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return mContactMethodId; 331a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 332a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 333a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public synchronized Uri getPhoneUri() { 334a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (existsInDatabase()) { 335a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return ContentUris.withAppendedId(Phone.CONTENT_URI, mContactMethodId); 336a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } else { 337a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Uri.Builder ub = new Uri.Builder(); 338a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao ub.scheme(TEL_SCHEME); 339a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao ub.encodedOpaquePart(mNumber); 340a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return ub.build(); 341a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 342a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 343a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 344b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public synchronized Drawable getAvatar(Context context, Drawable defaultValue) { 345b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (mAvatar == null) { 346b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (mAvatarData != null) { 347b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Bitmap b = BitmapFactory.decodeByteArray(mAvatarData, 0, mAvatarData.length); 348b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mAvatar = new BitmapDrawable(context.getResources(), b); 349b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 350b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 3511c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner return mAvatar != null ? mAvatar : defaultValue; 3521c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner } 3531c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner 3541d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public static void init(final Context context) { 355b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner sContactCache = new ContactsCache(context); 356b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 3571d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick RecipientIdCache.init(context); 358d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang 359d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang // it maybe too aggressive to listen for *any* contact changes, and rebuild MMS contact 360d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang // cache each time that occurs. Unless we can get targeted updates for the contacts we 361d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang // care about(which probably won't happen for a long time), we probably should just 362d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang // invalidate cache peoridically, or surgically. 363d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang /* 3641d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick context.getContentResolver().registerContentObserver( 3652be1333ab5b265c0ff758354bac6a9eff97e1facDmitri Plotnikov Contacts.CONTENT_URI, true, sContactsObserver); 366d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang */ 3671d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 3681d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 3691d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public static void dump() { 370b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner sContactCache.dump(); 371b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 372b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 373b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static class ContactsCache { 374b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private final TaskStack mTaskQueue = new TaskStack(); 375b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static final String SEPARATOR = ";"; 376b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 3774759133e3c935e751815bf4f997d029caa64d889Bai Tao /** 3784759133e3c935e751815bf4f997d029caa64d889Bai Tao * For a specified phone number, 2 rows were inserted into phone_lookup 3794759133e3c935e751815bf4f997d029caa64d889Bai Tao * table. One is the phone number's E164 representation, and another is 3804759133e3c935e751815bf4f997d029caa64d889Bai Tao * one's normalized format. If the phone number's normalized format in 3814759133e3c935e751815bf4f997d029caa64d889Bai Tao * the lookup table is the suffix of the given number's one, it is 3824759133e3c935e751815bf4f997d029caa64d889Bai Tao * treated as matched CallerId. E164 format number must fully equal. 3834759133e3c935e751815bf4f997d029caa64d889Bai Tao * 3844759133e3c935e751815bf4f997d029caa64d889Bai Tao * For example: Both 650-123-4567 and +1 (650) 123-4567 will match the 3854759133e3c935e751815bf4f997d029caa64d889Bai Tao * normalized number 6501234567 in the phone lookup. 3864759133e3c935e751815bf4f997d029caa64d889Bai Tao * 3874759133e3c935e751815bf4f997d029caa64d889Bai Tao * The min_match is used to narrow down the candidates for the final 3884759133e3c935e751815bf4f997d029caa64d889Bai Tao * comparison. 3894759133e3c935e751815bf4f997d029caa64d889Bai Tao */ 390b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // query params for caller id lookup 3914759133e3c935e751815bf4f997d029caa64d889Bai Tao private static final String CALLER_ID_SELECTION = " Data._ID IN " 3924759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (SELECT DISTINCT lookup.data_id " 3934759133e3c935e751815bf4f997d029caa64d889Bai Tao + " FROM " 3944759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (SELECT data_id, normalized_number, length(normalized_number) as len " 3954759133e3c935e751815bf4f997d029caa64d889Bai Tao + " FROM phone_lookup " 3964759133e3c935e751815bf4f997d029caa64d889Bai Tao + " WHERE min_match = ?) AS lookup " 3974759133e3c935e751815bf4f997d029caa64d889Bai Tao + " WHERE lookup.normalized_number = ? OR" 3984759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (lookup.len <= ? AND " 3994759133e3c935e751815bf4f997d029caa64d889Bai Tao + " substr(?, ? - lookup.len + 1) = lookup.normalized_number))"; 4004759133e3c935e751815bf4f997d029caa64d889Bai Tao 4014759133e3c935e751815bf4f997d029caa64d889Bai Tao // query params for caller id lookup without E164 number as param 4024759133e3c935e751815bf4f997d029caa64d889Bai Tao private static final String CALLER_ID_SELECTION_WITHOUT_E164 = " Data._ID IN " 4034759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (SELECT DISTINCT lookup.data_id " 4044759133e3c935e751815bf4f997d029caa64d889Bai Tao + " FROM " 4054759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (SELECT data_id, normalized_number, length(normalized_number) as len " 4064759133e3c935e751815bf4f997d029caa64d889Bai Tao + " FROM phone_lookup " 4074759133e3c935e751815bf4f997d029caa64d889Bai Tao + " WHERE min_match = ?) AS lookup " 4084759133e3c935e751815bf4f997d029caa64d889Bai Tao + " WHERE " 4094759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (lookup.len <= ? AND " 4104759133e3c935e751815bf4f997d029caa64d889Bai Tao + " substr(?, ? - lookup.len + 1) = lookup.normalized_number))"; 411b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 412b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // Utilizing private API 413b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static final Uri PHONES_WITH_PRESENCE_URI = Data.CONTENT_URI; 414b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 415b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static final String[] CALLER_ID_PROJECTION = new String[] { 416a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone._ID, // 0 417a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.NUMBER, // 1 418a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.LABEL, // 2 419a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.DISPLAY_NAME, // 3 420a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.CONTACT_ID, // 4 421a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.CONTACT_PRESENCE, // 5 422a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.CONTACT_STATUS, // 6 4231b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor Phone.NORMALIZED_NUMBER, // 7 4241b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor Contacts.SEND_TO_VOICEMAIL // 8 425b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner }; 426b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 427a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int PHONE_ID_COLUMN = 0; 428a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int PHONE_NUMBER_COLUMN = 1; 429a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int PHONE_LABEL_COLUMN = 2; 430a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int CONTACT_NAME_COLUMN = 3; 431a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int CONTACT_ID_COLUMN = 4; 432a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int CONTACT_PRESENCE_COLUMN = 5; 433a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int CONTACT_STATUS_COLUMN = 6; 4344759133e3c935e751815bf4f997d029caa64d889Bai Tao private static final int PHONE_NORMALIZED_NUMBER = 7; 4351b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor private static final int SEND_TO_VOICEMAIL = 8; 436b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 4374f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private static final String[] SELF_PROJECTION = new String[] { 4384f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Phone._ID, // 0 4394f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Phone.DISPLAY_NAME, // 1 4404f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor }; 4414f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 4424f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private static final int SELF_ID_COLUMN = 0; 4434f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private static final int SELF_NAME_COLUMN = 1; 4444f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 445b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // query params for contact lookup by email 446b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static final Uri EMAIL_WITH_PRESENCE_URI = Data.CONTENT_URI; 447b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 4480a3684e0f1242518b522e2883fe275343768bb27Dmitri Plotnikov private static final String EMAIL_SELECTION = "UPPER(" + Email.DATA + ")=UPPER(?) AND " 4490a3684e0f1242518b522e2883fe275343768bb27Dmitri Plotnikov + Data.MIMETYPE + "='" + Email.CONTENT_ITEM_TYPE + "'"; 450b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 451b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static final String[] EMAIL_PROJECTION = new String[] { 452a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Email._ID, // 0 453a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Email.DISPLAY_NAME, // 1 454a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Email.CONTACT_PRESENCE, // 2 455a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Email.CONTACT_ID, // 3 456a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.DISPLAY_NAME, // 4 4571b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor Contacts.SEND_TO_VOICEMAIL // 5 458b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner }; 459a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int EMAIL_ID_COLUMN = 0; 460a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int EMAIL_NAME_COLUMN = 1; 461a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int EMAIL_STATUS_COLUMN = 2; 462a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int EMAIL_CONTACT_ID_COLUMN = 3; 463a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int EMAIL_CONTACT_NAME_COLUMN = 4; 4641b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor private static final int EMAIL_SEND_TO_VOICEMAIL_COLUMN = 5; 465b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 466b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private final Context mContext; 467458dea8d1858e418b6918f477d0139335b14ff45Tom Taylor 468513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner private final HashMap<String, ArrayList<Contact>> mContactsHash = 469513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner new HashMap<String, ArrayList<Contact>>(); 470513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner 471b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private ContactsCache(Context context) { 472b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mContext = context; 473b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 474458dea8d1858e418b6918f477d0139335b14ff45Tom Taylor 475b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner void dump() { 476b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (ContactsCache.this) { 477b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Log.d(TAG, "**** Contact cache dump ****"); 47840ab55a4337738075adbda3642ce0415f3810c4cMark Wagner for (String key : mContactsHash.keySet()) { 47940ab55a4337738075adbda3642ce0415f3810c4cMark Wagner ArrayList<Contact> alc = mContactsHash.get(key); 480513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner for (Contact c : alc) { 48140ab55a4337738075adbda3642ce0415f3810c4cMark Wagner Log.d(TAG, key + " ==> " + c.toString()); 482513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 483b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 484b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 485b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 486161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner 487b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static class TaskStack { 488b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Thread mWorkerThread; 489b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private final ArrayList<Runnable> mThingsToLoad; 490b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 491b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public TaskStack() { 492b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mThingsToLoad = new ArrayList<Runnable>(); 493b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mWorkerThread = new Thread(new Runnable() { 494b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public void run() { 495b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner while (true) { 496b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Runnable r = null; 497b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (mThingsToLoad) { 498b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (mThingsToLoad.size() == 0) { 499b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner try { 500b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mThingsToLoad.wait(); 501b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } catch (InterruptedException ex) { 502b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // nothing to do 503b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 504b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 505b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (mThingsToLoad.size() > 0) { 506b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner r = mThingsToLoad.remove(0); 507161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 508161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 509b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (r != null) { 510b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner r.run(); 511161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 512161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 513b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 514b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner }); 515b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mWorkerThread.start(); 516b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 517b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 518b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public void push(Runnable r) { 519b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (mThingsToLoad) { 520b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mThingsToLoad.add(r); 521b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mThingsToLoad.notify(); 522b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 523b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 524b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 525b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 526b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public void pushTask(Runnable r) { 527b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mTaskQueue.push(r); 528b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 529b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 5304f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor public Contact getMe(boolean canBlock) { 5314f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return get(SELF_ITEM_KEY, true, canBlock); 5324f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 5334f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 534b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public Contact get(String number, boolean canBlock) { 5354f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return get(number, false, canBlock); 5364f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 5374f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 5384f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private Contact get(String number, boolean isMe, boolean canBlock) { 5394f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if (V) logWithTrace("get(%s, %s, %s)", number, isMe, canBlock); 540b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 541b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (TextUtils.isEmpty(number)) { 542b142ea00f24f4b838e6b4d0f2761eedd0f14f625Tom Taylor number = ""; // In some places (such as Korea), it's possible to receive 543b142ea00f24f4b838e6b4d0f2761eedd0f14f625Tom Taylor // a message without the sender's address. In this case, 544b142ea00f24f4b838e6b4d0f2761eedd0f14f625Tom Taylor // all such anonymous messages will get added to the same 545b142ea00f24f4b838e6b4d0f2761eedd0f14f625Tom Taylor // thread. 546b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 547b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 548b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // Always return a Contact object, if if we don't have an actual contact 549b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // in the contacts db. 5504f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Contact contact = internalGet(number, isMe); 551b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Runnable r = null; 552dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 553b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (contact) { 554b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // If there's a query pending and we're willing to block then 555b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // wait here until the query completes. 556b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner while (canBlock && contact.mQueryPending) { 557b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner try { 558b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner contact.wait(); 559b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } catch (InterruptedException ex) { 560b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // try again by virtue of the loop unless mQueryPending is false 561b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 562b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 563b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 564b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // If we're stale and we haven't already kicked off a query then kick 565b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // it off here. 566b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (contact.mIsStale && !contact.mQueryPending) { 567b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner contact.mIsStale = false; 568b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 569b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 570dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang log("async update for " + contact.toString() + " canBlock: " + canBlock + 571b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner " isStale: " + contact.mIsStale); 572b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 573b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 574b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner final Contact c = contact; 575b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner r = new Runnable() { 576b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public void run() { 577b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner updateContact(c); 578161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 579b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner }; 580b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 581b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // set this to true while we have the lock on contact since we will 582b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // either run the query directly (canBlock case) or push the query 583b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // onto the queue. In either case the mQueryPending will get set 584b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // to false via updateContact. 585b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner contact.mQueryPending = true; 586b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 587b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 588b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // do this outside of the synchronized so we don't hold up any 589b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // subsequent calls to "get" on other threads 590b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (r != null) { 591b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (canBlock) { 592b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner r.run(); 593b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } else { 594b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner pushTask(r); 595b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 596b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 597b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return contact; 598b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 599b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 600a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao /** 601a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao * Get CacheEntry list for given phone URIs. This method will do single one query to 602a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao * get expected contacts from provider. Be sure passed in URIs are not null and contains 603a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao * only valid URIs. 604a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao */ 605a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public List<Contact> getContactInfoForPhoneUris(Parcelable[] uris) { 606a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (uris.length == 0) { 607a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return null; 608a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 609a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao StringBuilder idSetBuilder = new StringBuilder(); 610a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao boolean first = true; 611a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao for (Parcelable p : uris) { 612a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Uri uri = (Uri) p; 613a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if ("content".equals(uri.getScheme())) { 614a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (first) { 615a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao first = false; 616a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao idSetBuilder.append(uri.getLastPathSegment()); 617a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } else { 618a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao idSetBuilder.append(',').append(uri.getLastPathSegment()); 619a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 620a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 621a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 622a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao // Check whether there is content URI. 623a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (first) return null; 624a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Cursor cursor = null; 625a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (idSetBuilder.length() > 0) { 626a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao final String whereClause = Phone._ID + " IN (" + idSetBuilder.toString() + ")"; 627a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao cursor = mContext.getContentResolver().query( 628a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao PHONES_WITH_PRESENCE_URI, CALLER_ID_PROJECTION, whereClause, null, null); 629a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 630a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 631a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (cursor == null) { 632a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return null; 633a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 634a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 635a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao List<Contact> entries = new ArrayList<Contact>(); 636a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 637a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao try { 638a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao while (cursor.moveToNext()) { 639a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Contact entry = new Contact(cursor.getString(PHONE_NUMBER_COLUMN), 640a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao cursor.getString(CONTACT_NAME_COLUMN)); 641a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao fillPhoneTypeContact(entry, cursor); 642a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao ArrayList<Contact> value = new ArrayList<Contact>(); 643a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao value.add(entry); 644a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao // Put the result in the cache. 645a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao mContactsHash.put(key(entry.mNumber, sStaticKeyBuffer), value); 646a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao entries.add(entry); 647a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 648a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } finally { 649a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao cursor.close(); 650a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 651a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return entries; 652a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 653a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 654b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private boolean contactChanged(Contact orig, Contact newContactData) { 655b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // The phone number should never change, so don't bother checking. 656b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // TODO: Maybe update it if it has gotten longer, i.e. 650-234-5678 -> +16502345678? 657b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 658a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao // Do the quick check first. 659a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (orig.mContactMethodType != newContactData.mContactMethodType) { 660b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return true; 661b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 662b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 663a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (orig.mContactMethodId != newContactData.mContactMethodId) { 664b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return true; 665b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 666b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 667b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (orig.mPersonId != newContactData.mPersonId) { 668b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (V) Log.d(TAG, "person id changed"); 669b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return true; 670b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 671b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 672b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (orig.mPresenceResId != newContactData.mPresenceResId) { 673b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (V) Log.d(TAG, "presence changed"); 674b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return true; 675b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 676b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 6771b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor if (orig.mSendToVoicemail != newContactData.mSendToVoicemail) { 6781b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor return true; 6791b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor } 6801b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor 681a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao String oldName = emptyIfNull(orig.mName); 682a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao String newName = emptyIfNull(newContactData.mName); 683a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (!oldName.equals(newName)) { 684a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (V) Log.d(TAG, String.format("name changed: %s -> %s", oldName, newName)); 685a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return true; 686a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 687a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 688a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao String oldLabel = emptyIfNull(orig.mLabel); 689a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao String newLabel = emptyIfNull(newContactData.mLabel); 690a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (!oldLabel.equals(newLabel)) { 691a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (V) Log.d(TAG, String.format("label changed: %s -> %s", oldLabel, newLabel)); 692a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return true; 693a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 694a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 695b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (!Arrays.equals(orig.mAvatarData, newContactData.mAvatarData)) { 696b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (V) Log.d(TAG, "avatar changed"); 697b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return true; 698b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 699b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 700b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return false; 701b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 702b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 703b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private void updateContact(final Contact c) { 704b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (c == null) { 705b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return; 706b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 707b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 7084f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Contact entry = getContactInfo(c); 709dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang synchronized (c) { 710b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (contactChanged(c, entry)) { 711b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 712b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner log("updateContact: contact changed for " + entry.mName); 713161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 714b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 715b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mNumber = entry.mNumber; 716b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mLabel = entry.mLabel; 717b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mPersonId = entry.mPersonId; 718b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mPresenceResId = entry.mPresenceResId; 719b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mPresenceText = entry.mPresenceText; 720b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mAvatarData = entry.mAvatarData; 721b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mAvatar = entry.mAvatar; 722a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao c.mContactMethodId = entry.mContactMethodId; 723a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao c.mContactMethodType = entry.mContactMethodType; 7244759133e3c935e751815bf4f997d029caa64d889Bai Tao c.mNumberE164 = entry.mNumberE164; 7254f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor c.mName = entry.mName; 7261b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor c.mSendToVoicemail = entry.mSendToVoicemail; 727dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 728dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang c.notSynchronizedUpdateNameAndNumber(); 729b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 730ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // We saw a bug where we were updating an empty contact. That would trigger 731ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // l.onUpdate() below, which would call ComposeMessageActivity.onUpdate, 732ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // which would call the adapter's notifyDataSetChanged, which would throw 733ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // away the message items and rebuild, eventually calling updateContact() 734ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // again -- all in a vicious and unending loop. Break the cycle and don't 735ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // notify if the number (the most important piece of information) is empty. 736ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor if (!TextUtils.isEmpty(c.mNumber)) { 737ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // clone the list of listeners in case the onUpdate call turns around and 738ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // modifies the list of listeners 739ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // access to mListeners is synchronized on ContactsCache 740ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor HashSet<UpdateListener> iterator; 741ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor synchronized (mListeners) { 742ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor iterator = (HashSet<UpdateListener>)Contact.mListeners.clone(); 743ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor } 744ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor for (UpdateListener l : iterator) { 745ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor if (V) Log.d(TAG, "updating " + l); 746ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor l.onUpdate(c); 747ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor } 748b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 749b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 750b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (c) { 751b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mQueryPending = false; 752b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.notifyAll(); 753161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 754b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 755161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 756161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner 757b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner /** 758b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * Returns the caller info in Contact. 759b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner */ 7604f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private Contact getContactInfo(Contact c) { 7614f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if (c.mIsMe) { 7624f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return getContactInfoForSelf(); 7634f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } else if (Mms.isEmailAddress(c.mNumber) || isAlphaNumber(c.mNumber)) { 7644f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return getContactInfoForEmailAddress(c.mNumber); 765b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } else { 7664f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return getContactInfoForPhoneNumber(c.mNumber); 767b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 76833a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick } 76933a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick 7706ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // Some received sms's have addresses such as "OakfieldCPS" or "T-Mobile". This 7716ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // function will attempt to identify these and return true. If the number contains 7726ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // 3 or more digits, such as "jello123", this function will return false. 7736ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // Some countries have 3 digits shortcodes and we have to identify them as numbers. 7746ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // http://en.wikipedia.org/wiki/Short_code 7756ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // Examples of input/output for this function: 7766ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "Jello123" -> false [3 digits, it is considered to be the phone number "123"] 7776ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "T-Mobile" -> true [it is considered to be the address "T-Mobile"] 7786ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "Mobile1" -> true [1 digit, it is considered to be the address "Mobile1"] 7796ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "Dogs77" -> true [2 digits, it is considered to be the address "Dogs77"] 7806ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "****1" -> true [1 digits, it is considered to be the address "****1"] 7816ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "#4#5#6#" -> true [it is considered to be the address "#4#5#6#"] 7826ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "AB12" -> true [2 digits, it is considered to be the address "AB12"] 7836ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "12" -> true [2 digits, it is considered to be the address "12"] 7846ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor private boolean isAlphaNumber(String number) { 7856ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // TODO: PhoneNumberUtils.isWellFormedSmsAddress() only check if the number is a valid 7866ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // GSM SMS address. If the address contains a dialable char, it considers it a well 7876ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // formed SMS addr. CDMA doesn't work that way and has a different parser for SMS 7886ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // address (see CdmaSmsAddress.parse(String address)). We should definitely fix this!!! 7896ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor if (!PhoneNumberUtils.isWellFormedSmsAddress(number)) { 7906ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // The example "T-Mobile" will exit here because there are no numbers. 7916ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor return true; // we're not an sms address, consider it an alpha number 7926ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor } 793d7fddfa20e7bfe9f0bf376f9cce9188bf9bf0354Tom Taylor if (MessageUtils.isAlias(number)) { 794d7fddfa20e7bfe9f0bf376f9cce9188bf9bf0354Tom Taylor return true; 795d7fddfa20e7bfe9f0bf376f9cce9188bf9bf0354Tom Taylor } 7966ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor number = PhoneNumberUtils.extractNetworkPortion(number); 7976ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor if (TextUtils.isEmpty(number)) { 7986ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor return true; // there are no digits whatsoever in the number 7996ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor } 8006ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // At this point, anything like "Mobile1" or "Dogs77" will be stripped down to 8016ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "1" and "77". "#4#5#6#" remains as "#4#5#6#" at this point. 8026ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor return number.length() < 3; 8036ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor } 8046ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor 805b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner /** 806b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * Queries the caller id info with the phone number. 807b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * @return a Contact containing the caller id info corresponding to the number. 808b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner */ 809b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private Contact getContactInfoForPhoneNumber(String number) { 810b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner number = PhoneNumberUtils.stripSeparators(number); 811b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Contact entry = new Contact(number); 812a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao entry.mContactMethodType = CONTACT_METHOD_TYPE_PHONE; 813b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 814b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner //if (LOCAL_DEBUG) log("queryContactInfoByNumber: number=" + number); 815b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 8164759133e3c935e751815bf4f997d029caa64d889Bai Tao String normalizedNumber = PhoneNumberUtils.normalizeNumber(number); 8174759133e3c935e751815bf4f997d029caa64d889Bai Tao String minMatch = PhoneNumberUtils.toCallerIDMinMatch(normalizedNumber); 8184759133e3c935e751815bf4f997d029caa64d889Bai Tao if (!TextUtils.isEmpty(normalizedNumber) && !TextUtils.isEmpty(minMatch)) { 8194759133e3c935e751815bf4f997d029caa64d889Bai Tao String numberLen = String.valueOf(normalizedNumber.length()); 8204759133e3c935e751815bf4f997d029caa64d889Bai Tao String numberE164 = PhoneNumberUtils.formatNumberToE164( 8214759133e3c935e751815bf4f997d029caa64d889Bai Tao number, MmsApp.getApplication().getCurrentCountryIso()); 8224759133e3c935e751815bf4f997d029caa64d889Bai Tao String selection; 8234759133e3c935e751815bf4f997d029caa64d889Bai Tao String[] args; 8244759133e3c935e751815bf4f997d029caa64d889Bai Tao if (TextUtils.isEmpty(numberE164)) { 8254759133e3c935e751815bf4f997d029caa64d889Bai Tao selection = CALLER_ID_SELECTION_WITHOUT_E164; 8264759133e3c935e751815bf4f997d029caa64d889Bai Tao args = new String[] {minMatch, numberLen, normalizedNumber, numberLen}; 8274759133e3c935e751815bf4f997d029caa64d889Bai Tao } else { 8284759133e3c935e751815bf4f997d029caa64d889Bai Tao selection = CALLER_ID_SELECTION; 8294759133e3c935e751815bf4f997d029caa64d889Bai Tao args = new String[] { 8304759133e3c935e751815bf4f997d029caa64d889Bai Tao minMatch, numberE164, numberLen, normalizedNumber, numberLen}; 8314759133e3c935e751815bf4f997d029caa64d889Bai Tao } 832b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 8334759133e3c935e751815bf4f997d029caa64d889Bai Tao Cursor cursor = mContext.getContentResolver().query( 8344759133e3c935e751815bf4f997d029caa64d889Bai Tao PHONES_WITH_PRESENCE_URI, CALLER_ID_PROJECTION, selection, args, null); 8354759133e3c935e751815bf4f997d029caa64d889Bai Tao if (cursor == null) { 8364759133e3c935e751815bf4f997d029caa64d889Bai Tao Log.w(TAG, "queryContactInfoByNumber(" + number + ") returned NULL cursor!" 8374759133e3c935e751815bf4f997d029caa64d889Bai Tao + " contact uri used " + PHONES_WITH_PRESENCE_URI); 8384759133e3c935e751815bf4f997d029caa64d889Bai Tao return entry; 8394759133e3c935e751815bf4f997d029caa64d889Bai Tao } 840b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 8414759133e3c935e751815bf4f997d029caa64d889Bai Tao try { 8424759133e3c935e751815bf4f997d029caa64d889Bai Tao if (cursor.moveToFirst()) { 8434759133e3c935e751815bf4f997d029caa64d889Bai Tao fillPhoneTypeContact(entry, cursor); 8444759133e3c935e751815bf4f997d029caa64d889Bai Tao } 8454759133e3c935e751815bf4f997d029caa64d889Bai Tao } finally { 8464759133e3c935e751815bf4f997d029caa64d889Bai Tao cursor.close(); 847b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 848b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 849b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return entry; 85033a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick } 85133a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick 8524f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor /** 8534f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor * @return a Contact containing the info for the profile. 8544f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor */ 8554f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private Contact getContactInfoForSelf() { 8564f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Contact entry = new Contact(true); 8574f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor entry.mContactMethodType = CONTACT_METHOD_TYPE_SELF; 8584f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 8594f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor //if (LOCAL_DEBUG) log("getContactInfoForSelf: number=" + number); 8604f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Cursor cursor = mContext.getContentResolver().query( 8614f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Profile.CONTENT_URI, SELF_PROJECTION, null, null, null); 8624f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if (cursor == null) { 8634f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Log.w(TAG, "getContactInfoForSelf() returned NULL cursor!" 8644f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor + " contact uri used " + Profile.CONTENT_URI); 8654f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return entry; 8664f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 8674f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 8684f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor try { 8694f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if (cursor.moveToFirst()) { 8704f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor fillSelfContact(entry, cursor); 8714f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 8724f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } finally { 8734f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor cursor.close(); 8744f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 8754f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return entry; 8764f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 8774f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 878a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private void fillPhoneTypeContact(final Contact contact, final Cursor cursor) { 879a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao synchronized (contact) { 880a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mContactMethodType = CONTACT_METHOD_TYPE_PHONE; 881a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mContactMethodId = cursor.getLong(PHONE_ID_COLUMN); 882a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mLabel = cursor.getString(PHONE_LABEL_COLUMN); 883a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mName = cursor.getString(CONTACT_NAME_COLUMN); 884a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mPersonId = cursor.getLong(CONTACT_ID_COLUMN); 885a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mPresenceResId = getPresenceIconResourceId( 886a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao cursor.getInt(CONTACT_PRESENCE_COLUMN)); 887a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mPresenceText = cursor.getString(CONTACT_STATUS_COLUMN); 8884759133e3c935e751815bf4f997d029caa64d889Bai Tao contact.mNumberE164 = cursor.getString(PHONE_NORMALIZED_NUMBER); 8891b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor contact.mSendToVoicemail = cursor.getInt(SEND_TO_VOICEMAIL) == 1; 890a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (V) { 8914f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor log("fillPhoneTypeContact: name=" + contact.mName + ", number=" 8921b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor + contact.mNumber + ", presence=" + contact.mPresenceResId 8931b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor + " SendToVoicemail: " + contact.mSendToVoicemail); 894a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 895a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 896a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao byte[] data = loadAvatarData(contact); 897a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 898a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao synchronized (contact) { 899a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mAvatarData = data; 900a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 901a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 9024f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 9034f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private void fillSelfContact(final Contact contact, final Cursor cursor) { 9044f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor synchronized (contact) { 9054f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor contact.mName = cursor.getString(SELF_NAME_COLUMN); 9064f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if (TextUtils.isEmpty(contact.mName)) { 9074f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor contact.mName = mContext.getString(R.string.messagelist_sender_self); 9084f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 9094f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if (V) { 9104f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor log("fillSelfContact: name=" + contact.mName + ", number=" 9114f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor + contact.mNumber); 9124f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 9134f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 9144f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor byte[] data = loadAvatarData(contact); 9154f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 9164f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor synchronized (contact) { 9174f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor contact.mAvatarData = data; 9184f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 9194f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 920b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner /* 921b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * Load the avatar data from the cursor into memory. Don't decode the data 922b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * until someone calls for it (see getAvatar). Hang onto the raw data so that 923b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * we can compare it when the data is reloaded. 924b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * TODO: consider comparing a checksum so that we don't have to hang onto 925b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * the raw bytes after the image is decoded. 926b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner */ 927dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang private byte[] loadAvatarData(Contact entry) { 928dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang byte [] data = null; 929dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 9304f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if ((!entry.mIsMe && entry.mPersonId == 0) || entry.mAvatar != null) { 931dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang return null; 932b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 933b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 934313d09ee558e6ac94ab28a205357885dc830cd0dTom Taylor if (V) { 9358d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylor log("loadAvatarData: name=" + entry.mName + ", number=" + entry.mNumber); 936313d09ee558e6ac94ab28a205357885dc830cd0dTom Taylor } 937313d09ee558e6ac94ab28a205357885dc830cd0dTom Taylor 9388d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylor // If the contact is "me", then use my local profile photo. Otherwise, build a 9398d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylor // uri to get the avatar of the contact. 9404f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Uri contactUri = entry.mIsMe ? 9418d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylor Profile.CONTENT_URI : 9428d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylor ContentUris.withAppendedId(Contacts.CONTENT_URI, entry.mPersonId); 943b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 944dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang InputStream avatarDataStream = Contacts.openContactPhotoInputStream( 945b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mContext.getContentResolver(), 946b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner contactUri); 947b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner try { 948b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (avatarDataStream != null) { 949dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang data = new byte[avatarDataStream.available()]; 950b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner avatarDataStream.read(data, 0, data.length); 951b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 952b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } catch (IOException ex) { 953b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // 954b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } finally { 955b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner try { 956b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (avatarDataStream != null) { 957b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner avatarDataStream.close(); 958b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 959b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } catch (IOException e) { 960b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 961b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 962dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 963dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang return data; 9641d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 9651d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 966b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private int getPresenceIconResourceId(int presence) { 9676be18bedb5b87dbbcdb54f37d5a0945bd0f71377Tom Taylor // TODO: must fix for SDK 968b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (presence != Presence.OFFLINE) { 969b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return Presence.getPresenceIconResourceId(presence); 970b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 971b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 972b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return 0; 973b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 974b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 975b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner /** 976b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * Query the contact email table to get the name of an email address. 977b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner */ 978b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private Contact getContactInfoForEmailAddress(String email) { 979b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Contact entry = new Contact(email); 980a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao entry.mContactMethodType = CONTACT_METHOD_TYPE_EMAIL; 981b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 982b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Cursor cursor = SqliteWrapper.query(mContext, mContext.getContentResolver(), 983b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner EMAIL_WITH_PRESENCE_URI, 984b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner EMAIL_PROJECTION, 985b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner EMAIL_SELECTION, 986dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang new String[] { email }, 987b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner null); 988b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 989b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (cursor != null) { 990b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner try { 991b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner while (cursor.moveToNext()) { 992dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang boolean found = false; 993a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao entry.mContactMethodId = cursor.getLong(EMAIL_ID_COLUMN); 994a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao entry.mPresenceResId = getPresenceIconResourceId( 995a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao cursor.getInt(EMAIL_STATUS_COLUMN)); 996a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao entry.mPersonId = cursor.getLong(EMAIL_CONTACT_ID_COLUMN); 9971b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor entry.mSendToVoicemail = cursor.getInt(EMAIL_SEND_TO_VOICEMAIL_COLUMN) == 1; 998b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 999dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang synchronized (entry) { 1000dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang entry.mPresenceResId = getPresenceIconResourceId( 1001dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang cursor.getInt(EMAIL_STATUS_COLUMN)); 1002dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang entry.mPersonId = cursor.getLong(EMAIL_ID_COLUMN); 1003dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 1004dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang String name = cursor.getString(EMAIL_NAME_COLUMN); 1005dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang if (TextUtils.isEmpty(name)) { 1006dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang name = cursor.getString(EMAIL_CONTACT_NAME_COLUMN); 1007dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang } 1008dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang if (!TextUtils.isEmpty(name)) { 1009dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang entry.mName = name; 1010dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang if (V) { 1011dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang log("getContactInfoForEmailAddress: name=" + entry.mName + 1012dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang ", email=" + email + ", presence=" + 1013dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang entry.mPresenceResId); 1014dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang } 1015dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang found = true; 1016dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang } 1017b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 1018dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 1019dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang if (found) { 1020dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang byte[] data = loadAvatarData(entry); 1021dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang synchronized (entry) { 1022dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang entry.mAvatarData = data; 1023b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 1024dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 1025b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner break; 1026b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 1027b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 1028b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } finally { 1029b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner cursor.close(); 10301d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10311d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1032b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return entry; 10331d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10341d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1035513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // Invert and truncate to five characters the phoneNumber so that we 1036513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // can use it as the key in a hashtable. We keep a mapping of this 1037513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // key to a list of all contacts which have the same key. 103840ab55a4337738075adbda3642ce0415f3810c4cMark Wagner private String key(String phoneNumber, CharBuffer keyBuffer) { 1039513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner keyBuffer.clear(); 1040513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner keyBuffer.mark(); 1041513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner 1042513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner int position = phoneNumber.length(); 1043513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner int resultCount = 0; 1044513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner while (--position >= 0) { 1045513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner char c = phoneNumber.charAt(position); 1046513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (Character.isDigit(c)) { 1047513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner keyBuffer.put(c); 1048513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (++resultCount == STATIC_KEY_BUFFER_MAXIMUM_LENGTH) { 1049513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner break; 10501d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10511d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1052513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 1053513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner keyBuffer.reset(); 1054513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (resultCount > 0) { 105540ab55a4337738075adbda3642ce0415f3810c4cMark Wagner return keyBuffer.toString(); 1056513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } else { 1057513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // there were no usable digits in the input phoneNumber 1058513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner return phoneNumber; 10591d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10601d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10611d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1062513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // Reuse this so we don't have to allocate each time we go through this 1063513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // "get" function. 1064513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner static final int STATIC_KEY_BUFFER_MAXIMUM_LENGTH = 5; 1065513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner static CharBuffer sStaticKeyBuffer = CharBuffer.allocate(STATIC_KEY_BUFFER_MAXIMUM_LENGTH); 10661d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 10674f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private Contact internalGet(String numberOrEmail, boolean isMe) { 1068b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (ContactsCache.this) { 1069513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // See if we can find "number" in the hashtable. 1070513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // If so, just return the result. 10714f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor final boolean isNotRegularPhoneNumber = isMe || Mms.isEmailAddress(numberOrEmail) || 1072dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang MessageUtils.isAlias(numberOrEmail); 1073dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang final String key = isNotRegularPhoneNumber ? 1074dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang numberOrEmail : key(numberOrEmail, sStaticKeyBuffer); 1075513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner 1076513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner ArrayList<Contact> candidates = mContactsHash.get(key); 1077513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (candidates != null) { 1078513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner int length = candidates.size(); 1079513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner for (int i = 0; i < length; i++) { 1080513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner Contact c= candidates.get(i); 1081513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (isNotRegularPhoneNumber) { 1082513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (numberOrEmail.equals(c.mNumber)) { 1083513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner return c; 1084513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 1085513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } else { 1086513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (PhoneNumberUtils.compare(numberOrEmail, c.mNumber)) { 1087513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner return c; 1088513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 1089513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 10901d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1091513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } else { 1092513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner candidates = new ArrayList<Contact>(); 1093513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // call toString() since it may be the static CharBuffer 109440ab55a4337738075adbda3642ce0415f3810c4cMark Wagner mContactsHash.put(key, candidates); 10951d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10964f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Contact c = isMe ? 10974f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor new Contact(true) : 10984f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor new Contact(numberOrEmail); 1099513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner candidates.add(c); 1100161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner return c; 11011d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 11021d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 11031d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1104b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner void invalidate() { 1105d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // Don't remove the contacts. Just mark them stale so we'll update their 1106d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // info, particularly their presence. 1107b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (ContactsCache.this) { 1108513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner for (ArrayList<Contact> alc : mContactsHash.values()) { 1109513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner for (Contact c : alc) { 1110dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang synchronized (c) { 1111dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang c.mIsStale = true; 1112dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang } 1113513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 1114d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor } 1115d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor } 1116d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor } 111732a1dcecca6ed0881431555a4218d0282814326cWink Saville } 111832a1dcecca6ed0881431555a4218d0282814326cWink Saville 111932a1dcecca6ed0881431555a4218d0282814326cWink Saville private static void log(String msg) { 112032a1dcecca6ed0881431555a4218d0282814326cWink Saville Log.d(TAG, msg); 11211d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 11221d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick} 1123