Change fallback method for contact matching
Modified the fallback method that is used for contact matching
whenever the original query fails to return a result. We previously
performed a 7 digit match but this resulted in problems such as false
positives when the area code is changed but the last 7 digits of
a number are the same. The new fallback method uses the GB method
of matching via the SQLite function phone_number_compare_loose.
Bug: 7000177
Change-Id: I597b4b9e44ab2c4e4a5381832a3e9dfd0d51cf8f
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index 62f49ae..81112aa 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -4453,20 +4453,35 @@
}
/**
- * As opposed to {@link #buildPhoneLookupAndContactQuery}, this phone lookup will only do
- * a comparison based on the last seven digits of the given phone number. This is only intended
- * to be used as a fallback, in case the regular lookup does not return any results.
+ * Phone lookup method that uses the custom SQLite function phone_number_compare_loose
+ * that serves as a fallback in case the regular lookup does not return any results.
* @param qb The query builder.
* @param number The phone number to search for.
*/
- public void buildMinimalPhoneLookupAndContactQuery(SQLiteQueryBuilder qb, String number) {
- String minMatch = PhoneNumberUtils.toCallerIDMinMatch(number);
- StringBuilder sb = new StringBuilder();
- appendPhoneLookupTables(sb, minMatch, true);
+ public void buildFallbackPhoneLookupAndContactQuery(SQLiteQueryBuilder qb, String number) {
+ final String minMatch = PhoneNumberUtils.toCallerIDMinMatch(number);
+ final StringBuilder sb = new StringBuilder();
+ //append lookup tables
+ sb.append(Tables.RAW_CONTACTS);
+ sb.append(" JOIN " + Views.CONTACTS + " as contacts_view"
+ + " ON (contacts_view._id = " + Tables.RAW_CONTACTS
+ + "." + RawContacts.CONTACT_ID + ")" +
+ " JOIN (SELECT " + PhoneLookupColumns.DATA_ID + "," +
+ PhoneLookupColumns.NORMALIZED_NUMBER + " FROM "+ Tables.PHONE_LOOKUP + " "
+ + "WHERE (" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.MIN_MATCH + " = '");
+ sb.append(minMatch);
+ sb.append("')) AS lookup " +
+ "ON lookup." + PhoneLookupColumns.DATA_ID + "=" + Tables.DATA + "." + Data._ID
+ + " JOIN " + Tables.DATA + " "
+ + "ON " + Tables.DATA + "." + Data.RAW_CONTACT_ID + "=" + Tables.RAW_CONTACTS + "."
+ + RawContacts._ID);
+
qb.setTables(sb.toString());
- sb = new StringBuilder();
- appendPhoneLookupSelection(sb, null, null);
+ sb.setLength(0);
+ sb.append("PHONE_NUMBERS_EQUAL(" + Tables.DATA + "." + Phone.NUMBER + ", ");
+ DatabaseUtils.appendEscapedSQLString(sb, number);
+ sb.append(mUseStrictPhoneNumberComparison ? ", 1)" : ", 0)");
qb.appendWhere(sb.toString());
}
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index ef2ea9a..d236de3 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -5768,10 +5768,13 @@
selectionArgs = mDbHelper.get().buildSipContactQuery(sb, sipAddress);
selection = sb.toString();
} else {
+ // Use this flag to track whether sortOrder was originally empty
+ boolean sortOrderIsEmpty = false;
if (TextUtils.isEmpty(sortOrder)) {
// Default the sort order to something reasonable so we get consistent
// results when callers don't request an ordering
sortOrder = " length(lookup.normalized_number) DESC";
+ sortOrderIsEmpty = true;
}
String number = uri.getPathSegments().size() > 1
@@ -5786,7 +5789,8 @@
// Peek at the results of the first query (which attempts to use fully
// normalized and internationalized numbers for comparison). If no results
- // were returned, fall back to doing a match of the trailing 7 digits.
+ // were returned, fall back to using the SQLite function
+ // phone_number_compare_loose.
qb.setStrict(true);
boolean foundResult = false;
Cursor cursor = query(db, qb, projection, selection, selectionArgs,
@@ -5796,9 +5800,15 @@
foundResult = true;
return cursor;
} else {
+ // Use fallback lookup method
+
qb = new SQLiteQueryBuilder();
- mDbHelper.get().buildMinimalPhoneLookupAndContactQuery(
- qb, normalizedNumber);
+
+ // use the raw number instead of the normalized number because
+ // phone_number_compare_loose in SQLite works only with non-normalized
+ // numbers
+ mDbHelper.get().buildFallbackPhoneLookupAndContactQuery(qb, number);
+
qb.setProjectionMap(sPhoneLookupProjectionMap);
}
} finally {
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index 003012e..8970e5d 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -1282,6 +1282,10 @@
// call id should match to both "8004664411" and "+18004664411".
Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "4664411");
assertEquals(2, getCount(lookupUri2, null, null));
+
+ // A wrong area code 799 vs 800 should not be matched
+ lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "7994664411");
+ assertEquals(0, getCount(lookupUri2, null, null));
}
public void testPhoneLookupUseCases() {
@@ -1310,6 +1314,18 @@
lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0000");
assertEquals(1, getCount(lookupUri2, null, null));
+ // does not match with wrong area code
+ lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "649 861 0000");
+ assertEquals(0, getCount(lookupUri2, null, null));
+
+ // does not match with missing digits in mistyped area code
+ lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "5 861 0000");
+ assertEquals(0, getCount(lookupUri2, null, null));
+
+ // does not match with missing digit in mistyped area code
+ lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "65 861 0000");
+ assertEquals(0, getCount(lookupUri2, null, null));
+
// National format in contacts
values.clear();
values.put(RawContacts.CUSTOM_RINGTONE, "d");
@@ -1352,8 +1368,8 @@
}
public void testIntlPhoneLookupUseCases() {
- // Checks the logic that relies on using the trailing 7-digits as a fallback for phone
- // number lookups.
+ // Checks the logic that relies on phone_number_compare_loose(Gingerbread) as a fallback
+ //for phone number lookups.
String fullNumber = "01197297427289";
ContentValues values = new ContentValues();
@@ -1371,9 +1387,9 @@
assertEquals(2, getCount(Uri.withAppendedPath(
PhoneLookup.CONTENT_FILTER_URI, "097427289"), null, null));
- // Shorter (local) number with +0 prefix should also match.
- assertEquals(2, getCount(Uri.withAppendedPath(
- PhoneLookup.CONTENT_FILTER_URI, "+097427289"), null, null));
+ // Number with international (+972) prefix should also match.
+ assertEquals(1, getCount(Uri.withAppendedPath(
+ PhoneLookup.CONTENT_FILTER_URI, "+97297427289"), null, null));
// Same shorter number with dashes should match.
assertEquals(2, getCount(Uri.withAppendedPath(