Fields Summary |
---|
private static final String | TAG |
private static final boolean | LOCAL_DEBUG |
private static final long | REBUILD_DELAY |
private static final String | SEPARATOR |
private static final String | CALLER_ID_SELECTION |
private static final android.net.Uri | PHONES_WITH_PRESENCE_URI |
private static final String[] | CALLER_ID_PROJECTION |
private static final int | PHONE_NUMBER_COLUMN |
private static final int | PHONE_LABEL_COLUMN |
private static final int | CONTACT_NAME_COLUMN |
private static final int | CONTACT_ID_COLUMN |
private static final int | CONTACT_PRESENCE_COLUMN |
private static final String | CONTACT_METHOD_SELECTION |
private static final android.net.Uri | CONTACT_METHOD_WITH_PRESENCE_URI |
private static final String[] | CONTACT_METHOD_PROJECTION |
private static final int | CONTACT_METHOD_NAME_COLUMN |
private static final int | CONTACT_METHOD_STATUS_COLUMN |
private static final int | CONTACT_METHOD_ID_COLUMN |
private static ContactInfoCache | sInstance |
private final android.content.Context | mContext |
private String[] | mContactInfoSelectionArgs |
private final HashMap | mCache |
private Thread | mCacheRebuilder |
private Object | mCacheRebuildLock |
private boolean | mPhoneCacheInvalidated |
private boolean | mEmailCacheInvalidated |
Methods Summary |
---|
public void | dump()
synchronized (mCache) {
Log.i(TAG, "ContactInfoCache.dump");
for (String name : mCache.keySet()) {
CacheEntry entry = mCache.get(name);
if (entry != null) {
Log.i(TAG, "key=" + name + ", cacheEntry={" + entry.toString() + '}");
} else {
Log.i(TAG, "key=" + name + ", cacheEntry={null}");
}
}
}
|
private java.lang.String | getCallerId(android.content.Context context, java.lang.String number)A cached version of CallerInfo.getCallerId().
ContactInfoCache.CacheEntry entry = getContactInfo(context, number);
if (entry != null && !TextUtils.isEmpty(entry.name)) {
return entry.name;
}
return number;
|
public com.android.mms.util.ContactInfoCache$CacheEntry | getContactInfo(android.content.Context context, java.lang.String numberOrEmail)Returns the caller info in CacheEntry.
if (Mms.isEmailAddress(numberOrEmail)) {
return getContactInfoForEmailAddress(context, numberOrEmail, true /* allow query */);
} else {
return getContactInfoForPhoneNumber(context, numberOrEmail, true /* allow query */);
}
|
public com.android.mms.util.ContactInfoCache$CacheEntry | getContactInfoForEmailAddress(android.content.Context context, java.lang.String email, boolean allowQuery)Returns the contact info for a given email address
synchronized (mCache) {
if (mCache.containsKey(email)) {
CacheEntry entry = mCache.get(email);
if (!allowQuery || !entry.isStale()) {
return entry;
}
} else if (!allowQuery) {
return null;
}
CacheEntry entry = queryEmailDisplayName(context, email);
mCache.put(email, entry);
return entry;
}
|
public com.android.mms.util.ContactInfoCache$CacheEntry | getContactInfoForPhoneNumber(android.content.Context context, java.lang.String number, boolean allowQuery)Returns the caller info in a CacheEntry. If 'noQuery' is set to true, then this
method only checks in the cache and makes no content provider query.
// TODO: numbers like "6501234567" and "+16501234567" are equivalent.
// we should convert them into a uniform format so that we don't cache
// them twice.
number = Recipient.filterPhoneNumber(number);
synchronized (mCache) {
if (mCache.containsKey(number)) {
CacheEntry entry = mCache.get(number);
if (LOCAL_DEBUG) {
log("getContactInfo: number=" + number + ", name=" + entry.name +
", presence=" + entry.presenceResId);
}
if (!allowQuery || !entry.isStale()) {
return entry;
}
} else if (!allowQuery) {
return null;
}
CacheEntry entry = queryContactInfoByNumber(context, number);
mCache.put(number, entry);
return entry;
}
|
public java.lang.String | getContactName(android.content.Context context, java.lang.String address)Get the display names of contacts. Contacts can be either email address or
phone number.
if (TextUtils.isEmpty(address)) {
return "";
}
StringBuilder result = new StringBuilder();
for (String value : address.split(SEPARATOR)) {
if (value.length() > 0) {
result.append(SEPARATOR);
if (MessageUtils.isLocalNumber(value)) {
result.append(context.getString(com.android.internal.R.string.me));
} else if (Mms.isEmailAddress(value)) {
result.append(getDisplayName(context, value));
} else {
result.append(getCallerId(context, value));
}
}
}
if (result.length() > 0) {
// Skip the first ";"
return result.substring(1);
}
return "";
|
public java.lang.String | getDisplayName(android.content.Context context, java.lang.String email)Get the display name of an email address. If the address already contains
the name, parse and return it. Otherwise, query the contact database. Cache
query results for repeated queries.
Matcher match = Mms.NAME_ADDR_EMAIL_PATTERN.matcher(email);
if (match.matches()) {
// email has display name
return getEmailDisplayName(match.group(1));
}
CacheEntry entry = getContactInfoForEmailAddress(context, email, true /* allow query */);
if (entry != null && entry.name != null) {
return entry.name;
}
return email;
|
private static java.lang.String | getEmailDisplayName(java.lang.String displayString)
Matcher match = Mms.QUOTED_STRING_PATTERN.matcher(displayString);
if (match.matches()) {
return match.group(1);
}
return displayString;
|
public static com.android.mms.util.ContactInfoCache | getInstance()Get the global instance.
return sInstance;
|
private int | getPresenceIconResourceId(int presence)
if (presence != Contacts.People.OFFLINE) {
return Contacts.Presence.getPresenceIconResourceId(presence);
}
return 0;
|
private void | getRebuildList(java.util.List phones, java.util.List emails)Get the list of phone/email candidates for the cache rebuilding. This is
a snapshot of the keys in the cache.
synchronized (mCache) {
for (String name : mCache.keySet()) {
if (Mms.isEmailAddress(name)) {
if (emails != null) {
emails.add(name);
}
} else {
if (phones != null) {
phones.add(name);
}
}
}
}
|
public static void | init(android.content.Context context)Initialize the global instance. Should call only once.
sInstance = new ContactInfoCache(context);
|
public void | invalidateCache()invalidates the cache entries by marking CacheEntry.isStale to true.
synchronized (mCache) {
for (Map.Entry<String, CacheEntry> e: mCache.entrySet()) {
CacheEntry entry = e.getValue();
entry.isStale = true;
}
}
|
public void | invalidateContact(java.lang.String emailOrNumber)invalidates a single cache entry. Can pass in an email or number.
synchronized (mCache) {
CacheEntry entry = mCache.get(emailOrNumber);
if (entry != null) {
entry.isStale = true;
}
}
|
private void | log(java.lang.String msg)
Log.d(TAG, "[ContactInfoCache] " + msg);
|
private com.android.mms.util.ContactInfoCache$CacheEntry | queryContactInfoByNumber(android.content.Context context, java.lang.String number)Queries the caller id info with the phone number.
CacheEntry entry = new CacheEntry();
entry.phoneNumber = number;
//if (LOCAL_DEBUG) log("queryContactInfoByNumber: number=" + number);
mContactInfoSelectionArgs[0] = number;
Cursor cursor = context.getContentResolver().query(
PHONES_WITH_PRESENCE_URI,
CALLER_ID_PROJECTION,
CALLER_ID_SELECTION,
mContactInfoSelectionArgs,
null);
try {
if (cursor.moveToFirst()) {
entry.phoneLabel = cursor.getString(PHONE_LABEL_COLUMN);
entry.name = cursor.getString(CONTACT_NAME_COLUMN);
entry.person_id = cursor.getLong(CONTACT_ID_COLUMN);
entry.presenceResId = getPresenceIconResourceId(
cursor.getInt(CONTACT_PRESENCE_COLUMN));
if (LOCAL_DEBUG) {
log("queryContactInfoByNumber: name=" + entry.name + ", number=" + number +
", presence=" + entry.presenceResId);
}
}
} finally {
cursor.close();
}
return entry;
|
private com.android.mms.util.ContactInfoCache$CacheEntry | queryEmailDisplayName(android.content.Context context, java.lang.String email)Query the contact email table to get the name of an email address.
CacheEntry entry = new CacheEntry();
mContactInfoSelectionArgs[0] = email;
Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
CONTACT_METHOD_WITH_PRESENCE_URI,
CONTACT_METHOD_PROJECTION,
CONTACT_METHOD_SELECTION,
mContactInfoSelectionArgs,
null);
if (cursor != null) {
try {
while (cursor.moveToNext()) {
entry.presenceResId = getPresenceIconResourceId(
cursor.getInt(CONTACT_METHOD_STATUS_COLUMN));
entry.person_id = cursor.getLong(CONTACT_METHOD_ID_COLUMN);
String name = cursor.getString(CONTACT_METHOD_NAME_COLUMN);
if (!TextUtils.isEmpty(name)) {
entry.name = name;
if (LOCAL_DEBUG) {
log("queryEmailDisplayName: name=" + entry.name + ", email=" + email +
", presence=" + entry.presenceResId);
}
break;
}
}
} finally {
cursor.close();
}
}
return entry;
|
private void | rebuildCache()The actual work of rebuilding the cache, i.e. syncing our cache with
the contacts database.
List<String> phones;
List<String> emails;
for (;;) {
// simulate the Nagle's algorithm:
// delay for a while to prevent from getting too busy, when, say,
// there is a big contacts sync going on
try {
Thread.sleep(REBUILD_DELAY);
} catch (InterruptedException ie) {
}
phones = null;
emails = null;
synchronized (mCacheRebuildLock) {
// if nothing changed during our sync, stop this thread
// otherwise, just keep working on it.
if (!(mPhoneCacheInvalidated || mEmailCacheInvalidated)) {
mCacheRebuilder = null;
return;
}
if (mPhoneCacheInvalidated) {
phones = new ArrayList<String>();
mPhoneCacheInvalidated = false;
}
if (mEmailCacheInvalidated) {
emails = new ArrayList<String>();
mEmailCacheInvalidated = false;
}
}
// retrieve the list of phone/email candidates for syncing
// which is a snapshot of the keys in the cache
getRebuildList(phones, emails);
// now sync
if (phones != null) {
if (LOCAL_DEBUG) log("rebuild cache for phone numbers...");
for (String phone : phones) {
synchronized (mCache) {
CacheEntry entry = queryContactInfoByNumber(mContext, phone);
mCache.put(phone, entry);
}
}
}
if (emails != null) {
if (LOCAL_DEBUG) log("rebuild cache for emails...");
for (String email : emails) {
synchronized (mCache) {
CacheEntry entry = queryEmailDisplayName(mContext, email);
mCache.put(email, entry);
}
}
}
}
|
private void | startCacheRebuilder()Start the background cache rebuilding thread if there is not one yet.
if (mCacheRebuilder == null) {
mCacheRebuilder = new Thread(new Runnable() {
public void run() {
rebuildCache();
}
});
mCacheRebuilder.start();
}
|