Improved the phone lookup and the phone filter

a. Altered the phone_lookup table to allow the rows with the same data_id.
b. Added E164 and normalized number for a phone number if it is applicable.
c. Improve the phone lookup by using the build in SQLite function.
d. Improve the phone filter by using 'Like filterparam%'

Change-Id: I1b23d0a10e46ef26467fb72528a7999d23e36c5e
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 24e8a54..0bf3cb4 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -12,6 +12,8 @@
     <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.cp" />
     <uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_READ" />
     <uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 
     <application android:process="android.process.acore"
         android:label="@string/app_label"
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index 03f93a8..ad3ab72 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -34,6 +34,7 @@
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.database.sqlite.SQLiteStatement;
+import android.location.CountryDetector;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -87,7 +88,7 @@
      *   400-499 Honeycomb
      * </pre>
      */
-    static final int DATABASE_VERSION = 404;
+    static final int DATABASE_VERSION = 405;
 
     private static final String DATABASE_NAME = "contacts2.db";
     private static final String DATABASE_PRESENCE = "presence_db";
@@ -785,7 +786,7 @@
         // Private phone numbers table used for lookup
         db.execSQL("CREATE TABLE " + Tables.PHONE_LOOKUP + " (" +
                 PhoneLookupColumns.DATA_ID
-                        + " INTEGER PRIMARY KEY REFERENCES data(_id) NOT NULL," +
+                        + " INTEGER REFERENCES data(_id) NOT NULL," +
                 PhoneLookupColumns.RAW_CONTACT_ID
                         + " INTEGER REFERENCES raw_contacts(_id) NOT NULL," +
                 PhoneLookupColumns.NORMALIZED_NUMBER + " TEXT NOT NULL," +
@@ -1584,6 +1585,12 @@
             oldVersion = 404;
         }
 
+        if (oldVersion == 404) {
+            upgradeViewsAndTriggers = true;
+            upgradeToVersion405(db);
+            oldVersion = 405;
+        }
+
         if (upgradeViewsAndTriggers) {
             createContactsViews(db);
             createGroupsView(db);
@@ -2530,6 +2537,72 @@
                 + " ADD is_read_only INTEGER NOT NULL DEFAULT 0;");
     }
 
