From 8d272bb15d3bb20b541da9f675bc5738cdfc2484 Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Mon, 20 Nov 2017 10:40:49 -0800 Subject: Search now supports alternative sort and display orders for contact names. This means that names like "Bob Dylan" can be displayed as "Dylan, Bob" and the names are now able to be sorted by last name as well. This change also adds content descriptions to search icon for a11y. Bug: 68293751 Test: NewSearchFragmentTest PiperOrigin-RevId: 176382228 Change-Id: I5b2b0f3f3f1e2f23ea6b745fd809adfb0ba6242c --- .../dialer/searchfragment/common/Projections.java | 31 +++++++++++++++++++--- .../searchfragment/cp2/ContactFilterCursor.java | 20 +++++++++----- .../cp2/SearchContactViewHolder.java | 4 +++ .../cp2/SearchContactsCursorLoader.java | 9 +++++++ 4 files changed, 54 insertions(+), 10 deletions(-) (limited to 'java/com/android/dialer/searchfragment') diff --git a/java/com/android/dialer/searchfragment/common/Projections.java b/java/com/android/dialer/searchfragment/common/Projections.java index 63fac4ca0..cebe5c9a9 100644 --- a/java/com/android/dialer/searchfragment/common/Projections.java +++ b/java/com/android/dialer/searchfragment/common/Projections.java @@ -39,8 +39,10 @@ public class Projections { @SuppressWarnings("unused") public static final int SORT_KEY = 11; - public static final int COMPANY_NAME = 12; - public static final int NICKNAME = 13; + public static final int SORT_ALTERNATIVE = 12; + + public static final int COMPANY_NAME = 13; + public static final int NICKNAME = 14; public static final String[] CP2_PROJECTION = new String[] { @@ -56,8 +58,29 @@ public class Projections { Data.CONTACT_ID, // 9 Data.MIMETYPE, // 10 Data.SORT_KEY_PRIMARY, // 11 - Organization.COMPANY, // 12 - Nickname.NAME // 13 + Data.SORT_KEY_ALTERNATIVE, // 12 + Organization.COMPANY, // 13 + Nickname.NAME // 14 + }; + + // Uses alternative display names (i.e. "Bob Dylan" becomes "Dylan, Bob"). + public static final String[] CP2_PROJECTION_ALTERNATIVE = + new String[] { + Data._ID, // 0 + Phone.TYPE, // 1 + Phone.LABEL, // 2 + Phone.NUMBER, // 3 + Data.DISPLAY_NAME_ALTERNATIVE, // 4 + Data.PHOTO_ID, // 5 + Data.PHOTO_THUMBNAIL_URI, // 6 + Data.LOOKUP_KEY, // 7 + Data.CARRIER_PRESENCE, // 8 + Data.CONTACT_ID, // 9 + Data.MIMETYPE, // 10 + Data.SORT_KEY_PRIMARY, // 11 + Data.SORT_KEY_ALTERNATIVE, // 12 + Organization.COMPANY, // 13 + Nickname.NAME // 14 }; public static final String[] DATA_PROJECTION = diff --git a/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java b/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java index dc16f9dd0..23c0d6e6d 100644 --- a/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java +++ b/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java @@ -32,6 +32,7 @@ import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.support.v4.util.ArraySet; import android.text.TextUtils; +import android.util.ArrayMap; import com.android.dialer.searchfragment.common.Projections; import com.android.dialer.searchfragment.common.QueryFilteringUtil; import java.lang.annotation.Retention; @@ -40,6 +41,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; /** @@ -108,25 +110,24 @@ final class ContactFilterCursor implements Cursor { private static Cursor createCursor(Cursor cursor) { // Convert cursor rows into Cp2Contacts List cp2Contacts = new ArrayList<>(); - Set contactIds = new ArraySet<>(); + Map contactIdsToPosition = new ArrayMap<>(); cursor.moveToPosition(-1); while (cursor.moveToNext()) { Cp2Contact contact = Cp2Contact.fromCursor(cursor); cp2Contacts.add(contact); - contactIds.add(contact.contactId()); + contactIdsToPosition.put(contact.contactId(), cursor.getPosition()); } cursor.close(); // Group then combine contact data List coalescedContacts = new ArrayList<>(); - for (Integer contactId : contactIds) { + for (Integer contactId : contactIdsToPosition.keySet()) { List duplicateContacts = getAllContactsWithContactId(contactId, cp2Contacts); coalescedContacts.addAll(coalesceContacts(duplicateContacts)); } - // Sort by display name, then build new cursor from coalesced contacts. - // We sort the contacts so that they are displayed to the user in lexicographic order. - Collections.sort(coalescedContacts, (o1, o2) -> o1.displayName().compareTo(o2.displayName())); + // Sort the contacts back into the exact same order they were inside of {@code cursor} + Collections.sort(coalescedContacts, (o1, o2) -> compare(contactIdsToPosition, o1, o2)); MatrixCursor newCursor = new MatrixCursor(Projections.CP2_PROJECTION, coalescedContacts.size()); for (Cp2Contact contact : coalescedContacts) { newCursor.addRow(contact.toCursorRow()); @@ -166,6 +167,13 @@ final class ContactFilterCursor implements Cursor { return coalescedContacts; } + private static int compare( + Map contactIdsToPosition, Cp2Contact o1, Cp2Contact o2) { + int position1 = contactIdsToPosition.get(o1.contactId()); + int position2 = contactIdsToPosition.get(o2.contactId()); + return Integer.compare(position1, position2); + } + private static void removeDuplicatePhoneNumbers(List phoneContacts) { for (int i = 0; i < phoneContacts.size(); i++) { Cp2Contact contact1 = phoneContacts.get(i); diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java b/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java index 386ab3a6b..e36df4bf7 100644 --- a/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java +++ b/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java @@ -171,6 +171,8 @@ public final class SearchContactViewHolder extends ViewHolder implements OnClick callToActionView.setVisibility(View.VISIBLE); callToActionView.setImageDrawable( context.getDrawable(com.android.contacts.common.R.drawable.ic_phone_attach)); + callToActionView.setContentDescription( + context.getString(R.string.description_search_call_and_share)); callToActionView.setOnClickListener(this); break; case CallToAction.DUO_CALL: @@ -178,6 +180,8 @@ public final class SearchContactViewHolder extends ViewHolder implements OnClick callToActionView.setVisibility(View.VISIBLE); callToActionView.setImageDrawable( context.getDrawable(R.drawable.quantum_ic_videocam_white_24)); + callToActionView.setContentDescription( + context.getString(R.string.description_search_video_call)); callToActionView.setOnClickListener(this); break; default: diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java index 2b7af1131..7624bc712 100644 --- a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java +++ b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java @@ -24,6 +24,7 @@ import android.provider.ContactsContract.CommonDataKinds.Organization; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Data; import android.support.annotation.Nullable; +import com.android.contacts.common.preference.ContactsPreferences; import com.android.dialer.searchfragment.common.Projections; /** Cursor Loader for CP2 contacts. */ @@ -41,6 +42,14 @@ public final class SearchContactsCursorLoader extends CursorLoader { null, Phone.SORT_KEY_PRIMARY + " ASC"); this.query = query; + + ContactsPreferences preferences = new ContactsPreferences(getContext()); + if (preferences.getSortOrder() == ContactsPreferences.SORT_ORDER_ALTERNATIVE) { + setSortOrder(Phone.SORT_KEY_ALTERNATIVE + " ASC"); + } + if (preferences.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE) { + setProjection(Projections.CP2_PROJECTION_ALTERNATIVE); + } } /** -- cgit v1.2.3