Loading src/com/android/contacts/common/list/ContactListAdapter.java +63 −16 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.database.Cursor; import android.net.Uri; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.CommonDataKinds.Email; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Directory; import android.provider.ContactsContract.SearchSnippets; import android.text.TextUtils; Loading @@ -27,9 +29,12 @@ import android.view.ViewGroup; import android.widget.ListView; import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest; import com.android.contacts.common.Experiments; import com.android.contacts.common.R; import com.android.contacts.common.compat.ContactsCompat; import com.android.contacts.common.preference.ContactsPreferences; import com.android.contacts.common.util.ContactDisplayUtils; import com.android.contacts.commonbind.experiments.Flags; /** * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type. Loading Loading @@ -107,8 +112,8 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter { public static final int CONTACT_SNIPPET = 11; } // NOTE: These projections must match those in ContactQuery above expect we omit the // SearchSnippers.SNIPPET column since that is only supported with Contacts.CONTENT_FILTER_URI. // The projection columns should match those in ContactQuery above expect we must omit the // columns which are not supported protected static class ExperimentQuery { private static final String[] FILTER_PROJECTION_PRIMARY = new String[] { Loading @@ -123,7 +128,7 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter { Contacts.PHONETIC_NAME, // 8 Contacts.TIMES_CONTACTED, // 9 Contacts.STARRED, // 10 // SearchSnippets.SNIPPET not supported // SearchSnippets.SNIPPET not supported for Contacts.CONTENT_URI }; private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] { Loading @@ -138,21 +143,48 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter { Contacts.PHONETIC_NAME, // 8 Contacts.TIMES_CONTACTED, // 9 Contacts.STARRED, // 10 // SearchSnippets.SNIPPET not supported // SearchSnippets.SNIPPET not supported for Contacts.CONTENT_URI }; public static final int CONTACT_ID = 0; public static final int CONTACT_DISPLAY_NAME = 1; public static final int CONTACT_PRESENCE_STATUS = 2; public static final int CONTACT_CONTACT_STATUS = 3; public static final int CONTACT_PHOTO_ID = 4; public static final int CONTACT_PHOTO_URI = 5; public static final int CONTACT_LOOKUP_KEY = 6; public static final int CONTACT_IS_USER_PROFILE = 7; public static final int CONTACT_PHONETIC_NAME = 8; public static final int CONTACT_TIMES_CONTACTED = 9; public static final int CONTACT_STARRED = 10; // SearchSnippets.SNIPPET not supported public static final String[] FILTER_PROJECTION_PRIMARY_EMAIL = new String[] { Contacts._ID, // 0 Contacts.DISPLAY_NAME_PRIMARY, // 1 Contacts.CONTACT_PRESENCE, // 2 Contacts.CONTACT_STATUS, // 3 Contacts.PHOTO_ID, // 4 Contacts.PHOTO_THUMBNAIL_URI, // 5 Contacts.LOOKUP_KEY, // 6 // Contacts.IS_USER_PROFILE not supported for Data.CONTENT_URI Contacts.IN_VISIBLE_GROUP, // 7 Contacts.PHONETIC_NAME, // 8 Contacts.TIMES_CONTACTED, // 9 Contacts.STARRED, // 10 // SearchSnippets.SNIPPET not supported for Data.CONTENT_URI Email.ADDRESS, // 11 }; public static final int EMAIL_ADDRESS = 11; public static final String[] FILTER_PROJECTION_PRIMARY_PHONE = new String[] { Contacts._ID, // 0 Contacts.DISPLAY_NAME_PRIMARY, // 1 Contacts.CONTACT_PRESENCE, // 2 Contacts.CONTACT_STATUS, // 3 Contacts.PHOTO_ID, // 4 Contacts.PHOTO_THUMBNAIL_URI, // 5 Contacts.LOOKUP_KEY, // 6 // Contacts.IS_USER_PROFILE not supported for Data.CONTENT_URI Contacts.IN_VISIBLE_GROUP, // 7 Contacts.PHONETIC_NAME, // 8 Contacts.TIMES_CONTACTED, // 9 Contacts.STARRED, // 10 // SearchSnippets.SNIPPET not supported for Data.CONTENT_URI Phone.NUMBER, // 11 Phone.NORMALIZED_NUMBER, // 12 }; public static final int NUMBER = 11; public static final int NORMAILIZED_NUMBER = 12; } private CharSequence mUnknownNameText; Loading Loading @@ -328,6 +360,21 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter { } protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) { if (Flags.getInstance(mContext).getBoolean( Experiments.FLAG_SEARCH_DISPLAY_NAME_QUERY, false)) { final String queryString = getQueryString(); if (ContactDisplayUtils.isPossiblePhoneNumber(queryString) && cursor.getColumnCount() > ExperimentQuery.NUMBER && Phone.NUMBER.equals(cursor.getColumnName(ExperimentQuery.NUMBER))) { view.showSnippet(cursor, queryString, ExperimentQuery.NUMBER); return; } if (cursor.getColumnCount() > ExperimentQuery.EMAIL_ADDRESS && Email.ADDRESS.equals(cursor.getColumnName(ExperimentQuery.EMAIL_ADDRESS))) { view.showSnippet(cursor, queryString, ExperimentQuery.EMAIL_ADDRESS); return; } } view.showSnippet(cursor, ContactQuery.CONTACT_SNIPPET); } Loading src/com/android/contacts/common/list/ContactListItemView.java +26 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import android.text.SpannableString; import android.text.TextUtils; import android.text.TextUtils.TruncateAt; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; Loading @@ -56,6 +55,7 @@ import com.android.contacts.common.R; import com.android.contacts.common.compat.CompatUtils; import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.contacts.common.format.TextHighlighter; import com.android.contacts.common.list.ContactListAdapter.ExperimentQuery; import com.android.contacts.common.util.ContactDisplayUtils; import com.android.contacts.common.util.SearchUtil; import com.android.contacts.common.util.ViewUtil; Loading Loading @@ -1478,6 +1478,31 @@ public class ContactListItemView extends ViewGroup setStatus(statusMessage); } /** * Shows search snippet for email and phone number matches. */ public void showSnippet(Cursor cursor, String query, int snippetColumn) { // TODO: this does not properly handle phone numbers with control characters // For example if the phone number is 444-5555, the search query 4445 will match the // number since we normalize it before querying CP2 but the snippet will fail since // the portion to be highlighted is 444-5 not 4445. final String snippet = cursor.getString(snippetColumn); if (snippet == null) { setSnippet(null); return; } final String displayName = cursor.getColumnIndex(Contacts.DISPLAY_NAME) >= 0 ? cursor.getString(cursor.getColumnIndex(Contacts.DISPLAY_NAME)) : null; if (snippet.equals(displayName)) { // If the snippet exactly matches the display name (i.e. the phone number or email // address is being used as the display name) then no snippet is necessary setSnippet(null); return; } // Show the snippet with the part of the query that matched it setSnippet(updateSnippet(snippet, query, displayName)); } /** * Shows search snippet. */ Loading src/com/android/contacts/common/list/DefaultContactListAdapter.java +36 −7 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ import android.net.Uri.Builder; import android.preference.PreferenceManager; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Data; import android.provider.ContactsContract.CommonDataKinds.Email; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Directory; import android.provider.ContactsContract.SearchSnippets; import android.support.annotation.VisibleForTesting; Loading @@ -33,7 +36,9 @@ import android.view.View; import com.android.contacts.common.Experiments; import com.android.contacts.common.compat.ContactsCompat; import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.contacts.common.preference.ContactsPreferences; import com.android.contacts.common.util.ContactDisplayUtils; import com.android.contacts.commonbind.experiments.Flags; import java.util.ArrayList; Loading Loading @@ -71,10 +76,10 @@ public class DefaultContactListAdapter extends ContactListAdapter { loader.setSelection("0"); } else if (flags.getBoolean(Experiments.FLAG_SEARCH_DISPLAY_NAME_QUERY, false) && directoryId == Directory.DEFAULT) { // Configure the loader to match display and phonetic names final String displayNameColumn = getContactNameDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME_ALTERNATIVE; final Builder builder = Contacts.CONTENT_URI.buildUpon(); builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)); Loading @@ -82,6 +87,30 @@ public class DefaultContactListAdapter extends ContactListAdapter { loader.setProjection(getExperimentProjection()); loader.setSelection(getDisplayNameSelection(query, displayNameColumn)); loader.setSelectionArgs(getDisplayNameSelectionArgs(query)); // Configure an extra query to show email and phone number matches and merge // them in after the display name loader query result. final ProfileAndContactsLoader profileAndContactsLoader = (ProfileAndContactsLoader) loader; final Builder extraBuilder = Data.CONTENT_URI.buildUpon(); if (ContactDisplayUtils.isPossiblePhoneNumber(query)) { final String normalizedQuery = PhoneNumberUtilsCompat.normalizeNumber(query); profileAndContactsLoader.setLoadExtraContactsLast( extraBuilder.build(), ExperimentQuery.FILTER_PROJECTION_PRIMARY_PHONE, Data.MIMETYPE + "=? AND " + Phone.NORMALIZED_NUMBER + " LIKE ? AND " + Contacts.IN_VISIBLE_GROUP + "=?", new String[]{Phone.CONTENT_ITEM_TYPE, "%" + normalizedQuery + "%", "1"}); } else { final Builder emailBuilder = Data.CONTENT_URI.buildUpon(); profileAndContactsLoader.setLoadExtraContactsLast( emailBuilder.build(), ExperimentQuery.FILTER_PROJECTION_PRIMARY_EMAIL, Data.MIMETYPE + "=? AND " + Email.ADDRESS + " LIKE ? AND " + Contacts.IN_VISIBLE_GROUP + "=?", new String[]{Email.CONTENT_ITEM_TYPE, "%" + query + "%", "1"}); } if (flags.getBoolean(Experiments.FLAG_SEARCH_STREQUENTS_FIRST, false)) { sortOrder = String.format("%s DESC, %s DESC", Contacts.TIMES_CONTACTED, Contacts.STARRED); Loading @@ -97,14 +126,14 @@ public class DefaultContactListAdapter extends ContactListAdapter { loader.setSelection(Contacts.TIMES_CONTACTED + "=0 AND " + Contacts.STARRED + "=0"); // Strequent contacts will be merged back in after the profile (ME) and before // the main loader query results. // Configure an extra query to load strequent contacts and merge them in // before the main loader query results. final ProfileAndContactsLoader profileAndContactsLoader = (ProfileAndContactsLoader) loader; final Builder strequentBuilder = Contacts.CONTENT_STREQUENT_FILTER_URI.buildUpon(); appendSearchParameters(strequentBuilder, query, directoryId); profileAndContactsLoader.setLoadStrequents( profileAndContactsLoader.setLoadExtraContactsFirst( strequentBuilder.build(), getExperimentProjection()); } } Loading Loading @@ -139,7 +168,7 @@ public class DefaultContactListAdapter extends ContactListAdapter { */ @VisibleForTesting static String getDisplayNameSelection(String query, String displayNameColumn) { final String[] tokens = getDisplayNameSearchSelectionTokens(query); final String[] tokens = getDisplayNameSelectionTokens(query); if (tokens == null) return null; final StringBuilder builder = new StringBuilder(); for (int i = 0; i < tokens.length; i++) { Loading @@ -157,7 +186,7 @@ public class DefaultContactListAdapter extends ContactListAdapter { */ @VisibleForTesting static String[] getDisplayNameSelectionArgs(String query) { final String[] tokens = getDisplayNameSearchSelectionTokens(query); final String[] tokens = getDisplayNameSelectionTokens(query); if (tokens == null) return null; for (int i = 0; i < tokens.length; i++) { tokens[i] = "%" + tokens[i] + "%"; Loading @@ -165,7 +194,7 @@ public class DefaultContactListAdapter extends ContactListAdapter { return tokens; } private static String[] getDisplayNameSearchSelectionTokens(String query) { private static String[] getDisplayNameSelectionTokens(String query) { if (query == null) return null; query = query.trim(); if (query.length() == 0) return null; Loading src/com/android/contacts/common/list/ProfileAndContactsLoader.java +32 −12 Original line number Diff line number Diff line Loading @@ -38,13 +38,17 @@ public class ProfileAndContactsLoader extends CursorLoader { private String[] mProjection; private Uri mStrequentUri; private String[] mStrequentProjection; private Uri mExtraUri; private String[] mExtraProjection; private String mExtraSelection; private String[] mExtraSelectionArgs; private boolean mMergeExtraContactsAfterPrimary; public ProfileAndContactsLoader(Context context) { super(context); } /** Whether to load the profile and merge results in before any other results. */ public void setLoadProfile(boolean flag) { mLoadProfile = flag; } Loading @@ -54,9 +58,25 @@ public class ProfileAndContactsLoader extends CursorLoader { mProjection = projection; } public void setLoadStrequents(Uri uri, String[] projection) { mStrequentUri = uri; mStrequentProjection = projection; /** Configure an extra query and merge results in before the primary results. */ public void setLoadExtraContactsFirst(Uri uri, String[] projection) { mExtraUri = uri; mExtraProjection = projection; mMergeExtraContactsAfterPrimary = false; } /** Configure an extra query and merge results in after the primary results. */ public void setLoadExtraContactsLast(Uri uri, String[] projection, String selection, String[] selectionArgs) { mExtraUri = uri; mExtraProjection = projection; mExtraSelection = selection; mExtraSelectionArgs = selectionArgs; mMergeExtraContactsAfterPrimary = true; } private boolean canLoadExtraContacts() { return mExtraUri != null && mExtraProjection != null; } @Override Loading @@ -66,8 +86,8 @@ public class ProfileAndContactsLoader extends CursorLoader { if (mLoadProfile) { cursors.add(loadProfile()); } if (mStrequentUri != null && mStrequentProjection != null) { cursors.add(loadStrequent()); if (canLoadExtraContacts() && !mMergeExtraContactsAfterPrimary) { cursors.add(loadExtraContacts()); } // ContactsCursor.loadInBackground() can return null; MergeCursor // correctly handles null cursors. Loading @@ -79,6 +99,9 @@ public class ProfileAndContactsLoader extends CursorLoader { } final Cursor contactsCursor = cursor; cursors.add(contactsCursor); if (canLoadExtraContacts() && mMergeExtraContactsAfterPrimary) { cursors.add(loadExtraContacts()); } return new MergeCursor(cursors.toArray(new Cursor[cursors.size()])) { @Override public Bundle getExtras() { Loading Loading @@ -115,11 +138,8 @@ public class ProfileAndContactsLoader extends CursorLoader { } } /** * Loads starred and frequently contacted contacts */ private Cursor loadStrequent() { private Cursor loadExtraContacts() { return getContext().getContentResolver().query( mStrequentUri, mStrequentProjection, null, null, null); mExtraUri, mExtraProjection, mExtraSelection, mExtraSelectionArgs, null); } } Loading
src/com/android/contacts/common/list/ContactListAdapter.java +63 −16 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.database.Cursor; import android.net.Uri; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.CommonDataKinds.Email; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Directory; import android.provider.ContactsContract.SearchSnippets; import android.text.TextUtils; Loading @@ -27,9 +29,12 @@ import android.view.ViewGroup; import android.widget.ListView; import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest; import com.android.contacts.common.Experiments; import com.android.contacts.common.R; import com.android.contacts.common.compat.ContactsCompat; import com.android.contacts.common.preference.ContactsPreferences; import com.android.contacts.common.util.ContactDisplayUtils; import com.android.contacts.commonbind.experiments.Flags; /** * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type. Loading Loading @@ -107,8 +112,8 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter { public static final int CONTACT_SNIPPET = 11; } // NOTE: These projections must match those in ContactQuery above expect we omit the // SearchSnippers.SNIPPET column since that is only supported with Contacts.CONTENT_FILTER_URI. // The projection columns should match those in ContactQuery above expect we must omit the // columns which are not supported protected static class ExperimentQuery { private static final String[] FILTER_PROJECTION_PRIMARY = new String[] { Loading @@ -123,7 +128,7 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter { Contacts.PHONETIC_NAME, // 8 Contacts.TIMES_CONTACTED, // 9 Contacts.STARRED, // 10 // SearchSnippets.SNIPPET not supported // SearchSnippets.SNIPPET not supported for Contacts.CONTENT_URI }; private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] { Loading @@ -138,21 +143,48 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter { Contacts.PHONETIC_NAME, // 8 Contacts.TIMES_CONTACTED, // 9 Contacts.STARRED, // 10 // SearchSnippets.SNIPPET not supported // SearchSnippets.SNIPPET not supported for Contacts.CONTENT_URI }; public static final int CONTACT_ID = 0; public static final int CONTACT_DISPLAY_NAME = 1; public static final int CONTACT_PRESENCE_STATUS = 2; public static final int CONTACT_CONTACT_STATUS = 3; public static final int CONTACT_PHOTO_ID = 4; public static final int CONTACT_PHOTO_URI = 5; public static final int CONTACT_LOOKUP_KEY = 6; public static final int CONTACT_IS_USER_PROFILE = 7; public static final int CONTACT_PHONETIC_NAME = 8; public static final int CONTACT_TIMES_CONTACTED = 9; public static final int CONTACT_STARRED = 10; // SearchSnippets.SNIPPET not supported public static final String[] FILTER_PROJECTION_PRIMARY_EMAIL = new String[] { Contacts._ID, // 0 Contacts.DISPLAY_NAME_PRIMARY, // 1 Contacts.CONTACT_PRESENCE, // 2 Contacts.CONTACT_STATUS, // 3 Contacts.PHOTO_ID, // 4 Contacts.PHOTO_THUMBNAIL_URI, // 5 Contacts.LOOKUP_KEY, // 6 // Contacts.IS_USER_PROFILE not supported for Data.CONTENT_URI Contacts.IN_VISIBLE_GROUP, // 7 Contacts.PHONETIC_NAME, // 8 Contacts.TIMES_CONTACTED, // 9 Contacts.STARRED, // 10 // SearchSnippets.SNIPPET not supported for Data.CONTENT_URI Email.ADDRESS, // 11 }; public static final int EMAIL_ADDRESS = 11; public static final String[] FILTER_PROJECTION_PRIMARY_PHONE = new String[] { Contacts._ID, // 0 Contacts.DISPLAY_NAME_PRIMARY, // 1 Contacts.CONTACT_PRESENCE, // 2 Contacts.CONTACT_STATUS, // 3 Contacts.PHOTO_ID, // 4 Contacts.PHOTO_THUMBNAIL_URI, // 5 Contacts.LOOKUP_KEY, // 6 // Contacts.IS_USER_PROFILE not supported for Data.CONTENT_URI Contacts.IN_VISIBLE_GROUP, // 7 Contacts.PHONETIC_NAME, // 8 Contacts.TIMES_CONTACTED, // 9 Contacts.STARRED, // 10 // SearchSnippets.SNIPPET not supported for Data.CONTENT_URI Phone.NUMBER, // 11 Phone.NORMALIZED_NUMBER, // 12 }; public static final int NUMBER = 11; public static final int NORMAILIZED_NUMBER = 12; } private CharSequence mUnknownNameText; Loading Loading @@ -328,6 +360,21 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter { } protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) { if (Flags.getInstance(mContext).getBoolean( Experiments.FLAG_SEARCH_DISPLAY_NAME_QUERY, false)) { final String queryString = getQueryString(); if (ContactDisplayUtils.isPossiblePhoneNumber(queryString) && cursor.getColumnCount() > ExperimentQuery.NUMBER && Phone.NUMBER.equals(cursor.getColumnName(ExperimentQuery.NUMBER))) { view.showSnippet(cursor, queryString, ExperimentQuery.NUMBER); return; } if (cursor.getColumnCount() > ExperimentQuery.EMAIL_ADDRESS && Email.ADDRESS.equals(cursor.getColumnName(ExperimentQuery.EMAIL_ADDRESS))) { view.showSnippet(cursor, queryString, ExperimentQuery.EMAIL_ADDRESS); return; } } view.showSnippet(cursor, ContactQuery.CONTACT_SNIPPET); } Loading
src/com/android/contacts/common/list/ContactListItemView.java +26 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import android.text.SpannableString; import android.text.TextUtils; import android.text.TextUtils.TruncateAt; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; Loading @@ -56,6 +55,7 @@ import com.android.contacts.common.R; import com.android.contacts.common.compat.CompatUtils; import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.contacts.common.format.TextHighlighter; import com.android.contacts.common.list.ContactListAdapter.ExperimentQuery; import com.android.contacts.common.util.ContactDisplayUtils; import com.android.contacts.common.util.SearchUtil; import com.android.contacts.common.util.ViewUtil; Loading Loading @@ -1478,6 +1478,31 @@ public class ContactListItemView extends ViewGroup setStatus(statusMessage); } /** * Shows search snippet for email and phone number matches. */ public void showSnippet(Cursor cursor, String query, int snippetColumn) { // TODO: this does not properly handle phone numbers with control characters // For example if the phone number is 444-5555, the search query 4445 will match the // number since we normalize it before querying CP2 but the snippet will fail since // the portion to be highlighted is 444-5 not 4445. final String snippet = cursor.getString(snippetColumn); if (snippet == null) { setSnippet(null); return; } final String displayName = cursor.getColumnIndex(Contacts.DISPLAY_NAME) >= 0 ? cursor.getString(cursor.getColumnIndex(Contacts.DISPLAY_NAME)) : null; if (snippet.equals(displayName)) { // If the snippet exactly matches the display name (i.e. the phone number or email // address is being used as the display name) then no snippet is necessary setSnippet(null); return; } // Show the snippet with the part of the query that matched it setSnippet(updateSnippet(snippet, query, displayName)); } /** * Shows search snippet. */ Loading
src/com/android/contacts/common/list/DefaultContactListAdapter.java +36 −7 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ import android.net.Uri.Builder; import android.preference.PreferenceManager; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Data; import android.provider.ContactsContract.CommonDataKinds.Email; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Directory; import android.provider.ContactsContract.SearchSnippets; import android.support.annotation.VisibleForTesting; Loading @@ -33,7 +36,9 @@ import android.view.View; import com.android.contacts.common.Experiments; import com.android.contacts.common.compat.ContactsCompat; import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.contacts.common.preference.ContactsPreferences; import com.android.contacts.common.util.ContactDisplayUtils; import com.android.contacts.commonbind.experiments.Flags; import java.util.ArrayList; Loading Loading @@ -71,10 +76,10 @@ public class DefaultContactListAdapter extends ContactListAdapter { loader.setSelection("0"); } else if (flags.getBoolean(Experiments.FLAG_SEARCH_DISPLAY_NAME_QUERY, false) && directoryId == Directory.DEFAULT) { // Configure the loader to match display and phonetic names final String displayNameColumn = getContactNameDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME_ALTERNATIVE; final Builder builder = Contacts.CONTENT_URI.buildUpon(); builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)); Loading @@ -82,6 +87,30 @@ public class DefaultContactListAdapter extends ContactListAdapter { loader.setProjection(getExperimentProjection()); loader.setSelection(getDisplayNameSelection(query, displayNameColumn)); loader.setSelectionArgs(getDisplayNameSelectionArgs(query)); // Configure an extra query to show email and phone number matches and merge // them in after the display name loader query result. final ProfileAndContactsLoader profileAndContactsLoader = (ProfileAndContactsLoader) loader; final Builder extraBuilder = Data.CONTENT_URI.buildUpon(); if (ContactDisplayUtils.isPossiblePhoneNumber(query)) { final String normalizedQuery = PhoneNumberUtilsCompat.normalizeNumber(query); profileAndContactsLoader.setLoadExtraContactsLast( extraBuilder.build(), ExperimentQuery.FILTER_PROJECTION_PRIMARY_PHONE, Data.MIMETYPE + "=? AND " + Phone.NORMALIZED_NUMBER + " LIKE ? AND " + Contacts.IN_VISIBLE_GROUP + "=?", new String[]{Phone.CONTENT_ITEM_TYPE, "%" + normalizedQuery + "%", "1"}); } else { final Builder emailBuilder = Data.CONTENT_URI.buildUpon(); profileAndContactsLoader.setLoadExtraContactsLast( emailBuilder.build(), ExperimentQuery.FILTER_PROJECTION_PRIMARY_EMAIL, Data.MIMETYPE + "=? AND " + Email.ADDRESS + " LIKE ? AND " + Contacts.IN_VISIBLE_GROUP + "=?", new String[]{Email.CONTENT_ITEM_TYPE, "%" + query + "%", "1"}); } if (flags.getBoolean(Experiments.FLAG_SEARCH_STREQUENTS_FIRST, false)) { sortOrder = String.format("%s DESC, %s DESC", Contacts.TIMES_CONTACTED, Contacts.STARRED); Loading @@ -97,14 +126,14 @@ public class DefaultContactListAdapter extends ContactListAdapter { loader.setSelection(Contacts.TIMES_CONTACTED + "=0 AND " + Contacts.STARRED + "=0"); // Strequent contacts will be merged back in after the profile (ME) and before // the main loader query results. // Configure an extra query to load strequent contacts and merge them in // before the main loader query results. final ProfileAndContactsLoader profileAndContactsLoader = (ProfileAndContactsLoader) loader; final Builder strequentBuilder = Contacts.CONTENT_STREQUENT_FILTER_URI.buildUpon(); appendSearchParameters(strequentBuilder, query, directoryId); profileAndContactsLoader.setLoadStrequents( profileAndContactsLoader.setLoadExtraContactsFirst( strequentBuilder.build(), getExperimentProjection()); } } Loading Loading @@ -139,7 +168,7 @@ public class DefaultContactListAdapter extends ContactListAdapter { */ @VisibleForTesting static String getDisplayNameSelection(String query, String displayNameColumn) { final String[] tokens = getDisplayNameSearchSelectionTokens(query); final String[] tokens = getDisplayNameSelectionTokens(query); if (tokens == null) return null; final StringBuilder builder = new StringBuilder(); for (int i = 0; i < tokens.length; i++) { Loading @@ -157,7 +186,7 @@ public class DefaultContactListAdapter extends ContactListAdapter { */ @VisibleForTesting static String[] getDisplayNameSelectionArgs(String query) { final String[] tokens = getDisplayNameSearchSelectionTokens(query); final String[] tokens = getDisplayNameSelectionTokens(query); if (tokens == null) return null; for (int i = 0; i < tokens.length; i++) { tokens[i] = "%" + tokens[i] + "%"; Loading @@ -165,7 +194,7 @@ public class DefaultContactListAdapter extends ContactListAdapter { return tokens; } private static String[] getDisplayNameSearchSelectionTokens(String query) { private static String[] getDisplayNameSelectionTokens(String query) { if (query == null) return null; query = query.trim(); if (query.length() == 0) return null; Loading
src/com/android/contacts/common/list/ProfileAndContactsLoader.java +32 −12 Original line number Diff line number Diff line Loading @@ -38,13 +38,17 @@ public class ProfileAndContactsLoader extends CursorLoader { private String[] mProjection; private Uri mStrequentUri; private String[] mStrequentProjection; private Uri mExtraUri; private String[] mExtraProjection; private String mExtraSelection; private String[] mExtraSelectionArgs; private boolean mMergeExtraContactsAfterPrimary; public ProfileAndContactsLoader(Context context) { super(context); } /** Whether to load the profile and merge results in before any other results. */ public void setLoadProfile(boolean flag) { mLoadProfile = flag; } Loading @@ -54,9 +58,25 @@ public class ProfileAndContactsLoader extends CursorLoader { mProjection = projection; } public void setLoadStrequents(Uri uri, String[] projection) { mStrequentUri = uri; mStrequentProjection = projection; /** Configure an extra query and merge results in before the primary results. */ public void setLoadExtraContactsFirst(Uri uri, String[] projection) { mExtraUri = uri; mExtraProjection = projection; mMergeExtraContactsAfterPrimary = false; } /** Configure an extra query and merge results in after the primary results. */ public void setLoadExtraContactsLast(Uri uri, String[] projection, String selection, String[] selectionArgs) { mExtraUri = uri; mExtraProjection = projection; mExtraSelection = selection; mExtraSelectionArgs = selectionArgs; mMergeExtraContactsAfterPrimary = true; } private boolean canLoadExtraContacts() { return mExtraUri != null && mExtraProjection != null; } @Override Loading @@ -66,8 +86,8 @@ public class ProfileAndContactsLoader extends CursorLoader { if (mLoadProfile) { cursors.add(loadProfile()); } if (mStrequentUri != null && mStrequentProjection != null) { cursors.add(loadStrequent()); if (canLoadExtraContacts() && !mMergeExtraContactsAfterPrimary) { cursors.add(loadExtraContacts()); } // ContactsCursor.loadInBackground() can return null; MergeCursor // correctly handles null cursors. Loading @@ -79,6 +99,9 @@ public class ProfileAndContactsLoader extends CursorLoader { } final Cursor contactsCursor = cursor; cursors.add(contactsCursor); if (canLoadExtraContacts() && mMergeExtraContactsAfterPrimary) { cursors.add(loadExtraContacts()); } return new MergeCursor(cursors.toArray(new Cursor[cursors.size()])) { @Override public Bundle getExtras() { Loading Loading @@ -115,11 +138,8 @@ public class ProfileAndContactsLoader extends CursorLoader { } } /** * Loads starred and frequently contacted contacts */ private Cursor loadStrequent() { private Cursor loadExtraContacts() { return getContext().getContentResolver().query( mStrequentUri, mStrequentProjection, null, null, null); mExtraUri, mExtraProjection, mExtraSelection, mExtraSelectionArgs, null); } }