+    private void upgradeToVersion405(SQLiteDatabase db) {
+        db.execSQL("DROP TABLE IF EXISTS phone_lookup;");
+        // Private phone numbers table used for lookup
+        db.execSQL("CREATE TABLE " + Tables.PHONE_LOOKUP + " (" +
+                PhoneLookupColumns.DATA_ID
+                + " INTEGER REFERENCES data(_id) NOT NULL," +
+                PhoneLookupColumns.RAW_CONTACT_ID
+                + " INTEGER REFERENCES raw_contacts(_id) NOT NULL," +
+                PhoneLookupColumns.NORMALIZED_NUMBER + " TEXT NOT NULL," +
+                PhoneLookupColumns.MIN_MATCH + " TEXT NOT NULL" +
+        ");");
+
+        db.execSQL("CREATE INDEX phone_lookup_index ON " + Tables.PHONE_LOOKUP + " (" +
+                PhoneLookupColumns.NORMALIZED_NUMBER + "," +
+                PhoneLookupColumns.RAW_CONTACT_ID + "," +
+                PhoneLookupColumns.DATA_ID +
+        ");");
+
+        db.execSQL("CREATE INDEX phone_lookup_min_match_index ON " + Tables.PHONE_LOOKUP + " (" +
+                PhoneLookupColumns.MIN_MATCH + "," +
+                PhoneLookupColumns.RAW_CONTACT_ID + "," +
+                PhoneLookupColumns.DATA_ID +
+        ");");
+
+        final long mimeTypeId = lookupMimeTypeId(db, Phone.CONTENT_ITEM_TYPE);
+        if (mimeTypeId == -1) {
+            return;
+        }
+
+        String mCountryIso = getCountryIso();
+        Cursor cursor = db.rawQuery(
+                    "SELECT _id, " + Phone.RAW_CONTACT_ID + ", " + Phone.NUMBER +
+                    " FROM " + Tables.DATA +
+                    " WHERE " + DataColumns.MIMETYPE_ID + "=" + mimeTypeId
+                            + " AND " + Phone.NUMBER + " NOT NULL", null);
+
+        ContentValues phoneValues = new ContentValues();
+        try {
+            while (cursor.moveToNext()) {
+                long dataID = cursor.getLong(0);
+                long rawContactID = cursor.getLong(1);
+                String number = cursor.getString(2);
+                String numberE164 = PhoneNumberUtils.formatNumberToE164(number, mCountryIso);
+                String normalizedNumber = PhoneNumberUtils.normalizeNumber(number);
+                if (!TextUtils.isEmpty(normalizedNumber)) {
+                    phoneValues.clear();
+                    phoneValues.put(PhoneLookupColumns.RAW_CONTACT_ID, rawContactID);
+                    phoneValues.put(PhoneLookupColumns.DATA_ID, dataID);
+                    phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, normalizedNumber);
+                    phoneValues.put(PhoneLookupColumns.MIN_MATCH,
+                            PhoneNumberUtils.toCallerIDMinMatch(normalizedNumber));
+                    db.insert(Tables.PHONE_LOOKUP, null, phoneValues);
+
+                    if (numberE164 != null && !numberE164.equals(normalizedNumber)) {
+                        phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, numberE164);
+                        phoneValues.put(PhoneLookupColumns.MIN_MATCH,
+                                PhoneNumberUtils.toCallerIDMinMatch(numberE164));
+                        db.insert(Tables.PHONE_LOOKUP, null, phoneValues);
+                    }
+                }
+            }
+        } finally {
+            cursor.close();
+        }
+    }
+
     public String extractHandleFromEmailAddress(String email) {
         Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(email);
         if (tokens.length == 0) {
@@ -2856,30 +2929,15 @@
         }
     }
 
-    public void buildPhoneLookupAndRawContactQuery(SQLiteQueryBuilder qb, String number) {
-        String minMatch = PhoneNumberUtils.toCallerIDMinMatch(number);
-        qb.setTables(Tables.DATA_JOIN_RAW_CONTACTS +
-                " JOIN " + Tables.PHONE_LOOKUP
-                + " ON(" + DataColumns.CONCRETE_ID + "=" + PhoneLookupColumns.DATA_ID + ")");
-
-        StringBuilder sb = new StringBuilder();
-        sb.append(PhoneLookupColumns.MIN_MATCH + "='");
-        sb.append(minMatch);
-        sb.append("' AND PHONE_NUMBERS_EQUAL(data." + Phone.NUMBER + ", ");
-        DatabaseUtils.appendEscapedSQLString(sb, number);
-        sb.append(mUseStrictPhoneNumberComparison ? ", 1)" : ", 0)");
-
-        qb.appendWhere(sb.toString());
-    }
-
-    public void buildPhoneLookupAndContactQuery(SQLiteQueryBuilder qb, String number) {
-        String minMatch = PhoneNumberUtils.toCallerIDMinMatch(number);
+    public void buildPhoneLookupAndContactQuery(
+            SQLiteQueryBuilder qb, String normalizedNumber, String numberE164) {
+        String minMatch = PhoneNumberUtils.toCallerIDMinMatch(normalizedNumber);
         StringBuilder sb = new StringBuilder();
         appendPhoneLookupTables(sb, minMatch, true);
         qb.setTables(sb.toString());
 
         sb = new StringBuilder();
-        appendPhoneLookupSelection(sb, number);
+        appendPhoneLookupSelection(sb, normalizedNumber, numberE164);
         qb.appendWhere(sb.toString());
     }
 
@@ -2889,7 +2947,7 @@
         sb.append("(SELECT DISTINCT raw_contact_id" + " FROM ");
         appendPhoneLookupTables(sb, minMatch, false);
         sb.append(" WHERE ");
-        appendPhoneLookupSelection(sb, number);
+        appendPhoneLookupSelection(sb, number, null);
         sb.append(")");
         return sb.toString();
     }
