Better handling of SIP addresses in the Call log
Fix some SIP-address-related issues in RecentCallsListActivity:
- When doing contacts lookups to "refresh" the list, don't try to use
the PhoneLookup table if the "number" is really a SIP address!
Instead, look it up directly in the Data table. (This basically
does what change https://android-git.corp.google.com/g/70555 did for
incoming calls.)
- With SIP addresses, correctly use a sip: URI when calling by tapping
the list, via the CALL button, or via the longpress context menu.
- Don't try to call PhoneNumberUtils.formatNumber() on SIP addresses
- "type" and "label" are currently unused for SIP addresses; don't
display them
- Disable "Add to contacts" for SIP addresses (for now at least, since
it's currently broken anyway.)
Bug: 3004127
TESTED:
- Visual appearance of both SIP calls and PSTN calls in the call log:
make sure we correctly display the contact name and "number".
- Verify the above for freshly added items, *and* after rebooting and
re-entering the call log.
- Tap the green "call" icon, make sure we call back correctly (for
both PSTN and SIP).
- Tap the entry itself, make sure "view contact" UI looks correct,
make sure the "Call" item works (for both PSTN and SIP).
- Longpress, verify the context menu items:
- "Call" should correctly call for either SIP or PSTN
- "View contact" should work for either SIP or PSTN
- "Edit number before call" should ONLY be shown for PSTN
- "Send text message" should ONLY be shown for PSTN
- "Remove from call log" should work for either SIP or PSTN
Change-Id: I8ab04250b00d23a88f32a56e7d9953d91c24807c
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java
index fe6d44c..8e7b4bc 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/RecentCallsListActivity.java
@@ -47,10 +47,12 @@
import android.os.SystemClock;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
-import android.provider.ContactsContract.Intents.Insert;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents.Insert;
+import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.text.SpannableStringBuilder;
@@ -208,8 +210,16 @@
public void onClick(View view) {
String number = (String) view.getTag();
if (!TextUtils.isEmpty(number)) {
- Uri telUri = Uri.fromParts("tel", number, null);
- startActivity(new Intent(Intent.ACTION_CALL_PRIVILEGED, telUri));
+ // Here, "number" can either be a PSTN phone number or a
+ // SIP address. So turn it into either a tel: URI or a
+ // sip: URI, as appropriate.
+ Uri callUri;
+ if (PhoneNumberUtils.isUriNumber(number)) {
+ callUri = Uri.fromParts("sip", number, null);
+ } else {
+ callUri = Uri.fromParts("tel", number, null);
+ }
+ startActivity(new Intent(Intent.ACTION_CALL_PRIVILEGED, callUri));
}
}
@@ -342,29 +352,103 @@
if (info != null && info != ContactInfo.EMPTY) {
return true;
} else {
- Cursor phonesCursor =
- RecentCallsListActivity.this.getContentResolver().query(
- Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
- Uri.encode(ciq.number)),
- PHONES_PROJECTION, null, null, null);
- if (phonesCursor != null) {
- if (phonesCursor.moveToFirst()) {
- info = new ContactInfo();
- info.personId = phonesCursor.getLong(PERSON_ID_COLUMN_INDEX);
- info.name = phonesCursor.getString(NAME_COLUMN_INDEX);
- info.type = phonesCursor.getInt(PHONE_TYPE_COLUMN_INDEX);
- info.label = phonesCursor.getString(LABEL_COLUMN_INDEX);
- info.number = phonesCursor.getString(MATCHED_NUMBER_COLUMN_INDEX);
+ // Ok, do a fresh Contacts lookup for ciq.number.
+ boolean infoUpdated = false;
- // New incoming phone number invalidates our formatted
- // cache. Any cache fills happen only on the GUI thread.
- info.formattedNumber = null;
+ if (PhoneNumberUtils.isUriNumber(ciq.number)) {
+ // This "number" is really a SIP address.
- mContactInfo.put(ciq.number, info);
- // Inform list to update this item, if in view
- needNotify = true;
+ // 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[] { ciq.number.toUpperCase() };
+
+ Cursor dataTableCursor =
+ RecentCallsListActivity.this.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.
+ info.personId = dataTableCursor.getLong(
+ dataTableCursor.getColumnIndex(Data.CONTACT_ID));
+ 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));
+
+ infoUpdated = true;
+ }
+ dataTableCursor.close();
}
- phonesCursor.close();
+ } else {
+ // "number" is a regular phone number, so use the
+ // PhoneLookup table:
+ Cursor phonesCursor =
+ RecentCallsListActivity.this.getContentResolver().query(
+ Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(ciq.number)),
+ PHONES_PROJECTION, null, null, null);
+ if (phonesCursor != null) {
+ if (phonesCursor.moveToFirst()) {
+ info = new ContactInfo();
+ info.personId = phonesCursor.getLong(PERSON_ID_COLUMN_INDEX);
+ info.name = phonesCursor.getString(NAME_COLUMN_INDEX);
+ info.type = phonesCursor.getInt(PHONE_TYPE_COLUMN_INDEX);
+ info.label = phonesCursor.getString(LABEL_COLUMN_INDEX);
+ info.number = phonesCursor.getString(MATCHED_NUMBER_COLUMN_INDEX);
+
+ infoUpdated = true;
+ }
+ phonesCursor.close();
+ }
+ }
+
+ if (infoUpdated) {
+ // New incoming phone number invalidates our formatted
+ // cache. Any cache fills happen only on the GUI thread.
+ info.formattedNumber = null;
+
+ mContactInfo.put(ciq.number, info);
+
+ // Inform list to update this item, if in view
+ needNotify = true;
}
}
if (info != null) {
@@ -590,8 +674,13 @@
if (!TextUtils.isEmpty(name)) {
views.line1View.setText(name);
views.labelView.setVisibility(View.VISIBLE);
- CharSequence numberLabel = Phone.getDisplayLabel(context, ntype, label,
- mLabelArray);
+
+ // "type" and "label" are currently unused for SIP addresses.
+ CharSequence numberLabel = null;
+ if (!PhoneNumberUtils.isUriNumber(number)) {
+ numberLabel = Phone.getDisplayLabel(context, ntype, label,
+ mLabelArray);
+ }
views.numberView.setVisibility(View.VISIBLE);
views.numberView.setText(formattedNumber);
if (!TextUtils.isEmpty(numberLabel)) {
@@ -799,6 +888,11 @@
return "";
}
+ // If "number" is really a SIP address, don't try to do any formatting at all.
+ if (PhoneNumberUtils.isUriNumber(number)) {
+ return number;
+ }
+
// Cache formatting type if not already present
if (sFormattingType == FORMATTING_TYPE_INVALID) {
sFormattingType = PhoneNumberUtils.getFormatTypeForLocale(Locale.getDefault());
@@ -866,7 +960,7 @@
numberUri = Uri.parse("voicemail:x");
isVoicemail = true;
} else if (PhoneNumberUtils.isUriNumber(number)) {
- numberUri = Uri.fromParts("tel", number, null);
+ numberUri = Uri.fromParts("sip", number, null);
isSipNumber = true;
} else {
numberUri = Uri.fromParts("tel", number, null);
@@ -899,7 +993,19 @@
.setIntent(new Intent(Intent.ACTION_SENDTO,
Uri.fromParts("sms", number, null)));
}
- if (!contactInfoPresent && numberUri != null && !isVoicemail) {
+
+ // "Add to contacts" item, if this entry isn't already associated with a contact
+ if (!contactInfoPresent && numberUri != null && !isVoicemail && !isSipNumber) {
+ // TODO: This item is currently disabled for SIP addresses, because
+ // the Insert.PHONE extra only works correctly for PSTN numbers.
+ //
+ // To fix this for SIP addresses, we need to:
+ // - define ContactsContract.Intents.Insert.SIP_ADDRESS, and use it here if
+ // the current number is a SIP address
+ // - update the contacts UI code to handle Insert.SIP_ADDRESS by
+ // updating the SipAddress field
+ // and then we can remove the "!isSipNumber" check above.
+
Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
intent.setType(Contacts.CONTENT_ITEM_TYPE);
intent.putExtra(Insert.PHONE, number);
@@ -1085,16 +1191,24 @@
// This number can't be called, do nothing
return;
}
-
- int callType = cursor.getInt(CALL_TYPE_COLUMN_INDEX);
- if (!number.startsWith("+") &&
- (callType == Calls.INCOMING_TYPE
- || callType == Calls.MISSED_TYPE)) {
- // If the caller-id matches a contact with a better qualified number, use it
- number = getBetterNumberFromContacts(number);
+ Intent intent;
+ // If "number" is really a SIP address, construct a sip: URI.
+ if (PhoneNumberUtils.isUriNumber(number)) {
+ intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
+ Uri.fromParts("sip", number, null));
+ } else {
+ // We're calling a regular PSTN phone number.
+ // Construct a tel: URI, but do some other possible cleanup first.
+ int callType = cursor.getInt(CALL_TYPE_COLUMN_INDEX);
+ if (!number.startsWith("+") &&
+ (callType == Calls.INCOMING_TYPE
+ || callType == Calls.MISSED_TYPE)) {
+ // If the caller-id matches a contact with a better qualified number, use it
+ number = getBetterNumberFromContacts(number);
+ }
+ intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
+ Uri.fromParts("tel", number, null));
}
- Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
- Uri.fromParts("tel", number, null));
intent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);