Loading java/com/android/dialer/app/DialtactsActivity.java +14 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.SystemClock; import android.os.Trace; import android.provider.CallLog.Calls; import android.provider.ContactsContract.QuickContact; import android.speech.RecognizerIntent; import android.support.annotation.MainThread; import android.support.annotation.NonNull; Loading Loading @@ -59,6 +60,7 @@ import android.view.animation.AnimationUtils; import android.widget.AbsListView.OnScrollListener; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; Loading Loading @@ -101,6 +103,7 @@ import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.contactsfragment.ContactsFragment; import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener; import com.android.dialer.database.Database; import com.android.dialer.database.DialerDatabaseHelper; import com.android.dialer.dialpadview.DialpadFragment; Loading @@ -109,6 +112,7 @@ import com.android.dialer.dialpadview.DialpadFragment.LastOutgoingCallCallback; import com.android.dialer.interactions.PhoneNumberInteraction; import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorCode; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.InteractionEvent; import com.android.dialer.logging.Logger; import com.android.dialer.logging.LoggingBindings; import com.android.dialer.logging.ScreenEvent; Loading Loading @@ -166,7 +170,8 @@ public class DialtactsActivity extends TransactionSafeActivity PhoneNumberInteraction.DisambigDialogDismissedListener, ActivityCompat.OnRequestPermissionsResultCallback, DialpadListener, SearchFragmentListener { SearchFragmentListener, OnContactSelectedListener { public static final boolean DEBUG = false; @VisibleForTesting public static final String TAG_DIALPAD_FRAGMENT = "dialpad"; Loading Loading @@ -1695,6 +1700,14 @@ public class DialtactsActivity extends TransactionSafeActivity return mPreviouslySelectedTabIndex; } @Override public void onContactSelected(ImageView photo, Uri contactUri, long contactId) { Logger.get(this) .logInteraction(InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_CONTACTS_FRAGMENT_ITEM); QuickContact.showQuickContact( this, photo, contactUri, QuickContact.MODE_LARGE, null /* excludeMimes */); } /** Popup menu accessible from the search bar */ protected class OptionsPopupMenu extends PopupMenu { Loading java/com/android/dialer/app/list/DialtactsPagerAdapter.java +1 −3 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.contactsfragment.ContactsFragment; import com.android.dialer.contactsfragment.ContactsFragment.ClickAction; import com.android.dialer.contactsfragment.ContactsFragment.Header; import com.android.dialer.database.CallLogQueryHandler; import com.android.dialer.speeddial.SpeedDialFragment; Loading Loading @@ -108,8 +107,7 @@ public class DialtactsPagerAdapter extends FragmentPagerAdapter { case TAB_INDEX_ALL_CONTACTS: if (useNewContactsTab) { if (contactsFragment == null) { contactsFragment = ContactsFragment.newInstance(Header.ADD_CONTACT, ClickAction.OPEN_CONTACT_CARD); contactsFragment = ContactsFragment.newInstance(Header.ADD_CONTACT); } return contactsFragment; } else { Loading java/com/android/dialer/contactsfragment/ContactViewHolder.java +9 −22 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.dialer.contactsfragment; import android.content.Context; import android.net.Uri; import android.provider.ContactsContract.QuickContact; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; Loading @@ -26,7 +25,7 @@ import android.view.View.OnClickListener; import android.widget.QuickContactBadge; import android.widget.TextView; import com.android.dialer.common.Assert; import com.android.dialer.contactsfragment.ContactsFragment.ClickAction; import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener; import com.android.dialer.logging.InteractionEvent; import com.android.dialer.logging.Logger; Loading @@ -37,20 +36,20 @@ final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClick private final TextView name; private final QuickContactBadge photo; private final Context context; private final @ClickAction int clickAction; private final OnContactSelectedListener onContactSelectedListener; private String headerText; private Uri contactUri; private long contactId; ContactViewHolder(View itemView, @ClickAction int clickAction) { ContactViewHolder(View itemView, OnContactSelectedListener onContactSelectedListener) { super(itemView); Assert.checkArgument(clickAction != ClickAction.INVALID, "Invalid click action."); this.onContactSelectedListener = Assert.isNotNull(onContactSelectedListener); context = itemView.getContext(); itemView.findViewById(R.id.click_target).setOnClickListener(this); header = itemView.findViewById(R.id.header); name = itemView.findViewById(R.id.contact_name); photo = itemView.findViewById(R.id.photo); this.clickAction = clickAction; } /** Loading @@ -61,9 +60,11 @@ final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClick * @param contactUri to be shown by the contact card on photo click. * @param showHeader if header view should be shown {@code True}, {@code False} otherwise. */ public void bind(String headerText, String displayName, Uri contactUri, boolean showHeader) { public void bind( String headerText, String displayName, Uri contactUri, long contactId, boolean showHeader) { Assert.checkArgument(!TextUtils.isEmpty(displayName)); this.contactUri = contactUri; this.contactId = contactId; this.headerText = headerText; name.setText(displayName); Loading @@ -89,20 +90,6 @@ final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClick @Override public void onClick(View v) { switch (clickAction) { case ClickAction.OPEN_CONTACT_CARD: Logger.get(context) .logInteraction(InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_CONTACTS_FRAGMENT_ITEM); QuickContact.showQuickContact( photo.getContext(), photo, contactUri, QuickContact.MODE_LARGE, null /* excludeMimes */); break; case ClickAction.INVALID: default: throw Assert.createIllegalStateFailException("Invalid click action."); } onContactSelectedListener.onContactSelected(photo, contactUri, contactId); } } java/com/android/dialer/contactsfragment/ContactsAdapter.java +13 −7 Original line number Diff line number Diff line Loading @@ -29,8 +29,8 @@ import android.view.ViewGroup; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.contactphoto.ContactPhotoManager; import com.android.dialer.contactsfragment.ContactsFragment.ClickAction; import com.android.dialer.contactsfragment.ContactsFragment.Header; import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener; import com.android.dialer.lettertile.LetterTileDrawable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading @@ -50,7 +50,7 @@ final class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder private final ArrayMap<ContactViewHolder, Integer> holderMap = new ArrayMap<>(); private final Context context; private final @Header int header; private final @ClickAction int clickAction; private final OnContactSelectedListener onContactSelectedListener; // List of contact sublist headers private String[] headers = new String[0]; Loading @@ -59,10 +59,11 @@ final class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder // Cursor with list of contacts private Cursor cursor; ContactsAdapter(Context context, @Header int header, @ClickAction int clickAction) { ContactsAdapter( Context context, @Header int header, OnContactSelectedListener onContactSelectedListener) { this.context = context; this.header = header; this.clickAction = clickAction; this.onContactSelectedListener = Assert.isNotNull(onContactSelectedListener); } void updateCursor(Cursor cursor) { Loading Loading @@ -92,7 +93,8 @@ final class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder LayoutInflater.from(context).inflate(R.layout.add_contact_row, parent, false)); case CONTACT_VIEW_TYPE: return new ContactViewHolder( LayoutInflater.from(context).inflate(R.layout.contact_row, parent, false), clickAction); LayoutInflater.from(context).inflate(R.layout.contact_row, parent, false), onContactSelectedListener); case UNKNOWN_VIEW_TYPE: default: throw Assert.createIllegalStateFailException("Invalid view type: " + viewType); Loading Loading @@ -133,7 +135,7 @@ final class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder // it to the previous element and only show the anchored header if the row elements fall into // the same sublists. boolean showHeader = position == 0 || !header.equals(getHeaderString(position - 1)); contactViewHolder.bind(header, name, contactUri, showHeader); contactViewHolder.bind(header, name, contactUri, getContactId(cursor), showHeader); } /** Loading Loading @@ -190,11 +192,15 @@ final class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder } private static Uri getContactUri(Cursor cursor) { long contactId = cursor.getLong(ContactsCursorLoader.CONTACT_ID); long contactId = getContactId(cursor); String lookupKey = cursor.getString(ContactsCursorLoader.CONTACT_LOOKUP_KEY); return Contacts.getLookupUri(contactId, lookupKey); } private static long getContactId(Cursor cursor) { return cursor.getLong(ContactsCursorLoader.CONTACT_ID); } String getHeaderString(int position) { if (header != Header.NONE) { if (position == 0) { Loading java/com/android/dialer/contactsfragment/ContactsCursorLoader.java +43 −14 Original line number Diff line number Diff line Loading @@ -18,7 +18,10 @@ package com.android.dialer.contactsfragment; import android.content.Context; import android.content.CursorLoader; import android.net.Uri; import android.provider.ContactsContract.Contacts; import android.text.TextUtils; import com.android.contacts.common.preference.ContactsPreferences; /** Cursor Loader for {@link ContactsFragment}. */ final class ContactsCursorLoader extends CursorLoader { Loading Loading @@ -47,26 +50,52 @@ final class ContactsCursorLoader extends CursorLoader { Contacts.LOOKUP_KEY, // 4 }; private ContactsCursorLoader(Context context, String[] contactProjection, String sortKey) { ContactsCursorLoader(Context context, boolean hasPhoneNumbers) { super( context, Contacts.CONTENT_URI .buildUpon() .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true") .build(), contactProjection, contactProjection[CONTACT_DISPLAY_NAME] + " IS NOT NULL", buildUri(""), getProjection(context), getWhere(context, hasPhoneNumbers), null, sortKey + " ASC"); getSortKey(context) + " ASC"); } public static ContactsCursorLoader createInstanceDisplayNamePrimary( Context context, String sortKey) { return new ContactsCursorLoader(context, CONTACTS_PROJECTION_DISPLAY_NAME_PRIMARY, sortKey); private static String[] getProjection(Context context) { ContactsPreferences contactsPrefs = new ContactsPreferences(context); boolean displayOrderPrimary = (contactsPrefs.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY); return displayOrderPrimary ? CONTACTS_PROJECTION_DISPLAY_NAME_PRIMARY : CONTACTS_PROJECTION_DISPLAY_NAME_ALTERNATIVE; } public static ContactsCursorLoader createInstanceDisplayNameAlternative( Context context, String sortKey) { return new ContactsCursorLoader(context, CONTACTS_PROJECTION_DISPLAY_NAME_ALTERNATIVE, sortKey); private static String getWhere(Context context, boolean hasPhoneNumbers) { String where = getProjection(context)[CONTACT_DISPLAY_NAME] + " IS NOT NULL"; if (hasPhoneNumbers) { where += " AND " + Contacts.HAS_PHONE_NUMBER + "=1"; } return where; } private static String getSortKey(Context context) { ContactsPreferences contactsPrefs = new ContactsPreferences(context); boolean sortOrderPrimary = (contactsPrefs.getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY); return sortOrderPrimary ? Contacts.SORT_KEY_PRIMARY : Contacts.SORT_KEY_ALTERNATIVE; } /** Update cursor loader to filter contacts based on the provided query. */ public void setQuery(String query) { setUri(buildUri(query)); } private static Uri buildUri(String query) { Uri.Builder baseUri; if (TextUtils.isEmpty(query)) { baseUri = Contacts.CONTENT_URI.buildUpon(); } else { baseUri = Contacts.CONTENT_FILTER_URI.buildUpon().appendPath(query); } return baseUri.appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true").build(); } } Loading
java/com/android/dialer/app/DialtactsActivity.java +14 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.SystemClock; import android.os.Trace; import android.provider.CallLog.Calls; import android.provider.ContactsContract.QuickContact; import android.speech.RecognizerIntent; import android.support.annotation.MainThread; import android.support.annotation.NonNull; Loading Loading @@ -59,6 +60,7 @@ import android.view.animation.AnimationUtils; import android.widget.AbsListView.OnScrollListener; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; Loading Loading @@ -101,6 +103,7 @@ import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.contactsfragment.ContactsFragment; import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener; import com.android.dialer.database.Database; import com.android.dialer.database.DialerDatabaseHelper; import com.android.dialer.dialpadview.DialpadFragment; Loading @@ -109,6 +112,7 @@ import com.android.dialer.dialpadview.DialpadFragment.LastOutgoingCallCallback; import com.android.dialer.interactions.PhoneNumberInteraction; import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorCode; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.InteractionEvent; import com.android.dialer.logging.Logger; import com.android.dialer.logging.LoggingBindings; import com.android.dialer.logging.ScreenEvent; Loading Loading @@ -166,7 +170,8 @@ public class DialtactsActivity extends TransactionSafeActivity PhoneNumberInteraction.DisambigDialogDismissedListener, ActivityCompat.OnRequestPermissionsResultCallback, DialpadListener, SearchFragmentListener { SearchFragmentListener, OnContactSelectedListener { public static final boolean DEBUG = false; @VisibleForTesting public static final String TAG_DIALPAD_FRAGMENT = "dialpad"; Loading Loading @@ -1695,6 +1700,14 @@ public class DialtactsActivity extends TransactionSafeActivity return mPreviouslySelectedTabIndex; } @Override public void onContactSelected(ImageView photo, Uri contactUri, long contactId) { Logger.get(this) .logInteraction(InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_CONTACTS_FRAGMENT_ITEM); QuickContact.showQuickContact( this, photo, contactUri, QuickContact.MODE_LARGE, null /* excludeMimes */); } /** Popup menu accessible from the search bar */ protected class OptionsPopupMenu extends PopupMenu { Loading
java/com/android/dialer/app/list/DialtactsPagerAdapter.java +1 −3 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.contactsfragment.ContactsFragment; import com.android.dialer.contactsfragment.ContactsFragment.ClickAction; import com.android.dialer.contactsfragment.ContactsFragment.Header; import com.android.dialer.database.CallLogQueryHandler; import com.android.dialer.speeddial.SpeedDialFragment; Loading Loading @@ -108,8 +107,7 @@ public class DialtactsPagerAdapter extends FragmentPagerAdapter { case TAB_INDEX_ALL_CONTACTS: if (useNewContactsTab) { if (contactsFragment == null) { contactsFragment = ContactsFragment.newInstance(Header.ADD_CONTACT, ClickAction.OPEN_CONTACT_CARD); contactsFragment = ContactsFragment.newInstance(Header.ADD_CONTACT); } return contactsFragment; } else { Loading
java/com/android/dialer/contactsfragment/ContactViewHolder.java +9 −22 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.dialer.contactsfragment; import android.content.Context; import android.net.Uri; import android.provider.ContactsContract.QuickContact; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; Loading @@ -26,7 +25,7 @@ import android.view.View.OnClickListener; import android.widget.QuickContactBadge; import android.widget.TextView; import com.android.dialer.common.Assert; import com.android.dialer.contactsfragment.ContactsFragment.ClickAction; import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener; import com.android.dialer.logging.InteractionEvent; import com.android.dialer.logging.Logger; Loading @@ -37,20 +36,20 @@ final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClick private final TextView name; private final QuickContactBadge photo; private final Context context; private final @ClickAction int clickAction; private final OnContactSelectedListener onContactSelectedListener; private String headerText; private Uri contactUri; private long contactId; ContactViewHolder(View itemView, @ClickAction int clickAction) { ContactViewHolder(View itemView, OnContactSelectedListener onContactSelectedListener) { super(itemView); Assert.checkArgument(clickAction != ClickAction.INVALID, "Invalid click action."); this.onContactSelectedListener = Assert.isNotNull(onContactSelectedListener); context = itemView.getContext(); itemView.findViewById(R.id.click_target).setOnClickListener(this); header = itemView.findViewById(R.id.header); name = itemView.findViewById(R.id.contact_name); photo = itemView.findViewById(R.id.photo); this.clickAction = clickAction; } /** Loading @@ -61,9 +60,11 @@ final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClick * @param contactUri to be shown by the contact card on photo click. * @param showHeader if header view should be shown {@code True}, {@code False} otherwise. */ public void bind(String headerText, String displayName, Uri contactUri, boolean showHeader) { public void bind( String headerText, String displayName, Uri contactUri, long contactId, boolean showHeader) { Assert.checkArgument(!TextUtils.isEmpty(displayName)); this.contactUri = contactUri; this.contactId = contactId; this.headerText = headerText; name.setText(displayName); Loading @@ -89,20 +90,6 @@ final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClick @Override public void onClick(View v) { switch (clickAction) { case ClickAction.OPEN_CONTACT_CARD: Logger.get(context) .logInteraction(InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_CONTACTS_FRAGMENT_ITEM); QuickContact.showQuickContact( photo.getContext(), photo, contactUri, QuickContact.MODE_LARGE, null /* excludeMimes */); break; case ClickAction.INVALID: default: throw Assert.createIllegalStateFailException("Invalid click action."); } onContactSelectedListener.onContactSelected(photo, contactUri, contactId); } }
java/com/android/dialer/contactsfragment/ContactsAdapter.java +13 −7 Original line number Diff line number Diff line Loading @@ -29,8 +29,8 @@ import android.view.ViewGroup; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.contactphoto.ContactPhotoManager; import com.android.dialer.contactsfragment.ContactsFragment.ClickAction; import com.android.dialer.contactsfragment.ContactsFragment.Header; import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener; import com.android.dialer.lettertile.LetterTileDrawable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading @@ -50,7 +50,7 @@ final class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder private final ArrayMap<ContactViewHolder, Integer> holderMap = new ArrayMap<>(); private final Context context; private final @Header int header; private final @ClickAction int clickAction; private final OnContactSelectedListener onContactSelectedListener; // List of contact sublist headers private String[] headers = new String[0]; Loading @@ -59,10 +59,11 @@ final class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder // Cursor with list of contacts private Cursor cursor; ContactsAdapter(Context context, @Header int header, @ClickAction int clickAction) { ContactsAdapter( Context context, @Header int header, OnContactSelectedListener onContactSelectedListener) { this.context = context; this.header = header; this.clickAction = clickAction; this.onContactSelectedListener = Assert.isNotNull(onContactSelectedListener); } void updateCursor(Cursor cursor) { Loading Loading @@ -92,7 +93,8 @@ final class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder LayoutInflater.from(context).inflate(R.layout.add_contact_row, parent, false)); case CONTACT_VIEW_TYPE: return new ContactViewHolder( LayoutInflater.from(context).inflate(R.layout.contact_row, parent, false), clickAction); LayoutInflater.from(context).inflate(R.layout.contact_row, parent, false), onContactSelectedListener); case UNKNOWN_VIEW_TYPE: default: throw Assert.createIllegalStateFailException("Invalid view type: " + viewType); Loading Loading @@ -133,7 +135,7 @@ final class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder // it to the previous element and only show the anchored header if the row elements fall into // the same sublists. boolean showHeader = position == 0 || !header.equals(getHeaderString(position - 1)); contactViewHolder.bind(header, name, contactUri, showHeader); contactViewHolder.bind(header, name, contactUri, getContactId(cursor), showHeader); } /** Loading Loading @@ -190,11 +192,15 @@ final class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder } private static Uri getContactUri(Cursor cursor) { long contactId = cursor.getLong(ContactsCursorLoader.CONTACT_ID); long contactId = getContactId(cursor); String lookupKey = cursor.getString(ContactsCursorLoader.CONTACT_LOOKUP_KEY); return Contacts.getLookupUri(contactId, lookupKey); } private static long getContactId(Cursor cursor) { return cursor.getLong(ContactsCursorLoader.CONTACT_ID); } String getHeaderString(int position) { if (header != Header.NONE) { if (position == 0) { Loading
java/com/android/dialer/contactsfragment/ContactsCursorLoader.java +43 −14 Original line number Diff line number Diff line Loading @@ -18,7 +18,10 @@ package com.android.dialer.contactsfragment; import android.content.Context; import android.content.CursorLoader; import android.net.Uri; import android.provider.ContactsContract.Contacts; import android.text.TextUtils; import com.android.contacts.common.preference.ContactsPreferences; /** Cursor Loader for {@link ContactsFragment}. */ final class ContactsCursorLoader extends CursorLoader { Loading Loading @@ -47,26 +50,52 @@ final class ContactsCursorLoader extends CursorLoader { Contacts.LOOKUP_KEY, // 4 }; private ContactsCursorLoader(Context context, String[] contactProjection, String sortKey) { ContactsCursorLoader(Context context, boolean hasPhoneNumbers) { super( context, Contacts.CONTENT_URI .buildUpon() .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true") .build(), contactProjection, contactProjection[CONTACT_DISPLAY_NAME] + " IS NOT NULL", buildUri(""), getProjection(context), getWhere(context, hasPhoneNumbers), null, sortKey + " ASC"); getSortKey(context) + " ASC"); } public static ContactsCursorLoader createInstanceDisplayNamePrimary( Context context, String sortKey) { return new ContactsCursorLoader(context, CONTACTS_PROJECTION_DISPLAY_NAME_PRIMARY, sortKey); private static String[] getProjection(Context context) { ContactsPreferences contactsPrefs = new ContactsPreferences(context); boolean displayOrderPrimary = (contactsPrefs.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY); return displayOrderPrimary ? CONTACTS_PROJECTION_DISPLAY_NAME_PRIMARY : CONTACTS_PROJECTION_DISPLAY_NAME_ALTERNATIVE; } public static ContactsCursorLoader createInstanceDisplayNameAlternative( Context context, String sortKey) { return new ContactsCursorLoader(context, CONTACTS_PROJECTION_DISPLAY_NAME_ALTERNATIVE, sortKey); private static String getWhere(Context context, boolean hasPhoneNumbers) { String where = getProjection(context)[CONTACT_DISPLAY_NAME] + " IS NOT NULL"; if (hasPhoneNumbers) { where += " AND " + Contacts.HAS_PHONE_NUMBER + "=1"; } return where; } private static String getSortKey(Context context) { ContactsPreferences contactsPrefs = new ContactsPreferences(context); boolean sortOrderPrimary = (contactsPrefs.getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY); return sortOrderPrimary ? Contacts.SORT_KEY_PRIMARY : Contacts.SORT_KEY_ALTERNATIVE; } /** Update cursor loader to filter contacts based on the provided query. */ public void setQuery(String query) { setUri(buildUri(query)); } private static Uri buildUri(String query) { Uri.Builder baseUri; if (TextUtils.isEmpty(query)) { baseUri = Contacts.CONTENT_URI.buildUpon(); } else { baseUri = Contacts.CONTENT_FILTER_URI.buildUpon().appendPath(query); } return baseUri.appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true").build(); } }