summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlinyuh <linyuh@google.com>2017-12-14 12:34:31 -0800
committerCopybara-Service <copybara-piper@google.com>2017-12-14 13:16:13 -0800
commit2d5167b475d64b4bad0f0cde2508bca55c4b7643 (patch)
treee8ac965f799aa1be24268c241280223b86157ec0
parent35363b349d9542a0dd124307a498a3daa0e73390 (diff)
Take into consideration special characters when we do contact match.
Bug: 30225112 Test: CallLogGroupBuilderTest, PhoneNumberHelperTest, CallerInfoTest, and Manual (see demo) PiperOrigin-RevId: 179080046 Change-Id: I8e451a6c197a6c3df4260e58d0276a5dc5b9515a
-rw-r--r--java/com/android/dialer/app/calllog/CallLogGroupBuilder.java17
-rw-r--r--java/com/android/dialer/phonenumbercache/ContactInfoHelper.java11
-rw-r--r--java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java88
-rw-r--r--java/com/android/incallui/CallerInfo.java22
4 files changed, 130 insertions, 8 deletions
diff --git a/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java b/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java
index 513c8aa59..a48de0f51 100644
--- a/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java
+++ b/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java
@@ -189,13 +189,26 @@ public class CallLogGroupBuilder {
mGroupCreator.addGroup(count - groupSize, groupSize);
}
+ /**
+ * Returns true when the two input numbers can be considered identical enough for caller ID
+ * purposes and put in a call log group.
+ */
@VisibleForTesting
boolean equalNumbers(@Nullable String number1, @Nullable String number2) {
if (PhoneNumberHelper.isUriNumber(number1) || PhoneNumberHelper.isUriNumber(number2)) {
return compareSipAddresses(number1, number2);
- } else {
- return PhoneNumberUtils.compare(number1, number2);
}
+
+ // PhoneNumberUtils.compare(String, String) ignores special characters such as '#'. For example,
+ // it thinks "123" and "#123" are identical enough for caller ID purposes.
+ // When either input number contains special characters, we put the two in the same group iff
+ // their raw numbers are exactly the same.
+ if (PhoneNumberHelper.numberHasSpecialChars(number1)
+ || PhoneNumberHelper.numberHasSpecialChars(number2)) {
+ return PhoneNumberHelper.sameRawNumbers(number1, number2);
+ }
+
+ return PhoneNumberUtils.compare(number1, number2);
}
private boolean isSameAccount(String name1, String name2, String id1, String id2) {
diff --git a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
index 39e3866cf..1fd2bffd9 100644
--- a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
+++ b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
@@ -355,6 +355,17 @@ public class ContactInfoHelper {
return ContactInfo.EMPTY;
}
+ // The Contacts provider ignores special characters in phone numbers when searching for a
+ // contact. For example, number "123" is considered a match with a contact with number "#123".
+ // We need to check whether the result contains a number that truly matches the query and move
+ // the cursor to that position before building a ContactInfo.
+ boolean hasNumberMatch =
+ PhoneNumberHelper.updateCursorToMatchContactLookupUri(
+ phoneLookupCursor, PhoneQuery.MATCHED_NUMBER, uri);
+ if (!hasNumberMatch) {
+ return ContactInfo.EMPTY;
+ }
+
String lookupKey = phoneLookupCursor.getString(PhoneQuery.LOOKUP_KEY);
ContactInfo contactInfo = createPhoneLookupContactInfo(phoneLookupCursor, lookupKey);
fillAdditionalContactInfo(mContext, contactInfo);
diff --git a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java
index be1b0629a..12e146959 100644
--- a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java
+++ b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java
@@ -17,6 +17,8 @@
package com.android.dialer.phonenumberutil;
import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
import android.os.Trace;
import android.provider.CallLog;
import android.support.annotation.NonNull;
@@ -27,6 +29,7 @@ import android.telephony.TelephonyManager;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
+import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.CompatUtils;
import com.android.dialer.compat.telephony.TelephonyManagerCompat;
@@ -50,6 +53,91 @@ public class PhoneNumberHelper {
}
/**
+ * Move the given cursor to a position where the number it points to matches the number in a
+ * contact lookup URI.
+ *
+ * <p>We assume the cursor is one returned by the Contacts Provider when the URI asks for a
+ * specific number. This method's behavior is undefined when the cursor doesn't meet the
+ * assumption.
+ *
+ * <p>When determining whether two phone numbers are identical enough for caller ID purposes, the
+ * Contacts Provider ignores special characters such as '#'. This makes it possible for the cursor
+ * returned by the Contacts Provider to have multiple rows even when the URI asks for a specific
+ * number.
+ *
+ * <p>For example, suppose the user has two contacts whose numbers are "#123" and "123",
+ * respectively. When the URI asks for number "123", both numbers will be returned. Therefore, the
+ * following strategy is employed to find a match.
+ *
+ * <p>In the following description, we use E to denote a number the cursor points to (an existing
+ * contact number), and L to denote the number in the contact lookup URI.
+ *
+ * <p>If neither E nor L contains special characters, return true to indicate a match is found.
+ *
+ * <p>If either E or L contains special characters, return true when the raw numbers of E and L
+ * are the same. Otherwise, move the cursor to its next position and start over.
+ *
+ * <p>Return false in all other circumstances to indicate that no match can be found.
+ *
+ * <p>When no match can be found, the cursor is after the last result when the method returns.
+ *
+ * @param cursor A cursor returned by the Contacts Provider.
+ * @param columnIndexForNumber The index of the column where phone numbers are stored. It is the
+ * caller's responsibility to pass the correct column index.
+ * @param contactLookupUri A URI used to retrieve a contact via the Contacts Provider. It is the
+ * caller's responsibility to ensure the URI is one that asks for a specific phone number.
+ * @return true if a match can be found.
+ */
+ public static boolean updateCursorToMatchContactLookupUri(
+ @Nullable Cursor cursor, int columnIndexForNumber, @Nullable Uri contactLookupUri) {
+ if (cursor == null || contactLookupUri == null) {
+ return false;
+ }
+
+ if (!cursor.moveToFirst()) {
+ return false;
+ }
+
+ Assert.checkArgument(
+ 0 <= columnIndexForNumber && columnIndexForNumber < cursor.getColumnCount());
+
+ String lookupNumber = contactLookupUri.getLastPathSegment();
+ if (TextUtils.isEmpty(lookupNumber)) {
+ return false;
+ }
+
+ boolean lookupNumberHasSpecialChars = numberHasSpecialChars(lookupNumber);
+
+ do {
+ String existingContactNumber = cursor.getString(columnIndexForNumber);
+ boolean existingContactNumberHasSpecialChars = numberHasSpecialChars(existingContactNumber);
+
+ if ((!lookupNumberHasSpecialChars && !existingContactNumberHasSpecialChars)
+ || sameRawNumbers(existingContactNumber, lookupNumber)) {
+ return true;
+ }
+
+ } while (cursor.moveToNext());
+
+ return false;
+ }
+
+ /** Returns true if the input phone number contains special characters. */
+ public static boolean numberHasSpecialChars(String number) {
+ return !TextUtils.isEmpty(number) && number.contains("#");
+ }
+
+ /** Returns true if the raw numbers of the two input phone numbers are the same. */
+ public static boolean sameRawNumbers(String number1, String number2) {
+ String rawNumber1 =
+ PhoneNumberUtils.stripSeparators(PhoneNumberUtils.convertKeypadLettersToDigits(number1));
+ String rawNumber2 =
+ PhoneNumberUtils.stripSeparators(PhoneNumberUtils.convertKeypadLettersToDigits(number2));
+
+ return rawNumber1.equals(rawNumber2);
+ }
+
+ /**
* Returns true if the given number is the number of the configured voicemail. To be able to
* mock-out this, it is not a static method.
*/
diff --git a/java/com/android/incallui/CallerInfo.java b/java/com/android/incallui/CallerInfo.java
index 5c43b4f39..d3b12c158 100644
--- a/java/com/android/incallui/CallerInfo.java
+++ b/java/com/android/incallui/CallerInfo.java
@@ -223,16 +223,26 @@ public class CallerInfo {
long contactId = 0L;
int columnIndex;
- // Look for the name
- columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
+ // Look for the number
+ columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
if (columnIndex != -1) {
- info.name = normalize(cursor.getString(columnIndex));
+ // The Contacts provider ignores special characters in phone numbers when searching for a
+ // contact. For example, number "123" is considered a match with a contact with number "#123".
+ // We need to check whether the result contains a number that truly matches the query and move
+ // the cursor to that position before filling in the fields in CallerInfo.
+ boolean hasNumberMatch =
+ PhoneNumberHelper.updateCursorToMatchContactLookupUri(cursor, columnIndex, contactRef);
+ if (hasNumberMatch) {
+ info.phoneNumber = cursor.getString(columnIndex);
+ } else {
+ return info;
+ }
}
- // Look for the number
- columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
+ // Look for the name
+ columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
if (columnIndex != -1) {
- info.phoneNumber = cursor.getString(columnIndex);
+ info.name = normalize(cursor.getString(columnIndex));
}
// Look for the normalized number