@@ -2901,17 +2959,38 @@
             sb.append(" JOIN " + getContactView() + " contacts_view"
                     + " ON (contacts_view._id = raw_contacts.contact_id)");
         }
-        sb.append(", (SELECT data_id FROM phone_lookup "
-                + "WHERE (" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.MIN_MATCH + " = '");
+        sb.append(", (SELECT data_id, normalized_number, length(normalized_number) as len "
+                + " FROM phone_lookup " + " WHERE (" + Tables.PHONE_LOOKUP + "."
+                + PhoneLookupColumns.MIN_MATCH + " = '");
         sb.append(minMatch);
         sb.append("')) AS lookup, " + Tables.DATA);
     }
 
-    private void appendPhoneLookupSelection(StringBuilder sb, String number) {
-        sb.append("lookup.data_id=data._id AND data.raw_contact_id=raw_contacts._id"
-                + " AND PHONE_NUMBERS_EQUAL(data." + Phone.NUMBER + ", ");
-        DatabaseUtils.appendEscapedSQLString(sb, number);
-        sb.append(mUseStrictPhoneNumberComparison ? ", 1)" : ", 0)");
+    private void appendPhoneLookupSelection(StringBuilder sb, String number, String numberE164) {
+        sb.append("lookup.data_id=data._id AND data.raw_contact_id=raw_contacts._id");
+        boolean hasNumberE164 = !TextUtils.isEmpty(numberE164);
+        boolean hasNumber = !TextUtils.isEmpty(number);
+        if (hasNumberE164 || hasNumber) {
+            sb.append(" AND ( ");
+            if (hasNumberE164) {
+                sb.append(" lookup.normalized_number = ");
+                DatabaseUtils.appendEscapedSQLString(sb, numberE164);
+            }
+            if (hasNumberE164 && hasNumber) {
+                sb.append(" OR ");
+            }
+            if (hasNumber) {
+                int numberLen = number.length();
+                sb.append(" lookup.len <= ");
+                sb.append(numberLen);
+                sb.append(" AND substr(");
+                DatabaseUtils.appendEscapedSQLString(sb, number);
+                sb.append(',');
+                sb.append(numberLen);
+                sb.append(" - lookup.len + 1) = lookup.normalized_number");
+            }
+            sb.append(')');
+        }
     }
 
     public String getUseStrictPhoneNumberComparisonParameter() {
@@ -3198,4 +3277,10 @@
 
         return sb.toString();
     }
+
+    protected String getCountryIso() {
+        CountryDetector detector =
+            (CountryDetector) mContext.getSystemService(Context.COUNTRY_DETECTOR);
+        return detector.detectCountry().getCountryIso();
+    }
 }
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 7828a3a..cdcceab 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -74,11 +74,16 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.database.sqlite.SQLiteStatement;
+import android.location.Country;
+import android.location.CountryDetector;
+import android.location.CountryListener;
 import android.net.Uri;
 import android.net.Uri.Builder;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.HandlerThread;
 import android.os.MemoryFile;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.preference.PreferenceManager;
