More aggressive fix for phone lookup issues.

    Rather than relying on a trailing suffix match on the longer of the
    two numbers (the one from caller ID and the one in the database),
    this first attempts to do the full internationalized-number-aware
    query that we'd normally do, and if no results are returned, falls
    back to a comparison of the trailing 7 digits of each number, as
    we did in Gingerbread.

    Also ports in Makoto's fix to the phone lookup tests.

    Bug: 5742389

Change-Id: Idda8474337bedaced59916c2b0af87b62b737d83
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index 8940c61..f5f1a6a 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -4146,6 +4146,24 @@
     }
 
     /**
+     * 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.
+     * @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);
+        qb.setTables(sb.toString());
+
+        sb = new StringBuilder();
+        appendPhoneLookupSelection(sb, null, null);
+        qb.appendWhere(sb.toString());
+    }
+
+    /**
      * Adds query for selecting the contact with the given {@code sipAddress} to the given
      * {@link StringBuilder}.
      *
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 120c0de..59b2170 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -5770,6 +5770,30 @@
                     mDbHelper.get().buildPhoneLookupAndContactQuery(
                             qb, normalizedNumber, numberE164);
                     qb.setProjectionMap(sPhoneLookupProjectionMap);
+
+                    // 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.
+                    qb.setStrict(true);
+                    boolean foundResult = false;
+                    Cursor cursor = query(mActiveDb.get(), qb, projection, selection, selectionArgs,
+                            sortOrder, groupBy, limit);
+                    try {
+                        if (cursor.getCount() > 0) {
+                            foundResult = true;
+                            return cursor;
+                        } else {
+                            qb = new SQLiteQueryBuilder();
+                            mDbHelper.get().buildMinimalPhoneLookupAndContactQuery(
+                                    qb, normalizedNumber);
+                            qb.setProjectionMap(sPhoneLookupProjectionMap);
+                        }
+                    } finally {
+                        if (!foundResult) {
+                            // We'll be returning a different cursor, so close this one.
+                            cursor.close();
+                        }
+                    }
                 }
                 break;
             }
diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
index 6080f7e..33a39ec 100644
--- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
@@ -57,6 +57,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.BitSet;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.Map;
@@ -1021,12 +1022,20 @@
 
     protected void assertCursorValues(Cursor cursor, ContentValues[] expectedValues) {
         StringBuilder message = new StringBuilder();
+
+        // In case if expectedValues contains multiple identical values, remember which cursor
+        // rows are "consumed" to prevent multiple ContentValues from hitting the same row.
+        final BitSet used = new BitSet(cursor.getCount());
+
         for (ContentValues v : expectedValues) {
             boolean found = false;
             cursor.moveToPosition(-1);
             while (cursor.moveToNext()) {
+                final int pos = cursor.getPosition();
+                if (used.get(pos)) continue;
                 found = equalsWithExpectedValues(cursor, v, message);
                 if (found) {
+                    used.set(pos);
                     break;
                 }
             }
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index eae168f..cbb1c49 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -982,6 +982,9 @@
         insertStructuredName(rawContactId, "Hot", "Tamale");
         insertPhoneNumber(rawContactId, "18004664411");
 
+        // We'll create two lookup records, 18004664411 and +18004664411, and the below lookup
+        // will match both.
+
         Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411");
 
         values.clear();
@@ -992,7 +995,7 @@
         values.putNull(PhoneLookup.LABEL);
         values.put(PhoneLookup.CUSTOM_RINGTONE, "d");
         values.put(PhoneLookup.SEND_TO_VOICEMAIL, 1);
-        assertStoredValues(lookupUri1, values);
+        assertStoredValues(lookupUri1, null, null, new ContentValues[] {values, values});
 
         // In the context that 8004664411 is a valid number, "4664411" as a
         // call id should  match to both "8004664411" and "+18004664411".
@@ -1067,6 +1070,70 @@
         assertEquals(1, getCount(lookupUri2, null, null));
     }
 
+    public void testIntlPhoneLookupUseCases() {
+        // Checks the logic that relies on using the trailing 7-digits as a fallback for phone
+        // number lookups.
+        String fullNumber = "01197297427289";
+
+        ContentValues values = new ContentValues();
+        values.put(RawContacts.CUSTOM_RINGTONE, "d");
+        values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
+        long rawContactId = ContentUris.parseId(mResolver.insert(RawContacts.CONTENT_URI, values));
+        insertStructuredName(rawContactId, "Senor", "Chang");
+        insertPhoneNumber(rawContactId, fullNumber);
+
+        // Full number should definitely match.
+        assertEquals(2, getCount(Uri.withAppendedPath(
+                PhoneLookup.CONTENT_FILTER_URI, fullNumber), null, null));
+
+        // Shorter (local) number with 0 prefix should also match.
+        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));
+
+        // Same shorter number with dashes should match.
+        assertEquals(2, getCount(Uri.withAppendedPath(
+                PhoneLookup.CONTENT_FILTER_URI, "09-742-7289"), null, null));
+
+        // Same shorter number with spaces should match.
+        assertEquals(2, getCount(Uri.withAppendedPath(
+                PhoneLookup.CONTENT_FILTER_URI, "09 742 7289"), null, null));
+
+        // Some other number should not match.
+        assertEquals(0, getCount(Uri.withAppendedPath(
+                PhoneLookup.CONTENT_FILTER_URI, "049102395"), null, null));
+    }
+
+    public void testPhoneLookupB5252190() {
+        // Test cases from b/5252190
+        String storedNumber = "796010101";
+
+        ContentValues values = new ContentValues();
+        values.put(RawContacts.CUSTOM_RINGTONE, "d");
+        values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
+        long rawContactId = ContentUris.parseId(mResolver.insert(RawContacts.CONTENT_URI, values));
+        insertStructuredName(rawContactId, "Senor", "Chang");
+        insertPhoneNumber(rawContactId, storedNumber);
+
+        assertEquals(1, getCount(Uri.withAppendedPath(
+                PhoneLookup.CONTENT_FILTER_URI, "0796010101"), null, null));
+
+        assertEquals(1, getCount(Uri.withAppendedPath(
+                PhoneLookup.CONTENT_FILTER_URI, "+48796010101"), null, null));
+
+        assertEquals(1, getCount(Uri.withAppendedPath(
+                PhoneLookup.CONTENT_FILTER_URI, "48796010101"), null, null));
+
+        assertEquals(1, getCount(Uri.withAppendedPath(
+                PhoneLookup.CONTENT_FILTER_URI, "4-879-601-0101"), null, null));
+
+        assertEquals(1, getCount(Uri.withAppendedPath(
+                PhoneLookup.CONTENT_FILTER_URI, "4 879 601 0101"), null, null));
+    }
+
     public void testPhoneUpdate() {
         ContentValues values = new ContentValues();
         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
@@ -1076,27 +1143,31 @@
         Uri phoneUri = insertPhoneNumber(rawContactId, "18004664411");
 
         Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411");
-        assertStoredValue(lookupUri1, PhoneLookup.DISPLAY_NAME, "Hot Tamale");
+        Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664422");
+        assertEquals(2, getCount(lookupUri1, null, null));
+        assertEquals(0, getCount(lookupUri2, null, null));
 
         values.clear();
         values.put(Phone.NUMBER, "18004664422");
         mResolver.update(phoneUri, values, null, null);
 
-        Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664422");
-        assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale");
+        assertEquals(0, getCount(lookupUri1, null, null));
+        assertEquals(2, getCount(lookupUri2, null, null));
 
         // Setting number to null will remove the phone lookup record
         values.clear();
         values.putNull(Phone.NUMBER);
         mResolver.update(phoneUri, values, null, null);
 
+        assertEquals(0, getCount(lookupUri1, null, null));
         assertEquals(0, getCount(lookupUri2, null, null));
 
         // Let's restore that phone lookup record
         values.clear();
         values.put(Phone.NUMBER, "18004664422");
         mResolver.update(phoneUri, values, null, null);
-        assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale");
+        assertEquals(0, getCount(lookupUri1, null, null));
+        assertEquals(2, getCount(lookupUri2, null, null));
         assertNetworkNotified(true);
     }