Share contact look up between call log and call details.
Currently, it is possible to get a contact be correctly identified in
the call log, but not in the details, because the logic to do the
look-up are completely separate.
For example, SIP contacts are correctly looked up by the call log, but
not by the details. Moreover, we recently fixed a few bugs in the logic
for looking up contacts in the call log, that have not been propagated
to the call details because the code is independent.
This commit moves the whole logic of looking up a contact given a number
(which may be a SIP number) from the CallLogAdapter into its own class.
Then, CallDetailActivity can use that to look up the contact in a way
that is guaranteed to yield the same result.
Bug: 5415134
Change-Id: I73acc39ba5dc65ecce6861f210224304fd91822d
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index 113a18b..012acc7 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -19,6 +19,8 @@
import com.android.contacts.BackScrollManager.ScrollableHeader;
import com.android.contacts.calllog.CallDetailHistoryAdapter;
import com.android.contacts.calllog.CallTypeHelper;
+import com.android.contacts.calllog.ContactInfo;
+import com.android.contacts.calllog.ContactInfoHelper;
import com.android.contacts.calllog.PhoneNumberHelper;
import com.android.contacts.util.AsyncTaskExecutor;
import com.android.contacts.util.AsyncTaskExecutors;
@@ -44,7 +46,6 @@
import android.provider.Contacts.Intents.Insert;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.PhoneLookup;
import android.provider.VoicemailContract.Voicemails;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
@@ -101,6 +102,7 @@
private ImageButton mMainActionPushLayerView;
private ImageView mContactBackgroundView;
private AsyncTaskExecutor mAsyncTaskExecutor;
+ private ContactInfoHelper mContactInfoHelper;
private String mNumber = null;
private String mDefaultCountryIso;
@@ -191,25 +193,6 @@
static final int COUNTRY_ISO_COLUMN_INDEX = 4;
static final int GEOCODED_LOCATION_COLUMN_INDEX = 5;
- static final String[] PHONES_PROJECTION = new String[] {
- PhoneLookup._ID,
- PhoneLookup.DISPLAY_NAME,
- PhoneLookup.TYPE,
- PhoneLookup.LABEL,
- PhoneLookup.NUMBER,
- PhoneLookup.NORMALIZED_NUMBER,
- PhoneLookup.PHOTO_URI,
- PhoneLookup.LOOKUP_KEY,
- };
- static final int COLUMN_INDEX_ID = 0;
- static final int COLUMN_INDEX_NAME = 1;
- static final int COLUMN_INDEX_TYPE = 2;
- static final int COLUMN_INDEX_LABEL = 3;
- static final int COLUMN_INDEX_NUMBER = 4;
- static final int COLUMN_INDEX_NORMALIZED_NUMBER = 5;
- static final int COLUMN_INDEX_PHOTO_URI = 6;
- static final int COLUMN_INDEX_LOOKUP_KEY = 7;
-
private final View.OnClickListener mPrimaryActionListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
@@ -251,6 +234,7 @@
mDefaultCountryIso = ContactsUtils.getCurrentCountryIso(this);
mContactPhotoManager = ContactPhotoManager.getInstance(this);
mProximitySensorManager = new ProximitySensorManager(this, mProximitySensorListener);
+ mContactInfoHelper = new ContactInfoHelper(this, ContactsUtils.getCurrentCountryIso(this));
configureActionBar();
optionallyHandleVoicemail();
}
@@ -570,53 +554,36 @@
}
// Formatted phone number.
- final CharSequence numberText;
+ final CharSequence formattedNumber;
// Read contact specifics.
- CharSequence nameText = "";
- int numberType = 0;
- CharSequence numberLabel = "";
- Uri photoUri = null;
- Uri contactUri = null;
+ final CharSequence nameText;
+ final int numberType;
+ final CharSequence numberLabel;
+ final Uri photoUri;
+ final Uri lookupUri;
// If this is not a regular number, there is no point in looking it up in the contacts.
- if (!mPhoneNumberHelper.canPlaceCallsTo(number)) {
- numberText = mPhoneNumberHelper.getDisplayNumber(number, null);
+ ContactInfo info =
+ mPhoneNumberHelper.canPlaceCallsTo(number)
+ ? mContactInfoHelper.lookupNumber(number, countryIso)
+ : null;
+ if (info == null) {
+ formattedNumber = mPhoneNumberHelper.getDisplayNumber(number, null);
+ nameText = "";
+ numberType = 0;
+ numberLabel = "";
+ photoUri = null;
+ lookupUri = null;
} else {
- // Perform a reverse-phonebook lookup to find the contact details.
- Uri phoneUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
- Uri.encode(number));
- Cursor phonesCursor = resolver.query(phoneUri, PHONES_PROJECTION, null, null, null);
- String candidateNumberText = number;
- try {
- if (phonesCursor != null && phonesCursor.moveToFirst()) {
- nameText = phonesCursor.getString(COLUMN_INDEX_NAME);
- String photoUriString = phonesCursor.getString(COLUMN_INDEX_PHOTO_URI);
- photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
- candidateNumberText = PhoneNumberUtils.formatNumber(
- phonesCursor.getString(COLUMN_INDEX_NUMBER),
- phonesCursor.getString(COLUMN_INDEX_NORMALIZED_NUMBER),
- countryIso);
- numberType = phonesCursor.getInt(COLUMN_INDEX_TYPE);
- numberLabel = phonesCursor.getString(COLUMN_INDEX_LABEL);
- long personId = phonesCursor.getLong(COLUMN_INDEX_ID);
- if (personId > 0) {
- contactUri = Contacts.getLookupUri(personId,
- phonesCursor.getString(COLUMN_INDEX_LOOKUP_KEY));
- }
- } else {
- // We could not find this contact in the contacts, just format the phone
- // number as best as we can. All the other fields will have their default
- // values.
- candidateNumberText =
- PhoneNumberUtils.formatNumber(number, countryIso);
- }
- } finally {
- if (phonesCursor != null) phonesCursor.close();
- numberText = candidateNumberText;
- }
+ formattedNumber = info.formattedNumber;
+ nameText = info.name;
+ numberType = info.type;
+ numberLabel = info.label;
+ photoUri = info.photoUri;
+ lookupUri = info.lookupUri;
}
- return new PhoneCallDetails(number, numberText, countryIso, geocode,
+ return new PhoneCallDetails(number, formattedNumber, countryIso, geocode,
new int[]{ callType }, date, duration,
- nameText, numberType, numberLabel, contactUri, photoUri);
+ nameText, numberType, numberLabel, lookupUri, photoUri);
} finally {
if (callCursor != null) {
callCursor.close();
diff --git a/src/com/android/contacts/calllog/CallLogAdapter.java b/src/com/android/contacts/calllog/CallLogAdapter.java
index 17209b4..4f274a9 100644
--- a/src/com/android/contacts/calllog/CallLogAdapter.java
+++ b/src/com/android/contacts/calllog/CallLogAdapter.java
@@ -33,11 +33,7 @@
import android.os.Handler;
import android.os.Message;
import android.provider.CallLog.Calls;
-import android.provider.ContactsContract.CommonDataKinds.SipAddress;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.PhoneLookup;
-import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -65,7 +61,7 @@
private static final int CONTACT_INFO_CACHE_SIZE = 100;
private final Context mContext;
- private final String mCurrentCountryIso;
+ private final ContactInfoHelper mContactInfoHelper;
private final CallFetcher mCallFetcher;
/**
@@ -198,12 +194,12 @@
};
public CallLogAdapter(Context context, CallFetcher callFetcher,
- String currentCountryIso, String voicemailNumber) {
+ ContactInfoHelper contactInfoHelper, String voicemailNumber) {
super(context);
mContext = context;
- mCurrentCountryIso = currentCountryIso;
mCallFetcher = callFetcher;
+ mContactInfoHelper = contactInfoHelper;
mContactInfoCache = ExpirableCache.create(CONTACT_INFO_CACHE_SIZE);
mRequests = new LinkedList<ContactInfoRequest>();
@@ -305,134 +301,6 @@
}
/**
- * Determines the contact information for the given SIP address.
- * <p>
- * It returns the contact info if found.
- * <p>
- * If no contact corresponds to the given SIP address, returns {@link ContactInfo#EMPTY}.
- * <p>
- * If the lookup fails for some other reason, it returns null.
- */
- private ContactInfo queryContactInfoForSipAddress(String sipAddress) {
- final ContactInfo info;
-
- // TODO: This code is duplicated from the
- // CallerInfoAsyncQuery class. To avoid that, could the
- // code here just use CallerInfoAsyncQuery, rather than
- // manually running ContentResolver.query() itself?
-
- // We look up SIP addresses directly in the Data table:
- Uri contactRef = Data.CONTENT_URI;
-
- // Note Data.DATA1 and SipAddress.SIP_ADDRESS are equivalent.
- //
- // Also note we use "upper(data1)" in the WHERE clause, and
- // uppercase the incoming SIP address, in order to do a
- // case-insensitive match.
- //
- // TODO: May also need to normalize by adding "sip:" as a
- // prefix, if we start storing SIP addresses that way in the
- // database.
- String selection = "upper(" + Data.DATA1 + ")=?"
- + " AND "
- + Data.MIMETYPE + "='" + SipAddress.CONTENT_ITEM_TYPE + "'";
- String[] selectionArgs = new String[] { sipAddress.toUpperCase() };
-
- Cursor dataTableCursor =
- mContext.getContentResolver().query(
- contactRef,
- null, // projection
- selection, // selection
- selectionArgs, // selectionArgs
- null); // sortOrder
-
- if (dataTableCursor != null) {
- if (dataTableCursor.moveToFirst()) {
- info = new ContactInfo();
-
- // TODO: we could slightly speed this up using an
- // explicit projection (and thus not have to do
- // those getColumnIndex() calls) but the benefit is
- // very minimal.
-
- // Note the Data.CONTACT_ID column here is
- // equivalent to the PERSON_ID_COLUMN_INDEX column
- // we use with "phonesCursor" below.
- long contactId = dataTableCursor.getLong(
- dataTableCursor.getColumnIndex(Data.CONTACT_ID));
- String lookupKey = dataTableCursor.getString(
- dataTableCursor.getColumnIndex(Data.LOOKUP_KEY));
- info.lookupUri = Contacts.getLookupUri(contactId, lookupKey);
- info.name = dataTableCursor.getString(
- dataTableCursor.getColumnIndex(Data.DISPLAY_NAME));
- // "type" and "label" are currently unused for SIP addresses
- info.type = SipAddress.TYPE_OTHER;
- info.label = null;
-
- // And "number" is the SIP address.
- // Note Data.DATA1 and SipAddress.SIP_ADDRESS are equivalent.
- info.number = dataTableCursor.getString(dataTableCursor.getColumnIndex(Data.DATA1));
- info.normalizedNumber = null; // meaningless for SIP addresses
- info.photoId = dataTableCursor.getLong(
- dataTableCursor.getColumnIndex(Data.PHOTO_ID));
- info.formattedNumber = null; // meaningless for SIP addresses
- } else {
- info = ContactInfo.EMPTY;
- }
- dataTableCursor.close();
- } else {
- // Failed to fetch the data, ignore this request.
- info = null;
- }
- return info;
- }
-
- /**
- * Determines the contact information for the given phone number.
- * <p>
- * It returns the contact info if found.
- * <p>
- * If no contact corresponds to the given phone number, returns {@link ContactInfo#EMPTY}.
- * <p>
- * If the lookup fails for some other reason, it returns null.
- */
- private ContactInfo queryContactInfoForPhoneNumber(String number, String countryIso) {
- final ContactInfo info;
-
- // "number" is a regular phone number, so use the
- // PhoneLookup table:
- Cursor phonesCursor =
- mContext.getContentResolver().query(
- Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
- Uri.encode(number)),
- PhoneQuery._PROJECTION, null, null, null);
- if (phonesCursor != null) {
- if (phonesCursor.moveToFirst()) {
- info = new ContactInfo();
- long contactId = phonesCursor.getLong(PhoneQuery.PERSON_ID);
- String lookupKey = phonesCursor.getString(PhoneQuery.LOOKUP_KEY);
- info.lookupUri = Contacts.getLookupUri(contactId, lookupKey);
- info.name = phonesCursor.getString(PhoneQuery.NAME);
- info.type = phonesCursor.getInt(PhoneQuery.PHONE_TYPE);
- info.label = phonesCursor.getString(PhoneQuery.LABEL);
- info.number = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER);
- info.normalizedNumber = phonesCursor.getString(PhoneQuery.NORMALIZED_NUMBER);
- info.photoId = phonesCursor.getLong(PhoneQuery.PHOTO_ID);
- info.formattedNumber = formatPhoneNumber(info.number, info.formattedNumber,
- countryIso);
-
- } else {
- info = ContactInfo.EMPTY;
- }
- phonesCursor.close();
- } else {
- // Failed to fetch the data, ignore this request.
- info = null;
- }
- return info;
- }
-
- /**
* Queries the appropriate content provider for the contact associated with the number.
* <p>
* Upon completion it also updates the cache in the call log, if it is different from
@@ -444,53 +312,25 @@
* view to update its content.
*/
private boolean queryContactInfo(String number, String countryIso, ContactInfo callLogInfo) {
- final ContactInfo info;
-
- // Determine the contact info.
- if (PhoneNumberUtils.isUriNumber(number)) {
- // This "number" is really a SIP address.
- ContactInfo sipInfo = queryContactInfoForSipAddress(number);
- if (sipInfo == null || sipInfo == ContactInfo.EMPTY) {
- // Check whether the username is actually a phone number of contact.
- String username = number.substring(0, number.indexOf('@'));
- if (PhoneNumberUtils.isGlobalPhoneNumber(username)) {
- sipInfo = queryContactInfoForPhoneNumber(username, countryIso);
- }
- }
- info = sipInfo;
- } else {
- info = queryContactInfoForPhoneNumber(number, countryIso);
- }
+ final ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso);
if (info == null) {
// The lookup failed, just return without requesting to update the view.
return false;
}
- final ContactInfo updatedInfo;
- // If we did not find a matching contact, generate an empty contact info for the number.
- if (info == ContactInfo.EMPTY) {
- // Did not find a matching contact.
- updatedInfo = new ContactInfo();
- updatedInfo.number = number;
- updatedInfo.formattedNumber = formatPhoneNumber(number, null, countryIso);
- } else {
- updatedInfo = info;
- }
-
// Check the existing entry in the cache: only if it has changed we should update the
// view.
ContactInfo existingInfo = mContactInfoCache.getPossiblyExpired(number);
- boolean updated = !updatedInfo.equals(existingInfo);
+ boolean updated = !info.equals(existingInfo);
// Store the data in the cache so that the UI thread can use to display it. Store it
// even if it has not changed so that it is marked as not expired.
- mContactInfoCache.put(number, updatedInfo);
+ mContactInfoCache.put(number, info);
// Update the call log even if the cache it is up-to-date: it is possible that the cache
// contains the value from a different call log entry.
- updateCallLogContactInfoCache(number, updatedInfo, callLogInfo);
+ updateCallLogContactInfoCache(number, info, callLogInfo);
return updated;
}
-
/*
* Handles requests for contact name and number type
* @see java.lang.Runnable#run()
@@ -804,6 +644,7 @@
info.number = matchedNumber == null ? c.getString(CallLogQuery.NUMBER) : matchedNumber;
info.normalizedNumber = c.getString(CallLogQuery.CACHED_NORMALIZED_NUMBER);
info.photoId = c.getLong(CallLogQuery.CACHED_PHOTO_ID);
+ info.photoUri = null; // We do not cache the photo URI.
info.formattedNumber = c.getString(CallLogQuery.CACHED_FORMATTED_NUMBER);
return info;
}
@@ -850,32 +691,6 @@
super.addGroup(cursorPosition, size, expanded);
}
- /**
- * Format the given phone number
- *
- * @param number the number to be formatted.
- * @param normalizedNumber the normalized number of the given number.
- * @param countryIso the ISO 3166-1 two letters country code, the country's
- * convention will be used to format the number if the normalized
- * phone is null.
- *
- * @return the formatted number, or the given number if it was formatted.
- */
- private String formatPhoneNumber(String number, String normalizedNumber,
- String countryIso) {
- if (TextUtils.isEmpty(number)) {
- return "";
- }
- // If "number" is really a SIP address, don't try to do any formatting at all.
- if (PhoneNumberUtils.isUriNumber(number)) {
- return number;
- }
- if (TextUtils.isEmpty(countryIso)) {
- countryIso = mCurrentCountryIso;
- }
- return PhoneNumberUtils.formatNumber(number, normalizedNumber, countryIso);
- }
-
/*
* Get the number from the Contacts, if available, since sometimes
* the number provided by caller id may not be formatted properly
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index c9a4b5b..f66bbd0 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -152,7 +152,8 @@
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
String currentCountryIso = ContactsUtils.getCurrentCountryIso(getActivity());
- mAdapter = new CallLogAdapter(getActivity(), this, currentCountryIso, mVoiceMailNumber);
+ mAdapter = new CallLogAdapter(getActivity(), this,
+ new ContactInfoHelper(getActivity(), currentCountryIso), mVoiceMailNumber);
setListAdapter(mAdapter);
getListView().setItemsCanFocus(true);
}
diff --git a/src/com/android/contacts/calllog/ContactInfo.java b/src/com/android/contacts/calllog/ContactInfo.java
index cf33d45..a02b457 100644
--- a/src/com/android/contacts/calllog/ContactInfo.java
+++ b/src/com/android/contacts/calllog/ContactInfo.java
@@ -34,6 +34,8 @@
public String normalizedNumber;
/** The photo for the contact, if available. */
public long photoId;
+ /** The high-res photo for the contact, if available. */
+ public Uri photoUri;
public static ContactInfo EMPTY = new ContactInfo();
@@ -63,6 +65,7 @@
if (!TextUtils.equals(formattedNumber, other.formattedNumber)) return false;
if (!TextUtils.equals(normalizedNumber, other.normalizedNumber)) return false;
if (photoId != other.photoId) return false;
+ if (!UriUtils.areEqual(photoUri, other.photoUri)) return false;
return true;
}
}
diff --git a/src/com/android/contacts/calllog/ContactInfoHelper.java b/src/com/android/contacts/calllog/ContactInfoHelper.java
new file mode 100644
index 0000000..f4b7daf
--- /dev/null
+++ b/src/com/android/contacts/calllog/ContactInfoHelper.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.calllog;
+
+import com.android.contacts.util.UriUtils;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.PhoneLookup;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+
+/**
+ * Utility class to look up the contact information for a given number.
+ */
+public class ContactInfoHelper {
+ private final Context mContext;
+ private final String mCurrentCountryIso;
+
+ public ContactInfoHelper(Context context, String currentCountryIso) {
+ mContext = context;
+ mCurrentCountryIso = currentCountryIso;
+ }
+
+ /**
+ * Returns the contact information for the given number.
+ * <p>
+ * If the number does not match any contact, returns a contact info containing only the number
+ * and the formatted number.
+ * <p>
+ * If an error occurs during the lookup, it returns null.
+ *
+ * @param number the number to look up
+ * @param countryIso the country associated with this number
+ */
+ public ContactInfo lookupNumber(String number, String countryIso) {
+ final ContactInfo info;
+
+ // Determine the contact info.
+ if (PhoneNumberUtils.isUriNumber(number)) {
+ // This "number" is really a SIP address.
+ ContactInfo sipInfo = queryContactInfoForSipAddress(number);
+ if (sipInfo == null || sipInfo == ContactInfo.EMPTY) {
+ // Check whether the username is actually a phone number of contact.
+ String username = number.substring(0, number.indexOf('@'));
+ if (PhoneNumberUtils.isGlobalPhoneNumber(username)) {
+ sipInfo = queryContactInfoForPhoneNumber(username, countryIso);
+ }
+ }
+ info = sipInfo;
+ } else {
+ info = queryContactInfoForPhoneNumber(number, countryIso);
+ }
+
+ final ContactInfo updatedInfo;
+ if (info == null) {
+ // The lookup failed.
+ updatedInfo = null;
+ } else {
+ // If we did not find a matching contact, generate an empty contact info for the number.
+ if (info == ContactInfo.EMPTY) {
+ // Did not find a matching contact.
+ updatedInfo = new ContactInfo();
+ updatedInfo.number = number;
+ updatedInfo.formattedNumber = formatPhoneNumber(number, null, countryIso);
+ } else {
+ updatedInfo = info;
+ }
+ }
+ return updatedInfo;
+ }
+
+ /**
+ * Determines the contact information for the given SIP address.
+ * <p>
+ * It returns the contact info if found.
+ * <p>
+ * If no contact corresponds to the given SIP address, returns {@link ContactInfo#EMPTY}.
+ * <p>
+ * If the lookup fails for some other reason, it returns null.
+ */
+ private ContactInfo queryContactInfoForSipAddress(String sipAddress) {
+ final ContactInfo info;
+
+ // TODO: This code is duplicated from the
+ // CallerInfoAsyncQuery class. To avoid that, could the
+ // code here just use CallerInfoAsyncQuery, rather than
+ // manually running ContentResolver.query() itself?
+
+ // We look up SIP addresses directly in the Data table:
+ Uri contactRef = Data.CONTENT_URI;
+
+ // Note Data.DATA1 and SipAddress.SIP_ADDRESS are equivalent.
+ //
+ // Also note we use "upper(data1)" in the WHERE clause, and
+ // uppercase the incoming SIP address, in order to do a
+ // case-insensitive match.
+ //
+ // TODO: May also need to normalize by adding "sip:" as a
+ // prefix, if we start storing SIP addresses that way in the
+ // database.
+ String selection = "upper(" + Data.DATA1 + ")=?"
+ + " AND "
+ + Data.MIMETYPE + "='" + SipAddress.CONTENT_ITEM_TYPE + "'";
+ String[] selectionArgs = new String[] { sipAddress.toUpperCase() };
+
+ Cursor dataTableCursor =
+ mContext.getContentResolver().query(
+ contactRef,
+ null, // projection
+ selection, // selection
+ selectionArgs, // selectionArgs
+ null); // sortOrder
+
+ if (dataTableCursor != null) {
+ if (dataTableCursor.moveToFirst()) {
+ info = new ContactInfo();
+
+ // TODO: we could slightly speed this up using an
+ // explicit projection (and thus not have to do
+ // those getColumnIndex() calls) but the benefit is
+ // very minimal.
+
+ // Note the Data.CONTACT_ID column here is
+ // equivalent to the PERSON_ID_COLUMN_INDEX column
+ // we use with "phonesCursor" below.
+ long contactId = dataTableCursor.getLong(
+ dataTableCursor.getColumnIndex(Data.CONTACT_ID));
+ String lookupKey = dataTableCursor.getString(
+ dataTableCursor.getColumnIndex(Data.LOOKUP_KEY));
+ info.lookupUri = Contacts.getLookupUri(contactId, lookupKey);
+ info.name = dataTableCursor.getString(
+ dataTableCursor.getColumnIndex(Data.DISPLAY_NAME));
+ // "type" and "label" are currently unused for SIP addresses
+ info.type = SipAddress.TYPE_OTHER;
+ info.label = null;
+
+ // And "number" is the SIP address.
+ // Note Data.DATA1 and SipAddress.SIP_ADDRESS are equivalent.
+ info.number = dataTableCursor.getString(dataTableCursor.getColumnIndex(Data.DATA1));
+ info.normalizedNumber = null; // meaningless for SIP addresses
+ info.photoId = dataTableCursor.getLong(
+ dataTableCursor.getColumnIndex(Data.PHOTO_ID));
+ info.photoUri = UriUtils.parseUriOrNull(dataTableCursor.getString(
+ dataTableCursor.getColumnIndex(Data.PHOTO_URI)));
+ info.formattedNumber = null; // meaningless for SIP addresses
+ } else {
+ info = ContactInfo.EMPTY;
+ }
+ dataTableCursor.close();
+ } else {
+ // Failed to fetch the data, ignore this request.
+ info = null;
+ }
+ return info;
+ }
+
+ /**
+ * Determines the contact information for the given phone number.
+ * <p>
+ * It returns the contact info if found.
+ * <p>
+ * If no contact corresponds to the given phone number, returns {@link ContactInfo#EMPTY}.
+ * <p>
+ * If the lookup fails for some other reason, it returns null.
+ */
+ private ContactInfo queryContactInfoForPhoneNumber(String number, String countryIso) {
+ final ContactInfo info;
+
+ // "number" is a regular phone number, so use the
+ // PhoneLookup table:
+ Cursor phonesCursor =
+ mContext.getContentResolver().query(
+ Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(number)),
+ PhoneQuery._PROJECTION, null, null, null);
+ if (phonesCursor != null) {
+ if (phonesCursor.moveToFirst()) {
+ info = new ContactInfo();
+ long contactId = phonesCursor.getLong(PhoneQuery.PERSON_ID);
+ String lookupKey = phonesCursor.getString(PhoneQuery.LOOKUP_KEY);
+ info.lookupUri = Contacts.getLookupUri(contactId, lookupKey);
+ info.name = phonesCursor.getString(PhoneQuery.NAME);
+ info.type = phonesCursor.getInt(PhoneQuery.PHONE_TYPE);
+ info.label = phonesCursor.getString(PhoneQuery.LABEL);
+ info.number = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER);
+ info.normalizedNumber = phonesCursor.getString(PhoneQuery.NORMALIZED_NUMBER);
+ info.photoId = phonesCursor.getLong(PhoneQuery.PHOTO_ID);
+ info.photoUri =
+ UriUtils.parseUriOrNull(phonesCursor.getString(PhoneQuery.PHOTO_URI));
+ info.formattedNumber = formatPhoneNumber(info.number, info.formattedNumber,
+ countryIso);
+
+ } else {
+ info = ContactInfo.EMPTY;
+ }
+ phonesCursor.close();
+ } else {
+ // Failed to fetch the data, ignore this request.
+ info = null;
+ }
+ return info;
+ }
+
+ /**
+ * Format the given phone number
+ *
+ * @param number the number to be formatted.
+ * @param normalizedNumber the normalized number of the given number.
+ * @param countryIso the ISO 3166-1 two letters country code, the country's
+ * convention will be used to format the number if the normalized
+ * phone is null.
+ *
+ * @return the formatted number, or the given number if it was formatted.
+ */
+ private String formatPhoneNumber(String number, String normalizedNumber,
+ String countryIso) {
+ if (TextUtils.isEmpty(number)) {
+ return "";
+ }
+ // If "number" is really a SIP address, don't try to do any formatting at all.
+ if (PhoneNumberUtils.isUriNumber(number)) {
+ return number;
+ }
+ if (TextUtils.isEmpty(countryIso)) {
+ countryIso = mCurrentCountryIso;
+ }
+ return PhoneNumberUtils.formatNumber(number, normalizedNumber, countryIso);
+ }
+}
diff --git a/src/com/android/contacts/calllog/PhoneQuery.java b/src/com/android/contacts/calllog/PhoneQuery.java
index a53e5c8..af44add 100644
--- a/src/com/android/contacts/calllog/PhoneQuery.java
+++ b/src/com/android/contacts/calllog/PhoneQuery.java
@@ -30,7 +30,8 @@
PhoneLookup.NUMBER,
PhoneLookup.NORMALIZED_NUMBER,
PhoneLookup.PHOTO_ID,
- PhoneLookup.LOOKUP_KEY};
+ PhoneLookup.LOOKUP_KEY,
+ PhoneLookup.PHOTO_URI};
public static final int PERSON_ID = 0;
public static final int NAME = 1;
@@ -40,4 +41,5 @@
public static final int NORMALIZED_NUMBER = 5;
public static final int PHOTO_ID = 6;
public static final int LOOKUP_KEY = 7;
+ public static final int PHOTO_URI = 8;
}
\ No newline at end of file
diff --git a/tests/src/com/android/contacts/calllog/CallLogAdapterTest.java b/tests/src/com/android/contacts/calllog/CallLogAdapterTest.java
index b159f61..909002a 100644
--- a/tests/src/com/android/contacts/calllog/CallLogAdapterTest.java
+++ b/tests/src/com/android/contacts/calllog/CallLogAdapterTest.java
@@ -53,7 +53,18 @@
public void fetchCalls() {}
};
- mAdapter = new TestCallLogAdapter(getContext(), fakeCallFetcher, TEST_COUNTRY_ISO,
+ ContactInfoHelper fakeContactInfoHelper =
+ new ContactInfoHelper(getContext(), TEST_COUNTRY_ISO) {
+ @Override
+ public ContactInfo lookupNumber(String number, String countryIso) {
+ ContactInfo info = new ContactInfo();
+ info.number = number;
+ info.formattedNumber = number;
+ return info;
+ }
+ };
+
+ mAdapter = new TestCallLogAdapter(getContext(), fakeCallFetcher, fakeContactInfoHelper,
TEST_VOICEMAIL_NUMBER);
// The cursor used in the tests to store the entries to display.
mCursor = new MatrixCursor(CallLogQuery.EXTENDED_PROJECTION);
@@ -202,8 +213,8 @@
public final List<Request> requests = Lists.newArrayList();
public TestCallLogAdapter(Context context, CallFetcher callFetcher,
- String currentCountryIso, String voicemailNumber) {
- super(context, callFetcher, currentCountryIso, voicemailNumber);
+ ContactInfoHelper contactInfoHelper, String voicemailNumber) {
+ super(context, callFetcher, contactInfoHelper, voicemailNumber);
}
@Override