@@ -1540,14 +1545,17 @@
             long dataId;
             if (values.containsKey(Phone.NUMBER)) {
                 String number = values.getAsString(Phone.NUMBER);
-                String normalizedNumber = computeNormalizedNumber(number);
-                values.put(PhoneColumns.NORMALIZED_NUMBER, normalizedNumber);
+                String numberE164 =
+                    PhoneNumberUtils.formatNumberToE164(number, getCurrentCountryIso());
+                if (numberE164 != null) {
+                    values.put(PhoneColumns.NORMALIZED_NUMBER, numberE164);
+                }
                 dataId = super.insert(db, rawContactId, values);
 
-                updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
+                updatePhoneLookup(db, rawContactId, dataId, number, numberE164);
                 mContactAggregator.updateHasPhoneNumber(db, rawContactId);
                 fixRawContactDisplayName(db, rawContactId);
-                if (normalizedNumber != null) {
+                if (numberE164 != null) {
                     triggerAggregation(rawContactId);
                 }
             } else {
@@ -1561,10 +1569,16 @@
                 boolean callerIsSyncAdapter) {
             String number = null;
             String normalizedNumber = null;
+            String numberE164 = null;
             if (values.containsKey(Phone.NUMBER)) {
                 number = values.getAsString(Phone.NUMBER);
-                normalizedNumber = computeNormalizedNumber(number);
-                values.put(PhoneColumns.NORMALIZED_NUMBER, normalizedNumber);
+                if (number != null) {
+                    numberE164 =
+                        PhoneNumberUtils.formatNumberToE164(number, getCurrentCountryIso());
+                }
+                if (numberE164 != null) {
+                    values.put(PhoneColumns.NORMALIZED_NUMBER, numberE164);
+                }
             }
 
             if (!super.update(db, values, c, callerIsSyncAdapter)) {
@@ -1574,7 +1588,7 @@
             if (values.containsKey(Phone.NUMBER)) {
                 long dataId = c.getLong(DataUpdateQuery._ID);
                 long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
-                updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
+                updatePhoneLookup(db, rawContactId, dataId, number, numberE164);
                 mContactAggregator.updateHasPhoneNumber(db, rawContactId);
                 fixRawContactDisplayName(db, rawContactId);
                 triggerAggregation(rawContactId);
@@ -1596,28 +1610,28 @@
             return count;
         }
 
-        private String computeNormalizedNumber(String number) {
-            String normalizedNumber = null;
-            if (number != null) {
-                normalizedNumber = PhoneNumberUtils.getStrippedReversed(number);
-            }
-            return normalizedNumber;
-        }
-
         private void updatePhoneLookup(SQLiteDatabase db, long rawContactId, long dataId,
-                String number, String normalizedNumber) {
+                String number, String numberE164) {
+            mSelectionArgs1[0] = String.valueOf(dataId);
+            db.delete(Tables.PHONE_LOOKUP, PhoneLookupColumns.DATA_ID + "=?", mSelectionArgs1);
             if (number != null) {
-                ContentValues phoneValues = new ContentValues();
-                phoneValues.put(PhoneLookupColumns.RAW_CONTACT_ID, rawContactId);
-                phoneValues.put(PhoneLookupColumns.DATA_ID, dataId);
-                phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, normalizedNumber);
-                phoneValues.put(PhoneLookupColumns.MIN_MATCH,
-                        PhoneNumberUtils.toCallerIDMinMatch(number));
+                String normalizedNumber = PhoneNumberUtils.normalizeNumber(number);
+                if (!TextUtils.isEmpty(normalizedNumber)) {
+                    ContentValues phoneValues = new ContentValues();
+                    phoneValues.put(PhoneLookupColumns.RAW_CONTACT_ID, rawContactId);
+                    phoneValues.put(PhoneLookupColumns.DATA_ID, dataId);
+                    phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, normalizedNumber);
+                    phoneValues.put(PhoneLookupColumns.MIN_MATCH,
+                            PhoneNumberUtils.toCallerIDMinMatch(normalizedNumber));
+                    db.insert(Tables.PHONE_LOOKUP, null, phoneValues);
 
-                db.replace(Tables.PHONE_LOOKUP, null, phoneValues);
-            } else {
-                mSelectionArgs1[0] = String.valueOf(dataId);
-                db.delete(Tables.PHONE_LOOKUP, PhoneLookupColumns.DATA_ID + "=?", mSelectionArgs1);
+                    if (numberE164 != null && !numberE164.equals(normalizedNumber)) {
+                        phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, numberE164);
+                        phoneValues.put(PhoneLookupColumns.MIN_MATCH,
+                                PhoneNumberUtils.toCallerIDMinMatch(numberE164));
+                        db.insert(Tables.PHONE_LOOKUP, null, phoneValues);
+                    }
+                }
             }
         }
 
