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; 16d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport android.database.sqlite.SqliteWrapper; 17b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport android.graphics.Bitmap; 18b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport android.graphics.BitmapFactory; 191c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagnerimport android.graphics.drawable.BitmapDrawable; 201c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagnerimport android.graphics.drawable.Drawable; 211d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.net.Uri; 221d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.os.Handler; 23a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Taoimport android.os.Parcelable; 24d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport android.provider.ContactsContract.CommonDataKinds.Email; 25d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport android.provider.ContactsContract.CommonDataKinds.Phone; 262be1333ab5b265c0ff758354bac6a9eff97e1facDmitri Plotnikovimport android.provider.ContactsContract.Contacts; 27b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagnerimport android.provider.ContactsContract.Data; 282be1333ab5b265c0ff758354bac6a9eff97e1facDmitri Plotnikovimport android.provider.ContactsContract.Presence; 298d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylorimport android.provider.ContactsContract.Profile; 30f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Mms; 311d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.telephony.PhoneNumberUtils; 321d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.text.TextUtils; 331d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrickimport android.util.Log; 341d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 3532a1dcecca6ed0881431555a4218d0282814326cWink Savilleimport com.android.mms.LogTag; 364759133e3c935e751815bf4f997d029caa64d889Bai Taoimport com.android.mms.MmsApp; 374f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylorimport com.android.mms.R; 38d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.ui.MessageUtils; 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"; 49b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static ContactsCache sContactCache; 504f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private static final String SELF_ITEM_KEY = "Self_Item_Key"; 511d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 52d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// private static final ContentObserver sContactsObserver = new ContentObserver(new Handler()) { 53d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// @Override 54d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// public void onChange(boolean selfUpdate) { 55d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 56d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// log("contact changed, invalidate cache"); 57d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// } 58d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// invalidateCache(); 59d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// } 60d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor// }; 61458dea8d1858e418b6918f477d0139335b14ff45Tom Taylor 62d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang private static final ContentObserver sPresenceObserver = new ContentObserver(new Handler()) { 631d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick @Override 641d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public void onChange(boolean selfUpdate) { 65d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 66d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang log("presence changed, invalidate cache"); 67d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang } 681d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick invalidateCache(); 691d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 701d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick }; 711d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 72ea5e915b6104ff0e30c313bcb5a96f838997e57bMark Wagner private final static HashSet<UpdateListener> mListeners = new HashSet<UpdateListener>(); 731d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 74a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private long mContactMethodId; // Id in phone or email Uri returned by provider of current 75a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao // Contact, -1 is invalid. e.g. contact method id is 20 when 76a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao // current contact has phone content://.../phones/20. 77a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private int mContactMethodType; 781d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private String mNumber; 794759133e3c935e751815bf4f997d029caa64d889Bai Tao private String mNumberE164; 801d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private String mName; 811d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private String mNameAndNumber; // for display, e.g. Fred Flintstone <670-782-1123> 82431e11d429783c07eca6e789de0518d17b42fb74Wei Huang private boolean mNumberIsModified; // true if the number is modified 83431e11d429783c07eca6e789de0518d17b42fb74Wei Huang 84431e11d429783c07eca6e789de0518d17b42fb74Wei Huang private long mRecipientId; // used to find the Recipient cache entry 851d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private String mLabel; 861d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private long mPersonId; 871d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private int mPresenceResId; // TODO: make this a state instead of a res ID 881c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner private String mPresenceText; 891c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner private BitmapDrawable mAvatar; 90b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private byte [] mAvatarData; 91d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor private boolean mIsStale; 92161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner private boolean mQueryPending; 934f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private boolean mIsMe; // true if this contact is me! 941b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor private boolean mSendToVoicemail; // true if this contact should not put up notification 951d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 961d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public interface UpdateListener { 971d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public void onUpdate(Contact updated); 981d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 991d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 100a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private Contact(String number, String name) { 101a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao init(number, name); 102a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 103b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner /* 104b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * Make a basic contact object with a phone number. 105b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner */ 1061d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private Contact(String number) { 107a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao init(number, ""); 108a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 109a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 1104f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private Contact(boolean isMe) { 1114f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor init(SELF_ITEM_KEY, ""); 1124f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor mIsMe = isMe; 1134f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 1144f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 115a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private void init(String number, String name) { 116a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao mContactMethodId = CONTACT_METHOD_ID_UNKNOWN; 117a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao mName = name; 118431e11d429783c07eca6e789de0518d17b42fb74Wei Huang setNumber(number); 119431e11d429783c07eca6e789de0518d17b42fb74Wei Huang mNumberIsModified = false; 1201d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick mLabel = ""; 1211d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick mPersonId = 0; 1221d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick mPresenceResId = 0; 123d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor mIsStale = true; 1241b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor mSendToVoicemail = false; 1251d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 126b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner @Override 127b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public String toString() { 128a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return String.format("{ number=%s, name=%s, nameAndNumber=%s, label=%s, person_id=%d, hash=%d method_id=%d }", 129feb1aab54eabc98a04349af52e19ff9fbcd7c169Tom Taylor (mNumber != null ? mNumber : "null"), 130feb1aab54eabc98a04349af52e19ff9fbcd7c169Tom Taylor (mName != null ? mName : "null"), 131feb1aab54eabc98a04349af52e19ff9fbcd7c169Tom Taylor (mNameAndNumber != null ? mNameAndNumber : "null"), 132feb1aab54eabc98a04349af52e19ff9fbcd7c169Tom Taylor (mLabel != null ? mLabel : "null"), 133a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao mPersonId, hashCode(), 134a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao mContactMethodId); 135b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 136b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 137d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor public static void logWithTrace(String tag, String msg, Object... format) { 1381d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick Thread current = Thread.currentThread(); 1391d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick StackTraceElement[] stack = current.getStackTrace(); 1401d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1411d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick StringBuilder sb = new StringBuilder(); 1421d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append("["); 1431d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append(current.getId()); 1441d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append("] "); 1451d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append(String.format(msg, format)); 1461d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1471d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append(" <- "); 1481d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick int stop = stack.length > 7 ? 7 : stack.length; 1491d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick for (int i = 3; i < stop; i++) { 1501d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick String methodName = stack[i].getMethodName(); 1511d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append(methodName); 1521d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick if ((i+1) != stop) { 1531d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick sb.append(" <- "); 1541d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1551d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1561d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 157d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor Log.d(tag, sb.toString()); 1581d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1591d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1601d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public static Contact get(String number, boolean canBlock) { 161b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return sContactCache.get(number, canBlock); 1621d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1631d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1644f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor public static Contact getMe(boolean canBlock) { 1654f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return sContactCache.getMe(canBlock); 1664f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 1674f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 1681b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor public void removeFromCache() { 1691b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor sContactCache.remove(this); 1701b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor } 1711b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor 172a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public static List<Contact> getByPhoneUris(Parcelable[] uris) { 173a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return sContactCache.getContactInfoForPhoneUris(uris); 174a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 175a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 1761d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public static void invalidateCache() { 17732a1dcecca6ed0881431555a4218d0282814326cWink Saville if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 17832a1dcecca6ed0881431555a4218d0282814326cWink Saville log("invalidateCache"); 17932a1dcecca6ed0881431555a4218d0282814326cWink Saville } 180d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor 181d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // While invalidating our local Cache doesn't remove the contacts, it will mark them 182d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // stale so the next time we're asked for a particular contact, we'll return that 183d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // stale contact and at the same time, fire off an asyncUpdateContact to update 184d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // that contact's info in the background. UI elements using the contact typically 185d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // call addListener() so they immediately get notified when the contact has been 186d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // updated with the latest info. They redraw themselves when we call the 187d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // listener's onUpdate(). 188b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner sContactCache.invalidate(); 1891d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1901d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1914f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor public boolean isMe() { 1924f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return mIsMe; 1934f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 1944f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 1951d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick private static String emptyIfNull(String s) { 1961d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return (s != null ? s : ""); 1971d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1981d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1994759133e3c935e751815bf4f997d029caa64d889Bai Tao /** 2004759133e3c935e751815bf4f997d029caa64d889Bai Tao * Fomat the name and number. 2014759133e3c935e751815bf4f997d029caa64d889Bai Tao * 2024759133e3c935e751815bf4f997d029caa64d889Bai Tao * @param name 2034759133e3c935e751815bf4f997d029caa64d889Bai Tao * @param number 2044759133e3c935e751815bf4f997d029caa64d889Bai Tao * @param numberE164 the number's E.164 representation, is used to get the 2054759133e3c935e751815bf4f997d029caa64d889Bai Tao * country the number belongs to. 2064759133e3c935e751815bf4f997d029caa64d889Bai Tao * @return the formatted name and number 2074759133e3c935e751815bf4f997d029caa64d889Bai Tao */ 2083e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor public static String formatNameAndNumber(String name, String number, String numberE164) { 2091d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick // Format like this: Mike Cleron <(650) 555-1234> 2101d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick // Erick Tseng <(650) 555-1212> 2111d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick // Tutankhamun <tutank1341@gmail.com> 2121d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick // (408) 555-1289 2131d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick String formattedNumber = number; 2141d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick if (!Mms.isEmailAddress(number)) { 2153e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor formattedNumber = PhoneNumberUtils.formatNumber(number, numberE164, 2163e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor MmsApp.getApplication().getCurrentCountryIso()); 2171d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2181d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2191d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick if (!TextUtils.isEmpty(name) && !name.equals(number)) { 2201d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return name + " <" + formattedNumber + ">"; 2211d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } else { 2221d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return formattedNumber; 2231d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2241d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2251d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 22660d7fa5f74463f22fe9a4cd81c0b2fcc95be7c09Tom Taylor public synchronized void reload() { 22760d7fa5f74463f22fe9a4cd81c0b2fcc95be7c09Tom Taylor mIsStale = true; 22860d7fa5f74463f22fe9a4cd81c0b2fcc95be7c09Tom Taylor sContactCache.get(mNumber, false); 22960d7fa5f74463f22fe9a4cd81c0b2fcc95be7c09Tom Taylor } 23060d7fa5f74463f22fe9a4cd81c0b2fcc95be7c09Tom Taylor 2311d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized String getNumber() { 2321d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mNumber; 2331d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2341d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 23525b939e5a7ecb1e0879b684dc5bc55183cf468b4Wei Huang public synchronized void setNumber(String number) { 2363e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor if (!Mms.isEmailAddress(number)) { 2373e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor mNumber = PhoneNumberUtils.formatNumber(number, mNumberE164, 2383e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor MmsApp.getApplication().getCurrentCountryIso()); 2393e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor } else { 2403e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor mNumber = number; 2413e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor } 242dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang notSynchronizedUpdateNameAndNumber(); 243431e11d429783c07eca6e789de0518d17b42fb74Wei Huang mNumberIsModified = true; 244431e11d429783c07eca6e789de0518d17b42fb74Wei Huang } 245431e11d429783c07eca6e789de0518d17b42fb74Wei Huang 246431e11d429783c07eca6e789de0518d17b42fb74Wei Huang public boolean isNumberModified() { 247431e11d429783c07eca6e789de0518d17b42fb74Wei Huang return mNumberIsModified; 248431e11d429783c07eca6e789de0518d17b42fb74Wei Huang } 249431e11d429783c07eca6e789de0518d17b42fb74Wei Huang 2501b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor public boolean getSendToVoicemail() { 2511b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor return mSendToVoicemail; 2521b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor } 2531b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor 254431e11d429783c07eca6e789de0518d17b42fb74Wei Huang public void setIsNumberModified(boolean flag) { 255431e11d429783c07eca6e789de0518d17b42fb74Wei Huang mNumberIsModified = flag; 25625b939e5a7ecb1e0879b684dc5bc55183cf468b4Wei Huang } 25725b939e5a7ecb1e0879b684dc5bc55183cf468b4Wei Huang 2581d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized String getName() { 2591d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick if (TextUtils.isEmpty(mName)) { 2601d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mNumber; 2611d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } else { 2621d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mName; 2631d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2641d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2651d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2661d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized String getNameAndNumber() { 2671d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mNameAndNumber; 2681d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2691d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 270dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang private void notSynchronizedUpdateNameAndNumber() { 2713e54d384bed81d27dbe15a2a69344d5e64a1c018Tom Taylor mNameAndNumber = formatNameAndNumber(mName, mNumber, mNumberE164); 27225b939e5a7ecb1e0879b684dc5bc55183cf468b4Wei Huang } 27325b939e5a7ecb1e0879b684dc5bc55183cf468b4Wei Huang 274431e11d429783c07eca6e789de0518d17b42fb74Wei Huang public synchronized long getRecipientId() { 275431e11d429783c07eca6e789de0518d17b42fb74Wei Huang return mRecipientId; 276431e11d429783c07eca6e789de0518d17b42fb74Wei Huang } 277431e11d429783c07eca6e789de0518d17b42fb74Wei Huang 278431e11d429783c07eca6e789de0518d17b42fb74Wei Huang public synchronized void setRecipientId(long id) { 279431e11d429783c07eca6e789de0518d17b42fb74Wei Huang mRecipientId = id; 280431e11d429783c07eca6e789de0518d17b42fb74Wei Huang } 281431e11d429783c07eca6e789de0518d17b42fb74Wei Huang 2821d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized String getLabel() { 2831d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mLabel; 2841d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2851d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2861d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized Uri getUri() { 2872be1333ab5b265c0ff758354bac6a9eff97e1facDmitri Plotnikov return ContentUris.withAppendedId(Contacts.CONTENT_URI, mPersonId); 2881d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2891d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2901d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized int getPresenceResId() { 2911d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return mPresenceResId; 2921d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2931d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2941d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized boolean existsInDatabase() { 2951d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return (mPersonId > 0); 2961d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 2971d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 2983487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner public static void addListener(UpdateListener l) { 2993487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner synchronized (mListeners) { 3003487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner mListeners.add(l); 3013487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner } 3021d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 3031d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 3043487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner public static void removeListener(UpdateListener l) { 3053487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner synchronized (mListeners) { 3063487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner mListeners.remove(l); 3073487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner } 308d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang } 309d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang 3103487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner public static void dumpListeners() { 3113487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner synchronized (mListeners) { 3123487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner int i = 0; 3133487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner Log.i(TAG, "[Contact] dumpListeners; size=" + mListeners.size()); 3143487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner for (UpdateListener listener : mListeners) { 3153487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner Log.i(TAG, "["+ (i++) + "]" + listener); 3163487a66797bbf5339c59750c0d3d7fb703626730Mark Wagner } 317d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang } 3181d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 3191d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 3201d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public synchronized boolean isEmail() { 3211d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick return Mms.isEmailAddress(mNumber); 3221d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 3231d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 3241c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner public String getPresenceText() { 3251c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner return mPresenceText; 3261c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner } 3271c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner 328a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public int getContactMethodType() { 329a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return mContactMethodType; 330a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 331a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 332a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public long getContactMethodId() { 333a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return mContactMethodId; 334a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 335a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 336a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public synchronized Uri getPhoneUri() { 337a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (existsInDatabase()) { 338a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return ContentUris.withAppendedId(Phone.CONTENT_URI, mContactMethodId); 339a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } else { 340a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Uri.Builder ub = new Uri.Builder(); 341a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao ub.scheme(TEL_SCHEME); 342a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao ub.encodedOpaquePart(mNumber); 343a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return ub.build(); 344a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 345a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 346a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 347b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public synchronized Drawable getAvatar(Context context, Drawable defaultValue) { 348b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (mAvatar == null) { 349b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (mAvatarData != null) { 350b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Bitmap b = BitmapFactory.decodeByteArray(mAvatarData, 0, mAvatarData.length); 351b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mAvatar = new BitmapDrawable(context.getResources(), b); 352b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 353b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 3541c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner return mAvatar != null ? mAvatar : defaultValue; 3551c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner } 3561c59b33adcdc15a035fce8bd37cd02cd063b4274Mark Wagner 3571d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public static void init(final Context context) { 358b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner sContactCache = new ContactsCache(context); 359b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 3601d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick RecipientIdCache.init(context); 361d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang 362d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang // it maybe too aggressive to listen for *any* contact changes, and rebuild MMS contact 363d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang // cache each time that occurs. Unless we can get targeted updates for the contacts we 364d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang // care about(which probably won't happen for a long time), we probably should just 365d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang // invalidate cache peoridically, or surgically. 366d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang /* 3671d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick context.getContentResolver().registerContentObserver( 3682be1333ab5b265c0ff758354bac6a9eff97e1facDmitri Plotnikov Contacts.CONTENT_URI, true, sContactsObserver); 369d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang */ 3701d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 3711d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 3721d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick public static void dump() { 373b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner sContactCache.dump(); 374b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 375b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 376b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static class ContactsCache { 377b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private final TaskStack mTaskQueue = new TaskStack(); 378b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static final String SEPARATOR = ";"; 379b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 3804759133e3c935e751815bf4f997d029caa64d889Bai Tao /** 3814759133e3c935e751815bf4f997d029caa64d889Bai Tao * For a specified phone number, 2 rows were inserted into phone_lookup 3824759133e3c935e751815bf4f997d029caa64d889Bai Tao * table. One is the phone number's E164 representation, and another is 3834759133e3c935e751815bf4f997d029caa64d889Bai Tao * one's normalized format. If the phone number's normalized format in 3844759133e3c935e751815bf4f997d029caa64d889Bai Tao * the lookup table is the suffix of the given number's one, it is 3854759133e3c935e751815bf4f997d029caa64d889Bai Tao * treated as matched CallerId. E164 format number must fully equal. 3864759133e3c935e751815bf4f997d029caa64d889Bai Tao * 3874759133e3c935e751815bf4f997d029caa64d889Bai Tao * For example: Both 650-123-4567 and +1 (650) 123-4567 will match the 3884759133e3c935e751815bf4f997d029caa64d889Bai Tao * normalized number 6501234567 in the phone lookup. 3894759133e3c935e751815bf4f997d029caa64d889Bai Tao * 3904759133e3c935e751815bf4f997d029caa64d889Bai Tao * The min_match is used to narrow down the candidates for the final 3914759133e3c935e751815bf4f997d029caa64d889Bai Tao * comparison. 3924759133e3c935e751815bf4f997d029caa64d889Bai Tao */ 393b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // query params for caller id lookup 3944759133e3c935e751815bf4f997d029caa64d889Bai Tao private static final String CALLER_ID_SELECTION = " Data._ID IN " 3954759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (SELECT DISTINCT lookup.data_id " 3964759133e3c935e751815bf4f997d029caa64d889Bai Tao + " FROM " 3974759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (SELECT data_id, normalized_number, length(normalized_number) as len " 3984759133e3c935e751815bf4f997d029caa64d889Bai Tao + " FROM phone_lookup " 3994759133e3c935e751815bf4f997d029caa64d889Bai Tao + " WHERE min_match = ?) AS lookup " 4004759133e3c935e751815bf4f997d029caa64d889Bai Tao + " WHERE lookup.normalized_number = ? OR" 4014759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (lookup.len <= ? AND " 4024759133e3c935e751815bf4f997d029caa64d889Bai Tao + " substr(?, ? - lookup.len + 1) = lookup.normalized_number))"; 4034759133e3c935e751815bf4f997d029caa64d889Bai Tao 4044759133e3c935e751815bf4f997d029caa64d889Bai Tao // query params for caller id lookup without E164 number as param 4054759133e3c935e751815bf4f997d029caa64d889Bai Tao private static final String CALLER_ID_SELECTION_WITHOUT_E164 = " Data._ID IN " 4064759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (SELECT DISTINCT lookup.data_id " 4074759133e3c935e751815bf4f997d029caa64d889Bai Tao + " FROM " 4084759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (SELECT data_id, normalized_number, length(normalized_number) as len " 4094759133e3c935e751815bf4f997d029caa64d889Bai Tao + " FROM phone_lookup " 4104759133e3c935e751815bf4f997d029caa64d889Bai Tao + " WHERE min_match = ?) AS lookup " 4114759133e3c935e751815bf4f997d029caa64d889Bai Tao + " WHERE " 4124759133e3c935e751815bf4f997d029caa64d889Bai Tao + " (lookup.len <= ? AND " 4134759133e3c935e751815bf4f997d029caa64d889Bai Tao + " substr(?, ? - lookup.len + 1) = lookup.normalized_number))"; 414b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 415b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // Utilizing private API 416b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static final Uri PHONES_WITH_PRESENCE_URI = Data.CONTENT_URI; 417b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 418b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static final String[] CALLER_ID_PROJECTION = new String[] { 419a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone._ID, // 0 420a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.NUMBER, // 1 421a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.LABEL, // 2 422a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.DISPLAY_NAME, // 3 423a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.CONTACT_ID, // 4 424a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.CONTACT_PRESENCE, // 5 425a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.CONTACT_STATUS, // 6 4261b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor Phone.NORMALIZED_NUMBER, // 7 4271b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor Contacts.SEND_TO_VOICEMAIL // 8 428b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner }; 429b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 430a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int PHONE_ID_COLUMN = 0; 431a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int PHONE_NUMBER_COLUMN = 1; 432a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int PHONE_LABEL_COLUMN = 2; 433a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int CONTACT_NAME_COLUMN = 3; 434a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int CONTACT_ID_COLUMN = 4; 435a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int CONTACT_PRESENCE_COLUMN = 5; 436a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int CONTACT_STATUS_COLUMN = 6; 4374759133e3c935e751815bf4f997d029caa64d889Bai Tao private static final int PHONE_NORMALIZED_NUMBER = 7; 4381b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor private static final int SEND_TO_VOICEMAIL = 8; 439b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 4404f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private static final String[] SELF_PROJECTION = new String[] { 4414f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Phone._ID, // 0 4424f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Phone.DISPLAY_NAME, // 1 4434f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor }; 4444f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 4454f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private static final int SELF_ID_COLUMN = 0; 4464f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private static final int SELF_NAME_COLUMN = 1; 4474f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 448b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // query params for contact lookup by email 449b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static final Uri EMAIL_WITH_PRESENCE_URI = Data.CONTENT_URI; 450b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 4510a3684e0f1242518b522e2883fe275343768bb27Dmitri Plotnikov private static final String EMAIL_SELECTION = "UPPER(" + Email.DATA + ")=UPPER(?) AND " 4520a3684e0f1242518b522e2883fe275343768bb27Dmitri Plotnikov + Data.MIMETYPE + "='" + Email.CONTENT_ITEM_TYPE + "'"; 453b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 454b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static final String[] EMAIL_PROJECTION = new String[] { 455a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Email._ID, // 0 456a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Email.DISPLAY_NAME, // 1 457a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Email.CONTACT_PRESENCE, // 2 458a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Email.CONTACT_ID, // 3 459a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Phone.DISPLAY_NAME, // 4 4601b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor Contacts.SEND_TO_VOICEMAIL // 5 461b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner }; 462a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int EMAIL_ID_COLUMN = 0; 463a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int EMAIL_NAME_COLUMN = 1; 464a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int EMAIL_STATUS_COLUMN = 2; 465a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int EMAIL_CONTACT_ID_COLUMN = 3; 466a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private static final int EMAIL_CONTACT_NAME_COLUMN = 4; 4671b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor private static final int EMAIL_SEND_TO_VOICEMAIL_COLUMN = 5; 468b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 469b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private final Context mContext; 470458dea8d1858e418b6918f477d0139335b14ff45Tom Taylor 471513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner private final HashMap<String, ArrayList<Contact>> mContactsHash = 472513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner new HashMap<String, ArrayList<Contact>>(); 473513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner 474b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private ContactsCache(Context context) { 475b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mContext = context; 476b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 477458dea8d1858e418b6918f477d0139335b14ff45Tom Taylor 478b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner void dump() { 479b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (ContactsCache.this) { 480b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Log.d(TAG, "**** Contact cache dump ****"); 48140ab55a4337738075adbda3642ce0415f3810c4cMark Wagner for (String key : mContactsHash.keySet()) { 48240ab55a4337738075adbda3642ce0415f3810c4cMark Wagner ArrayList<Contact> alc = mContactsHash.get(key); 483513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner for (Contact c : alc) { 48440ab55a4337738075adbda3642ce0415f3810c4cMark Wagner Log.d(TAG, key + " ==> " + c.toString()); 485513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 486b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 487b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 488b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 489161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner 490b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private static class TaskStack { 491b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Thread mWorkerThread; 492b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private final ArrayList<Runnable> mThingsToLoad; 493b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 494b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public TaskStack() { 495b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mThingsToLoad = new ArrayList<Runnable>(); 496b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mWorkerThread = new Thread(new Runnable() { 497ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 498b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public void run() { 499b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner while (true) { 500b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Runnable r = null; 501b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (mThingsToLoad) { 502b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (mThingsToLoad.size() == 0) { 503b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner try { 504b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mThingsToLoad.wait(); 505b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } catch (InterruptedException ex) { 506b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // nothing to do 507b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 508b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 509b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (mThingsToLoad.size() > 0) { 510b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner r = mThingsToLoad.remove(0); 511161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 512161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 513b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (r != null) { 514b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner r.run(); 515161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 516161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 517b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 518ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev }, "Contact.ContactsCache.TaskStack worker thread"); 5198112b6847de98297068915e7d95a87a8dc842c64Todor Kalaydjiev mWorkerThread.setPriority(Thread.MIN_PRIORITY); 520b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mWorkerThread.start(); 521b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 522b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 523b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public void push(Runnable r) { 524b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (mThingsToLoad) { 525b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mThingsToLoad.add(r); 526b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mThingsToLoad.notify(); 527b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 528b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 529b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 530b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 531b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public void pushTask(Runnable r) { 532b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mTaskQueue.push(r); 533b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 534b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 5354f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor public Contact getMe(boolean canBlock) { 5364f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return get(SELF_ITEM_KEY, true, canBlock); 5374f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 5384f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 539b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public Contact get(String number, boolean canBlock) { 5404f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return get(number, false, canBlock); 5414f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 5424f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 5434f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private Contact get(String number, boolean isMe, boolean canBlock) { 5446f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 545d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor logWithTrace(TAG, "get(%s, %s, %s)", number, isMe, canBlock); 5466f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor } 547b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 548b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (TextUtils.isEmpty(number)) { 549b142ea00f24f4b838e6b4d0f2761eedd0f14f625Tom Taylor number = ""; // In some places (such as Korea), it's possible to receive 550b142ea00f24f4b838e6b4d0f2761eedd0f14f625Tom Taylor // a message without the sender's address. In this case, 551b142ea00f24f4b838e6b4d0f2761eedd0f14f625Tom Taylor // all such anonymous messages will get added to the same 552b142ea00f24f4b838e6b4d0f2761eedd0f14f625Tom Taylor // thread. 553b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 554b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 555b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // Always return a Contact object, if if we don't have an actual contact 556b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // in the contacts db. 5574f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Contact contact = internalGet(number, isMe); 558b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Runnable r = null; 559dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 560b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (contact) { 561b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // If there's a query pending and we're willing to block then 562b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // wait here until the query completes. 563b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner while (canBlock && contact.mQueryPending) { 564b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner try { 565b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner contact.wait(); 566b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } catch (InterruptedException ex) { 567b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // try again by virtue of the loop unless mQueryPending is false 568b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 569b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 570b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 571b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // If we're stale and we haven't already kicked off a query then kick 572b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // it off here. 573b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (contact.mIsStale && !contact.mQueryPending) { 574b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner contact.mIsStale = false; 575b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 576b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 577dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang log("async update for " + contact.toString() + " canBlock: " + canBlock + 578b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner " isStale: " + contact.mIsStale); 579b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 580b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 581b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner final Contact c = contact; 582b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner r = new Runnable() { 583ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 584b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner public void run() { 585b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner updateContact(c); 586161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 587b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner }; 588b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 589b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // set this to true while we have the lock on contact since we will 590b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // either run the query directly (canBlock case) or push the query 591b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // onto the queue. In either case the mQueryPending will get set 592b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // to false via updateContact. 593b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner contact.mQueryPending = true; 594b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 595b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 596b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // do this outside of the synchronized so we don't hold up any 597b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // subsequent calls to "get" on other threads 598b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (r != null) { 599b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (canBlock) { 600b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner r.run(); 601b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } else { 602b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner pushTask(r); 603b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 604b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 605b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return contact; 606b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 607b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 608a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao /** 609a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao * Get CacheEntry list for given phone URIs. This method will do single one query to 610a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao * get expected contacts from provider. Be sure passed in URIs are not null and contains 611a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao * only valid URIs. 612a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao */ 613a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao public List<Contact> getContactInfoForPhoneUris(Parcelable[] uris) { 614a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (uris.length == 0) { 615a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return null; 616a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 617a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao StringBuilder idSetBuilder = new StringBuilder(); 618a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao boolean first = true; 619a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao for (Parcelable p : uris) { 620a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Uri uri = (Uri) p; 621a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if ("content".equals(uri.getScheme())) { 622a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (first) { 623a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao first = false; 624a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao idSetBuilder.append(uri.getLastPathSegment()); 625a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } else { 626a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao idSetBuilder.append(',').append(uri.getLastPathSegment()); 627a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 628a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 629a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 630a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao // Check whether there is content URI. 631a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (first) return null; 632a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Cursor cursor = null; 633a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (idSetBuilder.length() > 0) { 634a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao final String whereClause = Phone._ID + " IN (" + idSetBuilder.toString() + ")"; 635a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao cursor = mContext.getContentResolver().query( 636a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao PHONES_WITH_PRESENCE_URI, CALLER_ID_PROJECTION, whereClause, null, null); 637a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 638a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 639a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (cursor == null) { 640a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return null; 641a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 642a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 643a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao List<Contact> entries = new ArrayList<Contact>(); 644a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 645a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao try { 646a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao while (cursor.moveToNext()) { 647a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao Contact entry = new Contact(cursor.getString(PHONE_NUMBER_COLUMN), 648a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao cursor.getString(CONTACT_NAME_COLUMN)); 649a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao fillPhoneTypeContact(entry, cursor); 650a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao ArrayList<Contact> value = new ArrayList<Contact>(); 651a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao value.add(entry); 652a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao // Put the result in the cache. 653a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao mContactsHash.put(key(entry.mNumber, sStaticKeyBuffer), value); 654a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao entries.add(entry); 655a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 656a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } finally { 657a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao cursor.close(); 658a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 659a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return entries; 660a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 661a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 662b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private boolean contactChanged(Contact orig, Contact newContactData) { 663b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // The phone number should never change, so don't bother checking. 664b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // TODO: Maybe update it if it has gotten longer, i.e. 650-234-5678 -> +16502345678? 665b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 666a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao // Do the quick check first. 667a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (orig.mContactMethodType != newContactData.mContactMethodType) { 668b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return true; 669b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 670b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 671a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (orig.mContactMethodId != newContactData.mContactMethodId) { 672b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return true; 673b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 674b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 675b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (orig.mPersonId != newContactData.mPersonId) { 6766f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 6776f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor Log.d(TAG, "person id changed"); 6786f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor } 679b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return true; 680b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 681b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 682b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (orig.mPresenceResId != newContactData.mPresenceResId) { 6836f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 6846f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor Log.d(TAG, "presence changed"); 6856f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor } 686b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return true; 687b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 688b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 6891b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor if (orig.mSendToVoicemail != newContactData.mSendToVoicemail) { 6901b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor return true; 6911b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor } 6921b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor 693a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao String oldName = emptyIfNull(orig.mName); 694a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao String newName = emptyIfNull(newContactData.mName); 695a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (!oldName.equals(newName)) { 6966f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 6976f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor Log.d(TAG, String.format("name changed: %s -> %s", oldName, newName)); 6986f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor } 699a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return true; 700a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 701a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 702a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao String oldLabel = emptyIfNull(orig.mLabel); 703a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao String newLabel = emptyIfNull(newContactData.mLabel); 704a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao if (!oldLabel.equals(newLabel)) { 7056f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 7066f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor Log.d(TAG, String.format("label changed: %s -> %s", oldLabel, newLabel)); 7076f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor } 708a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao return true; 709a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 710a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 711b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (!Arrays.equals(orig.mAvatarData, newContactData.mAvatarData)) { 7126f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 7136f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor Log.d(TAG, "avatar changed"); 7146f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor } 715b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return true; 716b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 717b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 718b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return false; 719b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 720b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 721b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private void updateContact(final Contact c) { 722b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (c == null) { 723b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return; 724b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 725b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 7264f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Contact entry = getContactInfo(c); 727dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang synchronized (c) { 728b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (contactChanged(c, entry)) { 729b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 730b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner log("updateContact: contact changed for " + entry.mName); 731161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 732b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 733b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mNumber = entry.mNumber; 734b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mLabel = entry.mLabel; 735b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mPersonId = entry.mPersonId; 736b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mPresenceResId = entry.mPresenceResId; 737b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mPresenceText = entry.mPresenceText; 738b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mAvatarData = entry.mAvatarData; 739b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mAvatar = entry.mAvatar; 740a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao c.mContactMethodId = entry.mContactMethodId; 741a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao c.mContactMethodType = entry.mContactMethodType; 7424759133e3c935e751815bf4f997d029caa64d889Bai Tao c.mNumberE164 = entry.mNumberE164; 7434f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor c.mName = entry.mName; 7441b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor c.mSendToVoicemail = entry.mSendToVoicemail; 745dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 746dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang c.notSynchronizedUpdateNameAndNumber(); 747b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 748ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // We saw a bug where we were updating an empty contact. That would trigger 749ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // l.onUpdate() below, which would call ComposeMessageActivity.onUpdate, 750ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // which would call the adapter's notifyDataSetChanged, which would throw 751ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // away the message items and rebuild, eventually calling updateContact() 752ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // again -- all in a vicious and unending loop. Break the cycle and don't 753ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // notify if the number (the most important piece of information) is empty. 754ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor if (!TextUtils.isEmpty(c.mNumber)) { 755ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // clone the list of listeners in case the onUpdate call turns around and 756ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // modifies the list of listeners 757ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor // access to mListeners is synchronized on ContactsCache 758ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor HashSet<UpdateListener> iterator; 759ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor synchronized (mListeners) { 760ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor iterator = (HashSet<UpdateListener>)Contact.mListeners.clone(); 761ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor } 762ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor for (UpdateListener l : iterator) { 7636f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 7646f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor Log.d(TAG, "updating " + l); 7656f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor } 766ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor l.onUpdate(c); 767ad5cd4c952745600c8b5a0ca06455f5bae0dacddTom Taylor } 768b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 769b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 770b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (c) { 771b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.mQueryPending = false; 772b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner c.notifyAll(); 773161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 774b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 775161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner } 776161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner 777b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner /** 778b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * Returns the caller info in Contact. 779b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner */ 7804f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private Contact getContactInfo(Contact c) { 7814f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if (c.mIsMe) { 7824f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return getContactInfoForSelf(); 7834f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } else if (Mms.isEmailAddress(c.mNumber) || isAlphaNumber(c.mNumber)) { 7844f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return getContactInfoForEmailAddress(c.mNumber); 785b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } else { 7864f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return getContactInfoForPhoneNumber(c.mNumber); 787b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 78833a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick } 78933a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick 7906ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // Some received sms's have addresses such as "OakfieldCPS" or "T-Mobile". This 7916ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // function will attempt to identify these and return true. If the number contains 7926ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // 3 or more digits, such as "jello123", this function will return false. 7936ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // Some countries have 3 digits shortcodes and we have to identify them as numbers. 7946ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // http://en.wikipedia.org/wiki/Short_code 7956ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // Examples of input/output for this function: 7966ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "Jello123" -> false [3 digits, it is considered to be the phone number "123"] 7976ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "T-Mobile" -> true [it is considered to be the address "T-Mobile"] 7986ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "Mobile1" -> true [1 digit, it is considered to be the address "Mobile1"] 7996ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "Dogs77" -> true [2 digits, it is considered to be the address "Dogs77"] 8006ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "****1" -> true [1 digits, it is considered to be the address "****1"] 8016ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "#4#5#6#" -> true [it is considered to be the address "#4#5#6#"] 8026ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "AB12" -> true [2 digits, it is considered to be the address "AB12"] 8036ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "12" -> true [2 digits, it is considered to be the address "12"] 8046ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor private boolean isAlphaNumber(String number) { 8056ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // TODO: PhoneNumberUtils.isWellFormedSmsAddress() only check if the number is a valid 8066ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // GSM SMS address. If the address contains a dialable char, it considers it a well 8076ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // formed SMS addr. CDMA doesn't work that way and has a different parser for SMS 8086ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // address (see CdmaSmsAddress.parse(String address)). We should definitely fix this!!! 8096ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor if (!PhoneNumberUtils.isWellFormedSmsAddress(number)) { 8106ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // The example "T-Mobile" will exit here because there are no numbers. 8116ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor return true; // we're not an sms address, consider it an alpha number 8126ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor } 813d7fddfa20e7bfe9f0bf376f9cce9188bf9bf0354Tom Taylor if (MessageUtils.isAlias(number)) { 814d7fddfa20e7bfe9f0bf376f9cce9188bf9bf0354Tom Taylor return true; 815d7fddfa20e7bfe9f0bf376f9cce9188bf9bf0354Tom Taylor } 8166ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor number = PhoneNumberUtils.extractNetworkPortion(number); 8176ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor if (TextUtils.isEmpty(number)) { 8186ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor return true; // there are no digits whatsoever in the number 8196ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor } 8206ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // At this point, anything like "Mobile1" or "Dogs77" will be stripped down to 8216ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor // "1" and "77". "#4#5#6#" remains as "#4#5#6#" at this point. 8226ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor return number.length() < 3; 8236ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor } 8246ac26ca62ba1e4252bf93672abd370966d3fb7c3Tom Taylor 825b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner /** 826b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * Queries the caller id info with the phone number. 827b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * @return a Contact containing the caller id info corresponding to the number. 828b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner */ 829b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private Contact getContactInfoForPhoneNumber(String number) { 830b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner number = PhoneNumberUtils.stripSeparators(number); 831b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Contact entry = new Contact(number); 832a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao entry.mContactMethodType = CONTACT_METHOD_TYPE_PHONE; 833b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 8346f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 8356f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor log("queryContactInfoByNumber: number=" + number); 8366f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor } 837b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 8384759133e3c935e751815bf4f997d029caa64d889Bai Tao String normalizedNumber = PhoneNumberUtils.normalizeNumber(number); 8394759133e3c935e751815bf4f997d029caa64d889Bai Tao String minMatch = PhoneNumberUtils.toCallerIDMinMatch(normalizedNumber); 8404759133e3c935e751815bf4f997d029caa64d889Bai Tao if (!TextUtils.isEmpty(normalizedNumber) && !TextUtils.isEmpty(minMatch)) { 8414759133e3c935e751815bf4f997d029caa64d889Bai Tao String numberLen = String.valueOf(normalizedNumber.length()); 8424759133e3c935e751815bf4f997d029caa64d889Bai Tao String numberE164 = PhoneNumberUtils.formatNumberToE164( 8434759133e3c935e751815bf4f997d029caa64d889Bai Tao number, MmsApp.getApplication().getCurrentCountryIso()); 8444759133e3c935e751815bf4f997d029caa64d889Bai Tao String selection; 8454759133e3c935e751815bf4f997d029caa64d889Bai Tao String[] args; 8464759133e3c935e751815bf4f997d029caa64d889Bai Tao if (TextUtils.isEmpty(numberE164)) { 8474759133e3c935e751815bf4f997d029caa64d889Bai Tao selection = CALLER_ID_SELECTION_WITHOUT_E164; 8484759133e3c935e751815bf4f997d029caa64d889Bai Tao args = new String[] {minMatch, numberLen, normalizedNumber, numberLen}; 8494759133e3c935e751815bf4f997d029caa64d889Bai Tao } else { 8504759133e3c935e751815bf4f997d029caa64d889Bai Tao selection = CALLER_ID_SELECTION; 8514759133e3c935e751815bf4f997d029caa64d889Bai Tao args = new String[] { 8524759133e3c935e751815bf4f997d029caa64d889Bai Tao minMatch, numberE164, numberLen, normalizedNumber, numberLen}; 8534759133e3c935e751815bf4f997d029caa64d889Bai Tao } 854b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 8554759133e3c935e751815bf4f997d029caa64d889Bai Tao Cursor cursor = mContext.getContentResolver().query( 8564759133e3c935e751815bf4f997d029caa64d889Bai Tao PHONES_WITH_PRESENCE_URI, CALLER_ID_PROJECTION, selection, args, null); 8574759133e3c935e751815bf4f997d029caa64d889Bai Tao if (cursor == null) { 8584759133e3c935e751815bf4f997d029caa64d889Bai Tao Log.w(TAG, "queryContactInfoByNumber(" + number + ") returned NULL cursor!" 8594759133e3c935e751815bf4f997d029caa64d889Bai Tao + " contact uri used " + PHONES_WITH_PRESENCE_URI); 8604759133e3c935e751815bf4f997d029caa64d889Bai Tao return entry; 8614759133e3c935e751815bf4f997d029caa64d889Bai Tao } 862b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 8634759133e3c935e751815bf4f997d029caa64d889Bai Tao try { 8644759133e3c935e751815bf4f997d029caa64d889Bai Tao if (cursor.moveToFirst()) { 8654759133e3c935e751815bf4f997d029caa64d889Bai Tao fillPhoneTypeContact(entry, cursor); 8664759133e3c935e751815bf4f997d029caa64d889Bai Tao } 8674759133e3c935e751815bf4f997d029caa64d889Bai Tao } finally { 8684759133e3c935e751815bf4f997d029caa64d889Bai Tao cursor.close(); 869b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 870b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 871b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return entry; 87233a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick } 87333a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick 8744f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor /** 8754f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor * @return a Contact containing the info for the profile. 8764f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor */ 8774f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private Contact getContactInfoForSelf() { 8784f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Contact entry = new Contact(true); 8794f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor entry.mContactMethodType = CONTACT_METHOD_TYPE_SELF; 8804f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 8816f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 8826f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor log("getContactInfoForSelf"); 8836f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor } 8844f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Cursor cursor = mContext.getContentResolver().query( 8854f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Profile.CONTENT_URI, SELF_PROJECTION, null, null, null); 8864f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if (cursor == null) { 8874f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Log.w(TAG, "getContactInfoForSelf() returned NULL cursor!" 8884f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor + " contact uri used " + Profile.CONTENT_URI); 8894f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return entry; 8904f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 8914f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 8924f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor try { 8934f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if (cursor.moveToFirst()) { 8944f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor fillSelfContact(entry, cursor); 8954f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 8964f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } finally { 8974f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor cursor.close(); 8984f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 8994f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor return entry; 9004f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 9014f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 902a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao private void fillPhoneTypeContact(final Contact contact, final Cursor cursor) { 903a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao synchronized (contact) { 904a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mContactMethodType = CONTACT_METHOD_TYPE_PHONE; 905a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mContactMethodId = cursor.getLong(PHONE_ID_COLUMN); 906a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mLabel = cursor.getString(PHONE_LABEL_COLUMN); 907a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mName = cursor.getString(CONTACT_NAME_COLUMN); 908a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mPersonId = cursor.getLong(CONTACT_ID_COLUMN); 909a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mPresenceResId = getPresenceIconResourceId( 910a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao cursor.getInt(CONTACT_PRESENCE_COLUMN)); 911a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mPresenceText = cursor.getString(CONTACT_STATUS_COLUMN); 9124759133e3c935e751815bf4f997d029caa64d889Bai Tao contact.mNumberE164 = cursor.getString(PHONE_NORMALIZED_NUMBER); 9131b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor contact.mSendToVoicemail = cursor.getInt(SEND_TO_VOICEMAIL) == 1; 9146f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 9154f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor log("fillPhoneTypeContact: name=" + contact.mName + ", number=" 9161b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor + contact.mNumber + ", presence=" + contact.mPresenceResId 9171b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor + " SendToVoicemail: " + contact.mSendToVoicemail); 918a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 919a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 920a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao byte[] data = loadAvatarData(contact); 921a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao 922a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao synchronized (contact) { 923a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao contact.mAvatarData = data; 924a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 925a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao } 9264f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 9274f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private void fillSelfContact(final Contact contact, final Cursor cursor) { 9284f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor synchronized (contact) { 9294f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor contact.mName = cursor.getString(SELF_NAME_COLUMN); 9304f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if (TextUtils.isEmpty(contact.mName)) { 9314f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor contact.mName = mContext.getString(R.string.messagelist_sender_self); 9324f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 9336f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 9344f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor log("fillSelfContact: name=" + contact.mName + ", number=" 9354f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor + contact.mNumber); 9364f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 9374f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 9384f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor byte[] data = loadAvatarData(contact); 9394f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor 9404f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor synchronized (contact) { 9414f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor contact.mAvatarData = data; 9424f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 9434f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor } 944b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner /* 945b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * Load the avatar data from the cursor into memory. Don't decode the data 946b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * until someone calls for it (see getAvatar). Hang onto the raw data so that 947b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * we can compare it when the data is reloaded. 948b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * TODO: consider comparing a checksum so that we don't have to hang onto 949b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * the raw bytes after the image is decoded. 950b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner */ 951dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang private byte[] loadAvatarData(Contact entry) { 952dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang byte [] data = null; 953dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 9544f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor if ((!entry.mIsMe && entry.mPersonId == 0) || entry.mAvatar != null) { 955dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang return null; 956b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 957b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 9586f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 9598d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylor log("loadAvatarData: name=" + entry.mName + ", number=" + entry.mNumber); 960313d09ee558e6ac94ab28a205357885dc830cd0dTom Taylor } 961313d09ee558e6ac94ab28a205357885dc830cd0dTom Taylor 9628d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylor // If the contact is "me", then use my local profile photo. Otherwise, build a 9638d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylor // uri to get the avatar of the contact. 9644f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Uri contactUri = entry.mIsMe ? 9658d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylor Profile.CONTENT_URI : 9668d54acc063c03b42c9b10dbd013a1552ebbe2d9fTom Taylor ContentUris.withAppendedId(Contacts.CONTENT_URI, entry.mPersonId); 967b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 968dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang InputStream avatarDataStream = Contacts.openContactPhotoInputStream( 969b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner mContext.getContentResolver(), 970b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner contactUri); 971b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner try { 972b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (avatarDataStream != null) { 973dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang data = new byte[avatarDataStream.available()]; 974b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner avatarDataStream.read(data, 0, data.length); 975b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 976b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } catch (IOException ex) { 977b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner // 978b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } finally { 979b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner try { 980b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (avatarDataStream != null) { 981b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner avatarDataStream.close(); 982b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 983b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } catch (IOException e) { 984b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 985b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 986dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 987dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang return data; 9881d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 9891d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 990b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private int getPresenceIconResourceId(int presence) { 9916be18bedb5b87dbbcdb54f37d5a0945bd0f71377Tom Taylor // TODO: must fix for SDK 992b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (presence != Presence.OFFLINE) { 993b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return Presence.getPresenceIconResourceId(presence); 994b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 995b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 996b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return 0; 997b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 998b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 999b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner /** 1000b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner * Query the contact email table to get the name of an email address. 1001b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner */ 1002b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner private Contact getContactInfoForEmailAddress(String email) { 1003b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Contact entry = new Contact(email); 1004a6dd14dc0963aa8f30e625aa88e925e3fa0744f0Bai Tao entry.mContactMethodType = CONTACT_METHOD_TYPE_EMAIL; 1005b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 1006b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner Cursor cursor = SqliteWrapper.query(mContext, mContext.getContentResolver(), 1007b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner EMAIL_WITH_PRESENCE_URI, 1008b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner EMAIL_PROJECTION, 1009b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner EMAIL_SELECTION, 1010dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang new String[] { email }, 1011b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner null); 1012b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner 1013b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner if (cursor != null) { 1014b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner try { 1015b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner while (cursor.moveToNext()) { 1016dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang boolean found = false; 1017dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang synchronized (entry) { 10180cf7a7c3bf1e23e03933eddb9bfc4b67f568fc16Tom Taylor entry.mContactMethodId = cursor.getLong(EMAIL_ID_COLUMN); 1019dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang entry.mPresenceResId = getPresenceIconResourceId( 1020dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang cursor.getInt(EMAIL_STATUS_COLUMN)); 10210cf7a7c3bf1e23e03933eddb9bfc4b67f568fc16Tom Taylor entry.mPersonId = cursor.getLong(EMAIL_CONTACT_ID_COLUMN); 10220cf7a7c3bf1e23e03933eddb9bfc4b67f568fc16Tom Taylor entry.mSendToVoicemail = 10230cf7a7c3bf1e23e03933eddb9bfc4b67f568fc16Tom Taylor cursor.getInt(EMAIL_SEND_TO_VOICEMAIL_COLUMN) == 1; 1024dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 1025dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang String name = cursor.getString(EMAIL_NAME_COLUMN); 1026dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang if (TextUtils.isEmpty(name)) { 1027dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang name = cursor.getString(EMAIL_CONTACT_NAME_COLUMN); 1028dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang } 1029dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang if (!TextUtils.isEmpty(name)) { 1030dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang entry.mName = name; 10316f21719c32796092cb2d07a3d375633a1f3c4c6bTom Taylor if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) { 1032dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang log("getContactInfoForEmailAddress: name=" + entry.mName + 1033dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang ", email=" + email + ", presence=" + 1034dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang entry.mPresenceResId); 1035dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang } 1036dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang found = true; 1037dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang } 1038b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 1039dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 1040dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang if (found) { 1041dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang byte[] data = loadAvatarData(entry); 1042dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang synchronized (entry) { 1043dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang entry.mAvatarData = data; 1044b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 1045dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang 1046b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner break; 1047b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 1048b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } 1049b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner } finally { 1050b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner cursor.close(); 10511d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10521d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1053b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner return entry; 10541d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10551d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1056513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // Invert and truncate to five characters the phoneNumber so that we 1057513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // can use it as the key in a hashtable. We keep a mapping of this 1058513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // key to a list of all contacts which have the same key. 105940ab55a4337738075adbda3642ce0415f3810c4cMark Wagner private String key(String phoneNumber, CharBuffer keyBuffer) { 1060513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner keyBuffer.clear(); 1061513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner keyBuffer.mark(); 1062513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner 1063513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner int position = phoneNumber.length(); 1064513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner int resultCount = 0; 1065513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner while (--position >= 0) { 1066513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner char c = phoneNumber.charAt(position); 1067513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (Character.isDigit(c)) { 1068513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner keyBuffer.put(c); 1069513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (++resultCount == STATIC_KEY_BUFFER_MAXIMUM_LENGTH) { 1070513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner break; 10711d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10721d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1073513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 1074513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner keyBuffer.reset(); 1075513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (resultCount > 0) { 107640ab55a4337738075adbda3642ce0415f3810c4cMark Wagner return keyBuffer.toString(); 1077513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } else { 1078513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // there were no usable digits in the input phoneNumber 1079513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner return phoneNumber; 10801d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10811d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 10821d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1083513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // Reuse this so we don't have to allocate each time we go through this 1084513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // "get" function. 1085513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner static final int STATIC_KEY_BUFFER_MAXIMUM_LENGTH = 5; 1086513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner static CharBuffer sStaticKeyBuffer = CharBuffer.allocate(STATIC_KEY_BUFFER_MAXIMUM_LENGTH); 10871d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 10884f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor private Contact internalGet(String numberOrEmail, boolean isMe) { 1089b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (ContactsCache.this) { 1090513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // See if we can find "number" in the hashtable. 1091513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // If so, just return the result. 10924f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor final boolean isNotRegularPhoneNumber = isMe || Mms.isEmailAddress(numberOrEmail) || 1093dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang MessageUtils.isAlias(numberOrEmail); 1094dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang final String key = isNotRegularPhoneNumber ? 1095dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang numberOrEmail : key(numberOrEmail, sStaticKeyBuffer); 1096513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner 1097513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner ArrayList<Contact> candidates = mContactsHash.get(key); 1098513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (candidates != null) { 1099513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner int length = candidates.size(); 1100513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner for (int i = 0; i < length; i++) { 1101513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner Contact c= candidates.get(i); 1102513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (isNotRegularPhoneNumber) { 1103513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (numberOrEmail.equals(c.mNumber)) { 1104513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner return c; 1105513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 1106513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } else { 1107513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner if (PhoneNumberUtils.compare(numberOrEmail, c.mNumber)) { 1108513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner return c; 1109513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 1110513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 11111d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 1112513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } else { 1113513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner candidates = new ArrayList<Contact>(); 1114513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner // call toString() since it may be the static CharBuffer 111540ab55a4337738075adbda3642ce0415f3810c4cMark Wagner mContactsHash.put(key, candidates); 11161d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 11174f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor Contact c = isMe ? 11184f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor new Contact(true) : 11194f1871e8e85598c94d5f09d508c690c41fdcce16Tom Taylor new Contact(numberOrEmail); 1120513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner candidates.add(c); 1121161c3cfe3480ab8b1b585cc0d3601f0cacc28c6dMark Wagner return c; 11221d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 11231d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 11241d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick 1125b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner void invalidate() { 1126d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // Don't remove the contacts. Just mark them stale so we'll update their 1127d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor // info, particularly their presence. 1128b54460a3af15ca85c2a7b6d5422e9e5eb4592fa8Mark Wagner synchronized (ContactsCache.this) { 1129513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner for (ArrayList<Contact> alc : mContactsHash.values()) { 1130513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner for (Contact c : alc) { 1131dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang synchronized (c) { 1132dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang c.mIsStale = true; 1133dc7f95eaf3f1668e90e1add17e07fd3b4b839535Wei Huang } 1134513ec194e86409bac7d2ca61a4edcbbe6a36181eMark Wagner } 1135d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor } 1136d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor } 1137d09e218e2278acb6276207bddfbef1761617e8f8Tom Taylor } 11381b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor 11391b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor // Remove a contact from the ContactsCache based on the number or email address 11401b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor private void remove(Contact contact) { 11411b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor synchronized (ContactsCache.this) { 11421b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor String number = contact.getNumber(); 11431b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor final boolean isNotRegularPhoneNumber = contact.isMe() || 11441b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor Mms.isEmailAddress(number) || 11451b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor MessageUtils.isAlias(number); 11461b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor final String key = isNotRegularPhoneNumber ? 11471b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor number : key(number, sStaticKeyBuffer); 11481b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor ArrayList<Contact> candidates = mContactsHash.get(key); 11491b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor if (candidates != null) { 11501b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor int length = candidates.size(); 11511b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor for (int i = 0; i < length; i++) { 11521b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor Contact c = candidates.get(i); 11531b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor if (isNotRegularPhoneNumber) { 11541b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor if (number.equals(c.mNumber)) { 11551b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor candidates.remove(i); 11561b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor break; 11571b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor } 11581b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor } else { 11591b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor if (PhoneNumberUtils.compare(number, c.mNumber)) { 11601b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor candidates.remove(i); 11611b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor break; 11621b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor } 11631b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor } 11641b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor } 11651b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor if (candidates.size() == 0) { 11661b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor mContactsHash.remove(key); 11671b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor } 11681b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor } 11691b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor } 11701b1af7c751218e380bd119629ff9a652157fbb21Tom Taylor } 117132a1dcecca6ed0881431555a4218d0282814326cWink Saville } 117232a1dcecca6ed0881431555a4218d0282814326cWink Saville 117332a1dcecca6ed0881431555a4218d0282814326cWink Saville private static void log(String msg) { 117432a1dcecca6ed0881431555a4218d0282814326cWink Saville Log.d(TAG, msg); 11751d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick } 11761d98ae0b203e01034ddead4214d1520ce863a23bFicus Kirkpatrick} 1177