From 3a72a0af9a390046cf0018fd76f02dcb64eda027 Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Tue, 3 Sep 2013 13:44:08 +0200 Subject: Correctly match against normalized phone numbers. When trying to match against inserted phone numbers, using the normalized number is the only way to get reliable results - otherwise it depends on the number formatting whether a match is found or not. Change-Id: If2aa03f9d9c978ba9f2008929162570766ffdafd --- chips/Android.mk | 3 +- chips/src/com/android/ex/chips/Queries.java | 13 +++-- .../ex/chips/RecipientAlternatesAdapter.java | 55 ++++++++++++++-------- .../android/ex/chips/RecipientEditTextView.java | 27 +++++------ 4 files changed, 59 insertions(+), 39 deletions(-) diff --git a/chips/Android.mk b/chips/Android.mk index 6aa8a01..18b7fd5 100644 --- a/chips/Android.mk +++ b/chips/Android.mk @@ -16,7 +16,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := android-common-chips -LOCAL_SDK_VERSION := 14 LOCAL_SRC_FILES := \ $(call all-java-files-under, src) \ $(call all-logtags-files-under, src) @@ -26,4 +25,4 @@ include $(BUILD_STATIC_JAVA_LIBRARY) ################################################## # Build all sub-directories -include $(call all-makefiles-under,$(LOCAL_PATH)) \ No newline at end of file +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/chips/src/com/android/ex/chips/Queries.java b/chips/src/com/android/ex/chips/Queries.java index 9d31aec..ab548a6 100644 --- a/chips/src/com/android/ex/chips/Queries.java +++ b/chips/src/com/android/ex/chips/Queries.java @@ -36,7 +36,7 @@ import android.provider.ContactsContract.Contacts; Phone._ID, // 5 Contacts.PHOTO_THUMBNAIL_URI,// 6 Contacts.DISPLAY_NAME_SOURCE // 7 - }, Phone.CONTENT_FILTER_URI, Phone.CONTENT_URI) { + }, Phone.CONTENT_FILTER_URI, Phone.CONTENT_URI, Phone.NORMALIZED_NUMBER) { @Override public CharSequence getTypeLabel(Resources res, int type, CharSequence label) { @@ -54,7 +54,7 @@ import android.provider.ContactsContract.Contacts; Email._ID, // 5 Contacts.PHOTO_THUMBNAIL_URI,// 6 Contacts.DISPLAY_NAME_SOURCE // 7 - }, Email.CONTENT_FILTER_URI, Email.CONTENT_URI) { + }, Email.CONTENT_FILTER_URI, Email.CONTENT_URI, Email.DATA) { @Override public CharSequence getTypeLabel(Resources res, int type, CharSequence label) { @@ -67,6 +67,7 @@ import android.provider.ContactsContract.Contacts; private final String[] mProjection; private final Uri mContentFilterUri; private final Uri mContentUri; + private final String mSelectionColumn; public static final int NAME = 0; // String public static final int DESTINATION = 1; // String @@ -77,10 +78,12 @@ import android.provider.ContactsContract.Contacts; public static final int PHOTO_THUMBNAIL_URI = 6; // String public static final int DISPLAY_NAME_SOURCE = 7; // int - public Query (String[] projection, Uri contentFilter, Uri content) { + public Query (String[] projection, Uri contentFilter, + Uri content, String selectionColumn) { mProjection = projection; mContentFilterUri = contentFilter; mContentUri = content; + mSelectionColumn = selectionColumn; } public String[] getProjection() { @@ -95,6 +98,10 @@ import android.provider.ContactsContract.Contacts; return mContentUri; } + public String getSelectionColumn() { + return mSelectionColumn; + } + public abstract CharSequence getTypeLabel(Resources res, int type, CharSequence label); } } diff --git a/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java b/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java index 0693df2..237e442 100644 --- a/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java +++ b/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java @@ -21,8 +21,10 @@ import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.database.MatrixCursor; +import android.location.CountryDetector; import android.net.Uri; import android.provider.ContactsContract; +import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import android.text.util.Rfc822Token; import android.text.util.Rfc822Tokenizer; @@ -73,11 +75,6 @@ public class RecipientAlternatesAdapter extends CursorAdapter { public void matchesNotFound(Set unfoundAddresses); } - public static void getMatchingRecipients(Context context, ArrayList inAddresses, - Account account, RecipientMatchCallback callback) { - getMatchingRecipients(context, inAddresses, QUERY_TYPE_EMAIL, account, callback); - } - /** * Get a HashMap of address to RecipientEntry that contains all contact * information for a contact with the provided address, if one exists. This @@ -90,23 +87,26 @@ public class RecipientAlternatesAdapter extends CursorAdapter { */ public static void getMatchingRecipients(Context context, ArrayList inAddresses, int addressType, Account account, RecipientMatchCallback callback) { - Queries.Query query; - if (addressType == QUERY_TYPE_EMAIL) { - query = Queries.EMAIL; - } else { - query = Queries.PHONE; - } + boolean isPhoneQuery = addressType == QUERY_TYPE_PHONE; + Queries.Query query = isPhoneQuery ? Queries.PHONE : Queries.EMAIL; + int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.size()); HashSet addresses = new HashSet(); StringBuilder bindString = new StringBuilder(); + // Create the "?" string and set up arguments. for (int i = 0; i < addressesSize; i++) { - Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses.get(i).toLowerCase()); - addresses.add(tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i)); - bindString.append("?"); - if (i < addressesSize - 1) { + String normalized = normalizeAddress(context, inAddresses.get(i), isPhoneQuery); + if (TextUtils.isEmpty(normalized)) { + continue; + } + Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(normalized); + String tokenized = tokens.length > 0 ? tokens[0].getAddress() : normalized; + addresses.add(tokenized); + if (bindString.length() > 0) { bindString.append(","); } + bindString.append("?"); } if (Log.isLoggable(TAG, Log.DEBUG)) { @@ -122,9 +122,9 @@ public class RecipientAlternatesAdapter extends CursorAdapter { c = context.getContentResolver().query( query.getContentUri(), query.getProjection(), - query.getProjection()[Queries.Query.DESTINATION] + " IN (" + query.getSelectionColumn() + " IN (" + bindString.toString() + ")", addressArray, null); - recipientEntries = processContactEntries(c); + recipientEntries = processContactEntries(context, c, isPhoneQuery); callback.matchesFound(recipientEntries); } finally { if (c != null) { @@ -177,7 +177,8 @@ public class RecipientAlternatesAdapter extends CursorAdapter { if (directoryContactsCursor != null) { try { final Map entries = - processContactEntries(directoryContactsCursor); + processContactEntries(context, + directoryContactsCursor, isPhoneQuery); for (final String address : entries.keySet()) { matchesNotFound.remove(address); @@ -194,11 +195,25 @@ public class RecipientAlternatesAdapter extends CursorAdapter { callback.matchesNotFound(matchesNotFound); } - private static HashMap processContactEntries(Cursor c) { + public static String normalizeAddress(Context context, String address, boolean isPhone) { + if (!isPhone) { + return address.toLowerCase(); + } + + final CountryDetector detector = + (CountryDetector) context.getSystemService(Context.COUNTRY_DETECTOR); + final String currentCountryIso = detector.detectCountry().getCountryIso(); + + return PhoneNumberUtils.formatNumberToE164(address, currentCountryIso); + } + + private static HashMap processContactEntries(Context context, + Cursor c, boolean isPhoneQuery) { HashMap recipientEntries = new HashMap(); if (c != null && c.moveToFirst()) { do { - String address = c.getString(Queries.Query.DESTINATION); + String address = normalizeAddress(context, + c.getString(Queries.Query.DESTINATION), isPhoneQuery); final RecipientEntry newRecipientEntry = RecipientEntry.constructTopLevelEntry( c.getString(Queries.Query.NAME), diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index d2e5806..765438a 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -1068,12 +1068,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements return mValidator == null ? true : mValidator.isValid(text); } - private static String tokenizeAddress(String destination) { - Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(destination); - if (tokens != null && tokens.length > 0) { - return tokens[0].getAddress(); - } - return destination; + private String normalizeAddress(String destination) { + return RecipientAlternatesAdapter.normalizeAddress(getContext(), + destination, isPhoneQuery()); } @Override @@ -2497,7 +2494,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements return null; } RecipientAlternatesAdapter.getMatchingRecipients(getContext(), addresses, - adapter.getAccount(), new RecipientMatchCallback() { + adapter.getQueryType(), adapter.getAccount(), new RecipientMatchCallback() { @Override public void matchesFound(Map entries) { final ArrayList replacements = @@ -2508,9 +2505,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements temp.getEntry().getContactId()) && getSpannable().getSpanStart(temp) != -1) { // Replace this. - entry = createValidatedEntry( - entries.get(tokenizeAddress(temp.getEntry() - .getDestination()))); + String normalized = normalizeAddress( + temp.getEntry().getDestination()); + entry = createValidatedEntry(entries.get(normalized)); } if (entry != null) { replacements.add(createFreeChip(entry)); @@ -2623,8 +2620,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements addresses.add(createAddressText(chip.getEntry())); } } + final BaseRecipientAdapter adapter = (BaseRecipientAdapter) getAdapter(); RecipientAlternatesAdapter.getMatchingRecipients(getContext(), addresses, - ((BaseRecipientAdapter) getAdapter()).getAccount(), + adapter.getQueryType(), adapter.getAccount(), new RecipientMatchCallback() { @Override @@ -2634,9 +2632,10 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements .getContactId()) && getSpannable().getSpanStart(temp) != -1) { // Replace this. - RecipientEntry entry = createValidatedEntry(entries - .get(tokenizeAddress(temp.getEntry().getDestination()) - .toLowerCase())); + String normalized = normalizeAddress( + temp.getEntry().getDestination()); + RecipientEntry entry = createValidatedEntry( + entries.get(normalized)); // If we don't have a validated contact // match, just use the // entry as it existed before. -- cgit v1.2.3