@@ -1835,6 +1849,7 @@
 
     private Locale mCurrentLocale;
 
+    private String mCurrentCountryIso;
 
 
     @Override
@@ -1980,6 +1995,26 @@
         return (mDb != null);
     }
 
+    protected synchronized String getCurrentCountryIso() {
+        if (mCurrentCountryIso == null) {
+            final CountryDetector countryDetector =
+                (CountryDetector)getContext().getSystemService(Context.COUNTRY_DETECTOR);
+            mCurrentCountryIso = countryDetector.detectCountry().getCountryIso();
+            // Start a new thread to listen to the country change.
+            (new HandlerThread("country listener", Process.THREAD_PRIORITY_BACKGROUND) {
+                @Override
+                protected void onLooperPrepared() {
+                    countryDetector.addCountryListener(new CountryListener() {
+                        public void onCountryDetected(Country country) {
+                            mCurrentCountryIso = country.getCountryIso();
+                        }
+                    }, null);
+                }
+            }).start();
+        }
+        return mCurrentCountryIso;
+    }
+
     private void initDataRowHandlers() {
       mDataRowHandlers = new HashMap<String, DataRowHandler>();
 
@@ -3091,12 +3126,16 @@
             Cursor c = mDb.query(Tables.RAW_CONTACTS,
                     new String[]{RawContacts._ID, RawContacts.STARRED},
                     selection, selectionArgs, null, null, null);
-            while (c.moveToNext()) {
-                if (c.getLong(1) != 0) {
-                    final long rawContactId = c.getLong(0);
-                    insertDataGroupMembership(rawContactId, result);
-                    setRawContactDirty(rawContactId);
+            try {
+                while (c.moveToNext()) {
+                    if (c.getLong(1) != 0) {
+                        final long rawContactId = c.getLong(0);
+                        insertDataGroupMembership(rawContactId, result);
+                        setRawContactDirty(rawContactId);
+                    }
                 }
+            } finally {
+                c.close();
             }
         }
 
@@ -4625,18 +4664,17 @@
                         hasCondition = true;
                     }
 
-                    if (isPhoneNumber(filterParam)) {
+                    String number = PhoneNumberUtils.normalizeNumber(filterParam);
+                    if (!TextUtils.isEmpty(number)) {
                         if (orNeeded) {
                             sb.append(" OR ");
                         }
-                        String number = PhoneNumberUtils.convertKeypadLettersToDigits(filterParam);
-                        String reversed = PhoneNumberUtils.getStrippedReversed(number);
                         sb.append(Data._ID +
-                                " IN (SELECT " + PhoneLookupColumns.DATA_ID
-                                  + " FROM " + Tables.PHONE_LOOKUP
-                                  + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '%");
-                        sb.append(reversed);
-                        sb.append("')");
+                                " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID
+                                + " FROM " + Tables.PHONE_LOOKUP
+                                + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '");
+                        sb.append(number);
+                        sb.append("%')");
                         hasCondition = true;
                     }
 
@@ -4787,13 +4825,16 @@
                 if (TextUtils.isEmpty(sortOrder)) {
                     // Default the sort order to something reasonable so we get consistent
                     // results when callers don't request an ordering
-                    sortOrder = RawContactsColumns.CONCRETE_ID;
+                    sortOrder = " length(lookup.normalized_number) DESC";
                 }
 
                 String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : "";
-                mDbHelper.buildPhoneLookupAndContactQuery(qb, number);
+                String numberE164 =
+                        PhoneNumberUtils.formatNumberToE164(number, getCurrentCountryIso());
+                String normalizedNumber =
+                        PhoneNumberUtils.normalizeNumber(number);
+                mDbHelper.buildPhoneLookupAndContactQuery(qb, normalizedNumber, numberE164);
                 qb.setProjectionMap(sPhoneLookupProjectionMap);
-
                 // Phone lookup cannot be combined with a selection
                 selection = null;
                 selectionArgs = null;
@@ -5703,36 +5744,6 @@
         }
     }
 
-    /**
-     * Returns true if all the characters are meaningful as digits
-     * in a phone number -- letters, digits, and a few punctuation marks.
-     */
-    private boolean isPhoneNumber(CharSequence cons) {
-        int len = cons.length();
-
-        for (int i = 0; i < len; i++) {
-            char c = cons.charAt(i);
-
-            if ((c >= '0') && (c <= '9')) {
-                continue;
-            }
-            if ((c == ' ') || (c == '-') || (c == '(') || (c == ')') || (c == '.') || (c == '+')
-                    || (c == '#') || (c == '*')) {
-                continue;
-            }
-            if ((c >= 'A') && (c <= 'Z')) {
-                continue;
-            }
-            if ((c >= 'a') && (c <= 'z')) {
-                continue;
-            }
-
-            return false;
-        }
-
-        return true;
-    }
-
     String getContactsRestrictions() {
         if (mDbHelper.hasAccessToRestrictedData()) {
             return "1";
diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
index 3f672e4..944e853 100644
--- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
@@ -732,6 +732,10 @@
         assertStoredValues(rowUri, null, null, expectedValues);
     }
 
+    protected void assertStoredValues(Uri rowUri, ContentValues[] expectedValues) {
+        assertStoredValues(rowUri, null, null, expectedValues);
+    }
+
     protected void assertStoredValues(Uri rowUri, String selection, String[] selectionArgs,
             ContentValues expectedValues) {
         Cursor c = mResolver.query(rowUri, null, selection, selectionArgs, null);
@@ -755,6 +759,17 @@
         }
     }
 
+    protected void assertStoredValues(
+            Uri rowUri, String selection, String[] selectionArgs, ContentValues[] expectedValues) {
+        Cursor c = mResolver.query(rowUri, null, selection, selectionArgs, null);
+        try {
+            assertEquals("Record count", expectedValues.length, c.getCount());
+            assertCursorValues(c, expectedValues);
+        } finally {
+            c.close();
+        }
+    }
+
     /**
      * Constructs a selection (where clause) out of all supplied values, uses it
      * to query the provider and verifies that a single row is returned and it
@@ -804,11 +819,36 @@
     }
 
     protected void assertCursorValues(Cursor cursor, ContentValues expectedValues) {
+        StringBuilder message = new StringBuilder();
+        boolean result = equalsWithExpectedValues(cursor, expectedValues, message);
+        assertTrue(message.toString(), result);
+    }
+
+    protected void assertCursorValues(Cursor cursor, ContentValues[] expectedValues) {
+        StringBuilder message = new StringBuilder();
+        for (ContentValues v : expectedValues) {
+            boolean found = false;
+            cursor.moveToPosition(-1);
+            while (cursor.moveToNext()) {
+                found = equalsWithExpectedValues(cursor, v, message);
+                if (found) {
+                    break;
+                }
+            }
+            assertTrue("Expected values can not be found " + v + message.toString(), found);
+        }
+    }
+
+    private boolean equalsWithExpectedValues(Cursor cursor, ContentValues expectedValues,
+            StringBuilder msgBuffer) {
         Set<Map.Entry<String, Object>> entries = expectedValues.valueSet();
         for (Map.Entry<String, Object> entry : entries) {
             String column = entry.getKey();
             int index = cursor.getColumnIndex(column);
-            assertTrue("No such column: " + column, index != -1);
+            if (index == -1) {
+                msgBuffer.append("No such column: ").append(column);
+                return false;
+            }
             Object expectedValue = expectedValues.get(column);
             String value;
             if (expectedValue instanceof byte[]) {
@@ -818,8 +858,20 @@
                 expectedValue = expectedValues.getAsString(column);
                 value = cursor.getString(index);
             }
-            assertEquals("Column value " + column, expectedValue, value);
+            if (expectedValue != null && !expectedValue.equals(value) || value != null
+                    && !value.equals(expectedValue)) {
+                msgBuffer
+                        .append("Column value ")
+                        .append(column)
+                        .append(" expected <")
+                        .append(expectedValue)
+                        .append(">, but was <")
+                        .append(value)
+                        .append('>');
+                return false;
+            }
         }
+        return true;
     }
 
     private String[] buildProjection(ContentValues values) {
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index db1edf0..8882869 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -891,16 +891,77 @@
         values.put(PhoneLookup.SEND_TO_VOICEMAIL, 1);
         assertStoredValues(lookupUri1, values);
 
-        // The strict comparation, adopted in Donut, does not allow the behavior like
-        // "8004664411 == 4664411", while the loose comparation, which had been used in Cupcake
-        // and reverted back into the default in Eclair, allows it. Hmm...
-        final boolean useStrictComparation =
-            mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_use_strict_phone_number_comparation);
-        final int expectedResult = (useStrictComparation ? 0 : 1);
-
+        // In the context that 8004664411 is a valid number, "4664411" as a
+        // call id should not match to "8004664411"
         Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "4664411");
-        assertEquals(expectedResult, getCount(lookupUri2, null, null));
+        assertEquals(0, getCount(lookupUri2, null, null));
+    }
+
+    public void testPhoneLookupUseCases() {
+        ContentValues values = new ContentValues();
+        Uri rawContactUri;
+        long rawContactId;
+        Uri lookupUri2;
+
+        values.put(RawContacts.CUSTOM_RINGTONE, "d");
+        values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
+
+        // International format in contacts
+        rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
+        rawContactId = ContentUris.parseId(rawContactUri);
+
+        insertStructuredName(rawContactId, "Hot", "Tamale");
+        insertPhoneNumber(rawContactId, "+1-650-861-0000");
+
+        values.clear();
+
+        // match with international format
+        lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0000");
+        assertEquals(1, getCount(lookupUri2, null, null));
+
+        // match with national format
+        lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0000");
+        assertEquals(1, getCount(lookupUri2, null, null));
+
+        // National format in contacts
+        values.clear();
+        values.put(RawContacts.CUSTOM_RINGTONE, "d");
+        values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
+        rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
+        rawContactId = ContentUris.parseId(rawContactUri);
+
+        insertStructuredName(rawContactId, "Hot1", "Tamale");
+        insertPhoneNumber(rawContactId, "650-861-0001");
+
+        values.clear();
+
+        // match with international format
+        lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0001");
+        assertEquals(2, getCount(lookupUri2, null, null));
+
+        // match with national format
+        lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0001");
+        assertEquals(2, getCount(lookupUri2, null, null));
+
+        // Local format in contacts
+        values.clear();
+        values.put(RawContacts.CUSTOM_RINGTONE, "d");
+        values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
+        rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
+        rawContactId = ContentUris.parseId(rawContactUri);
+
+        insertStructuredName(rawContactId, "Hot2", "Tamale");
+        insertPhoneNumber(rawContactId, "861-0002");
+
+        values.clear();
+
+        // match with international format
+        lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0002");
+        assertEquals(1, getCount(lookupUri2, null, null));
+
+        // match with national format
+        lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0002");
+        assertEquals(1, getCount(lookupUri2, null, null));
     }
 
     public void testPhoneUpdate() {
diff --git a/tests/src/com/android/providers/contacts/LegacyContactsProviderTest.java b/tests/src/com/android/providers/contacts/LegacyContactsProviderTest.java
index 85ed6a7..d2e4365 100644
--- a/tests/src/com/android/providers/contacts/LegacyContactsProviderTest.java
+++ b/tests/src/com/android/providers/contacts/LegacyContactsProviderTest.java
@@ -392,19 +392,22 @@
         values.put(Phones.ISPRIMARY, 1);
 
         Uri uri = mResolver.insert(Phones.CONTENT_URI, values);
-
+        ContentValues expectedResults[] = new ContentValues[2];
         // Adding another value to assert
-        values.put(Phones.NUMBER_KEY, "11446640081");
-
+        expectedResults[0] = new ContentValues(values);
+        expectedResults[0].put(Phones.NUMBER_KEY, "+18004664411");
+        expectedResults[1] = values;
+        expectedResults[1].put(Phones.NUMBER_KEY, "18004664411");
         // The result is joined with People
-        putContactValues(values);
-        assertStoredValues(uri, values);
+        putContactValues(expectedResults[0]);
+        putContactValues(expectedResults[1]);
+        assertStoredValues(uri, expectedResults);
         assertSelection(Phones.CONTENT_URI, values, "phones",
                 Phones._ID, ContentUris.parseId(uri));
 
         // Access the phone through People
         Uri twigUri = Uri.withAppendedPath(personUri, People.Phones.CONTENT_DIRECTORY);
-        assertStoredValues(twigUri, values);
+        assertStoredValues(twigUri, expectedResults);
 
         // Now the person should be joined with Phone
         values.clear();
@@ -443,7 +446,12 @@
 
         mResolver.update(uri, values, null, null);
 
-        assertStoredValues(uri, values);
+        ContentValues[] expectedValues = new ContentValues[2];
+        expectedValues[0] = values;
+        expectedValues[0].put(Phones.NUMBER_KEY, "18005554663");
+        expectedValues[1] = new ContentValues(values);
+        expectedValues[1].put(Phones.NUMBER_KEY, "+18005554663");
+        assertStoredValues(uri, expectedValues);
     }
 
     public void testPhonesFilterQuery() {
@@ -456,13 +464,18 @@
         values.put(Phones.PERSON_ID, personId);
         values.put(Phones.TYPE, Phones.TYPE_CUSTOM);
         values.put(Phones.LABEL, "Directory");
-        values.put(Phones.NUMBER, "1-800-4664-411");
+        values.put(Phones.NUMBER, "800-4664-411");
         values.put(Phones.ISPRIMARY, 1);
 
         Uri uri = mResolver.insert(Phones.CONTENT_URI, values);
 
-        Uri filterUri1 = Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, "8004664411");
-        assertStoredValues(filterUri1, values);
+        Uri filterUri1 = Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, "18004664411");
+        ContentValues[] expectedValues = new ContentValues[2];
+        expectedValues[0] = values;
+        expectedValues[0].put(Phones.NUMBER_KEY, "8004664411");
+        expectedValues[1] = new ContentValues(values);
+        expectedValues[1].put(Phones.NUMBER_KEY, "+18004664411");
+        assertStoredValues(filterUri1, expectedValues);
 
         Uri filterUri2 = Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, "7773334444");
         assertEquals(0, getCount(filterUri2, null, null));
diff --git a/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java b/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java
index ba8b7f8..a280bb2 100644
--- a/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java
+++ b/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java
@@ -38,7 +38,12 @@
     @Override
     protected ContactsDatabaseHelper getDatabaseHelper(final Context context) {
         if (mDbHelper == null) {
-            mDbHelper = new ContactsDatabaseHelper(context);
+            mDbHelper = new ContactsDatabaseHelper(context) {
+                @Override
+                protected String getCountryIso() {
+                    return "US";
+                }
+            };
         }
         return mDbHelper;
     }
@@ -166,4 +171,9 @@
         // We have an explicit test for data conversion - no need to do it every time
         return false;
     }
+
+    @Override
+    protected String getCurrentCountryIso() {
+        return "us";
+    }
 }