summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/phonenumberutil
diff options
context:
space:
mode:
authorlinyuh <linyuh@google.com>2017-10-17 13:31:27 -0700
committerEric Erfanian <erfanian@google.com>2017-10-17 22:45:59 +0000
commit6f78d935ff64f178e9fe8891082c18578d4e4b74 (patch)
tree8bb6b163a88cf321073913c2b0b7dad5ecbd854e /java/com/android/dialer/phonenumberutil
parent68cc4733e1619e1b6b7f6d5f52ab057cc48525bb (diff)
Stop showing partially matched numbers that are not global phone numbers.
When determining whether two phone numbers are identical enough for caller ID purposes, the Contacts Provider ignores special dialable characters such as '#', '*', '+', etc. 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. 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. If the cursor points to a global phone number (i.e., a number that can be accepted by PhoneNumberUtils#isGlobalPhoneNumber(String)) and the lookup number in the URI is a PARTIAL match, the cursor is a match. If the cursor points to a number that is not a global phone number, the cursor is a match iff the lookup number in the URI is an EXACT match. There is no matched cursor in all other circumstances. UI demo: Suppose the user has a contact named "Service1" with number "#123". Before: Incall UI after the user dials "123": https://photos.app.goo.gl/xFWCD4qy2VR3YEuJ2 Call log UI after the call ends: https://photos.app.goo.gl/FT28GdTBy1dtANtI2 After: Incall UI after the user dials "123": https://photos.app.goo.gl/Io3BisQmsyfnvitV2 Call log UI after the call ends: https://photos.app.goo.gl/6GgRrmx75yUTga3B3 Bug: 30225112 Test: PhoneNumberHelperTest PiperOrigin-RevId: 172505648 Change-Id: Ida554313455ff9ce40432897681f89f58d64af04
Diffstat (limited to 'java/com/android/dialer/phonenumberutil')
-rw-r--r--java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java75
1 files changed, 75 insertions, 0 deletions
diff --git a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java
index cc9b73081..84cbb6947 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.Nullable;
@@ -24,6 +26,7 @@ import android.telecom.PhoneAccountHandle;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
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;
@@ -47,6 +50,78 @@ public class PhoneNumberHelper {
}
/**
+ * Find the cursor pointing to a number that matches the number in a contact lookup URI.
+ *
+ * <p>When determining whether two phone numbers are identical enough for caller ID purposes, the
+ * Contacts Provider uses {@link PhoneNumberUtils#compare(String, String)}, which ignores special
+ * dialable characters such as '#', '*', '+', etc. 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>If the cursor points to a global phone number (i.e., a number that can be accepted by {@link
+ * PhoneNumberUtils#isGlobalPhoneNumber(String)}) and the lookup number in the URI is a PARTIAL
+ * match, return the cursor.
+ *
+ * <p>If the cursor points to a number that is not a global phone number, return the cursor iff
+ * the lookup number in the URI is an EXACT match.
+ *
+ * <p>Return null in all other circumstances.
+ *
+ * @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 The cursor considered as a match by the description above or null if no such cursor can
+ * be found.
+ */
+ public static Cursor getCursorMatchForContactLookupUri(
+ Cursor cursor, int columnIndexForNumber, Uri contactLookupUri) {
+ if (cursor == null || contactLookupUri == null) {
+ return null;
+ }
+
+ if (!cursor.moveToFirst()) {
+ return null;
+ }
+
+ Assert.checkArgument(
+ 0 <= columnIndexForNumber && columnIndexForNumber < cursor.getColumnCount());
+
+ String lookupNumber = contactLookupUri.getLastPathSegment();
+ if (lookupNumber == null) {
+ return null;
+ }
+
+ boolean isMatchFound;
+ do {
+ // All undialable characters should be converted/removed before comparing the lookup number
+ // and the existing contact number.
+ String rawExistingContactNumber =
+ PhoneNumberUtils.stripSeparators(
+ PhoneNumberUtils.convertKeypadLettersToDigits(
+ cursor.getString(columnIndexForNumber)));
+ String rawQueryNumber =
+ PhoneNumberUtils.stripSeparators(
+ PhoneNumberUtils.convertKeypadLettersToDigits(lookupNumber));
+
+ isMatchFound =
+ PhoneNumberUtils.isGlobalPhoneNumber(rawExistingContactNumber)
+ ? rawExistingContactNumber.contains(rawQueryNumber)
+ : rawExistingContactNumber.equals(rawQueryNumber);
+
+ if (isMatchFound) {
+ return cursor;
+ }
+ } while (cursor.moveToNext());
+
+ return null;
+ }
+
+ /**
* 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.
*/