Item multi select now has defaults checked.
Added ability to send a list of ids to a
multi select picker to precheck defaults.
Defaults will preselect if the aggregate
contact has a single email/phone, or if
there is a super primary set for the contact.
Test: Verified all features are working as intended.
Picker now shows all contact methods for group/selection,
which fixes some strange selection behavior.
Bug: 31648014
Change-Id: I21ee4e79f8c1d08d41b4edcdef62aa5b2f2eb4b9
diff --git a/src/com/android/contacts/group/GroupMembersFragment.java b/src/com/android/contacts/group/GroupMembersFragment.java
index 1135939..43acd0a 100644
--- a/src/com/android/contacts/group/GroupMembersFragment.java
+++ b/src/com/android/contacts/group/GroupMembersFragment.java
@@ -65,10 +65,13 @@
import com.android.contacts.list.MultiSelectContactsListFragment;
import com.android.contacts.list.UiIntentActions;
import com.android.contactsbind.experiments.Flags;
+import com.google.common.primitives.Longs;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/** Displays the members of a group. */
@@ -303,15 +306,24 @@
ContactsContract.Data.MIMETYPE + "='"
+ ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "'";
- public static final String[] PROJECTION = {
+ public static final String[] EMAIL_PROJECTION = {
ContactsContract.Data.CONTACT_ID,
- ContactsContract.Data.IS_PRIMARY,
+ ContactsContract.CommonDataKinds.Email._ID,
+ ContactsContract.Data.IS_SUPER_PRIMARY,
ContactsContract.Data.DATA1
};
- public static final int ID = 0;
- public static final int IS_PRIMARY = 1;
- public static final int DATA1 = 2;
+ public static final String[] PHONE_PROJECTION = {
+ ContactsContract.Data.CONTACT_ID,
+ ContactsContract.CommonDataKinds.Phone._ID,
+ ContactsContract.Data.IS_SUPER_PRIMARY,
+ ContactsContract.Data.DATA1
+ };
+
+ public static final int CONTACT_ID = 0;
+ public static final int ITEM_ID = 1;
+ public static final int PRIMARY = 2;
+ public static final int DATA1 = 3;
}
private List<String> getSendToDataForIds(long[] ids, String scheme) {
@@ -324,7 +336,10 @@
+ " AND " + ContactsContract.CommonDataKinds.Phone._ID + " IN (" + sIds + ")");
final ContentResolver contentResolver = getContext().getContentResolver();
final Cursor cursor = contentResolver.query(ContactsContract.Data.CONTENT_URI,
- Query.PROJECTION, select, null, null);
+ ContactsUtils.SCHEME_MAILTO.equals(scheme)
+ ? Query.EMAIL_PROJECTION
+ : Query.PHONE_PROJECTION,
+ select, null, null);
if (cursor == null) {
return items;
@@ -350,8 +365,12 @@
if(ids == null || ids.length == 0) return;
// Get emails or phone numbers
- final List<String> itemsData = new ArrayList<>();
- final Set<String> usedContactIds = new HashSet<>();
+ // encounteredIds <contact_id, <item_id, is_super_primary>>
+ final Map<String, Map<String, Boolean>> encounteredIds = new HashMap<>();
+ // primaryItems <contact_id, has_super_primary>
+ final Map<String, Boolean> primaryItems = new HashMap<>();
+ // itemList <item_data>
+ final List<String> itemList = new ArrayList<>();
final String sIds = GroupUtil.convertArrayToString(ids);
final String select = (ContactsUtils.SCHEME_MAILTO.equals(sendScheme)
? Query.EMAIL_SELECTION
@@ -359,7 +378,10 @@
+ " AND " + ContactsContract.Data.CONTACT_ID + " IN (" + sIds + ")";
final ContentResolver contentResolver = getContext().getContentResolver();
final Cursor cursor = contentResolver.query(ContactsContract.Data.CONTENT_URI,
- Query.PROJECTION, select, null, null);
+ ContactsUtils.SCHEME_MAILTO.equals(sendScheme)
+ ? Query.EMAIL_PROJECTION
+ : Query.PHONE_PROJECTION,
+ select, null, null);
if (cursor == null) {
return;
@@ -368,35 +390,62 @@
try {
cursor.moveToPosition(-1);
while (cursor.moveToNext()) {
- final String contactId = cursor.getString(Query.ID);
+ final String contactId = cursor.getString(Query.CONTACT_ID);
+ final String itemId = cursor.getString(Query.ITEM_ID);
+ final boolean isPrimary = cursor.getInt(Query.PRIMARY) != 0;
final String data = cursor.getString(Query.DATA1);
- if (!usedContactIds.contains(contactId)) {
- usedContactIds.add(contactId);
- } else {
- // If we found a contact with multiple items (email, phone), start the picker
- startSendToSelectionPickerActivity(ids, sendScheme, title);
- return;
- } if (!TextUtils.isEmpty(data)) {
- itemsData.add(data);
+ if (!encounteredIds.containsKey(contactId)) {
+ encounteredIds.put(contactId, new HashMap<String, Boolean>());
+ }
+ final Boolean prevHasSuperPrimary = primaryItems.get(contactId);
+ final boolean hasPrimary = prevHasSuperPrimary == null
+ ? isPrimary
+ : prevHasSuperPrimary || isPrimary;
+ primaryItems.put(contactId, hasPrimary);
+
+ if (!TextUtils.isEmpty(data)) {
+ final Map<String, Boolean> itemMap = encounteredIds.get(contactId);
+ itemMap.put(itemId, isPrimary);
+ itemList.add(data);
}
}
} finally {
cursor.close();
}
- if (itemsData.size() == 0 || usedContactIds.size() < ids.length) {
+ // Start picker if a contact has multiple items with no superPrimary
+ for (Map.Entry<String, Map<String, Boolean>> i : encounteredIds.entrySet()) {
+ boolean hasSuperPrimary = primaryItems.get(i.getKey());
+ if (i.getValue().size() > 1 && !hasSuperPrimary) {
+ // Build list of default selected item ids
+ final List<Long> defaultSelection = new ArrayList<>();
+ for (Map.Entry<String, Map<String, Boolean>> j : encounteredIds.entrySet()) {
+ for (Map.Entry<String, Boolean> k : j.getValue().entrySet()) {
+ final String itemId = k.getKey();
+ if (j.getValue().size() == 1 || k.getValue()) {
+ defaultSelection.add(Long.parseLong(itemId));
+ }
+ }
+ }
+ final long[] defaultSelectionArray = Longs.toArray(defaultSelection);
+ startSendToSelectionPickerActivity(ids, defaultSelectionArray, sendScheme, title);
+ return;
+ }
+ }
+
+ if (itemList.size() == 0 || encounteredIds.size() < ids.length) {
Toast.makeText(getContext(), ContactsUtils.SCHEME_MAILTO.equals(sendScheme)
? getString(R.string.groupSomeContactsNoEmailsToast)
: getString(R.string.groupSomeContactsNoPhonesToast),
Toast.LENGTH_LONG).show();
}
- if (itemsData.size() == 0) {
+ if (itemList.size() == 0) {
return;
}
- final String itemsString = GroupUtil.convertListToString(itemsData);
+ final String itemsString = TextUtils.join(",", itemList);
startSendToSelectionActivity(itemsString, sendScheme, title);
}
@@ -404,9 +453,10 @@
startActivity(GroupUtil.createSendToSelectionIntent(listItems, sendScheme, title));
}
- private void startSendToSelectionPickerActivity(long[] ids, String sendScheme, String title) {
+ private void startSendToSelectionPickerActivity(long[] ids, long[] defaultSelection,
+ String sendScheme, String title) {
startActivityForResult(GroupUtil.createSendToSelectionPickerIntent(getContext(), ids,
- sendScheme, title), RESULT_SEND_TO_SELECTION);
+ defaultSelection, sendScheme, title), RESULT_SEND_TO_SELECTION);
}
private void startGroupAddMemberActivity() {
@@ -507,7 +557,7 @@
final String sendScheme = data.getStringExtra(UiIntentActions.SELECTION_SEND_SCHEME);
final String sendTitle = data.getStringExtra(UiIntentActions.SELECTION_SEND_TITLE);
final List<String> items = getSendToDataForIds(ids, sendScheme);
- final String list = GroupUtil.convertListToString(items);
+ final String list = TextUtils.join(",", items);
startSendToSelectionActivity(list, sendScheme, sendTitle);
break;
}
diff --git a/src/com/android/contacts/group/GroupUtil.java b/src/com/android/contacts/group/GroupUtil.java
index e9af483..dc85152 100644
--- a/src/com/android/contacts/group/GroupUtil.java
+++ b/src/com/android/contacts/group/GroupUtil.java
@@ -109,14 +109,15 @@
}
/** Returns an Intent to pick emails/phones to send to selection (or group) */
- public static Intent createSendToSelectionPickerIntent(
- Context context, long[] ids, String sendScheme, String title) {
+ public static Intent createSendToSelectionPickerIntent(Context context, long[] ids,
+ long[] defaultSelection, String sendScheme, String title) {
final Intent intent = new Intent(context, ContactSelectionActivity.class);
intent.setAction(UiIntentActions.ACTION_SELECT_ITEMS);
intent.setType(ContactsUtils.SCHEME_MAILTO.equals(sendScheme)
? ContactsContract.CommonDataKinds.Email.CONTENT_TYPE
: ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
- intent.putExtra(UiIntentActions.LIST_CONTACTS, ids);
+ intent.putExtra(UiIntentActions.SELECTION_ITEM_LIST, ids);
+ intent.putExtra(UiIntentActions.SELECTION_DEFAULT_SELECTION, defaultSelection);
intent.putExtra(UiIntentActions.SELECTION_SEND_SCHEME, sendScheme);
intent.putExtra(UiIntentActions.SELECTION_SEND_TITLE, title);
@@ -141,11 +142,6 @@
return Arrays.toString(list).replace("[", "").replace("]", "");
}
- public static String convertListToString(List<String> list) {
- if (list == null || list.size() == 0) return "";
- return list.toString().replace("[", "").replace("]", "");
- }
-
public static long[] convertLongSetToLongArray(Set<Long> set) {
final Long[] contactIds = set.toArray(new Long[set.size()]);
final long[] result = new long[contactIds.length];
diff --git a/src/com/android/contacts/list/MultiSelectEmailAddressesListAdapter.java b/src/com/android/contacts/list/MultiSelectEmailAddressesListAdapter.java
index d77a98e..b225ba4 100644
--- a/src/com/android/contacts/list/MultiSelectEmailAddressesListAdapter.java
+++ b/src/com/android/contacts/list/MultiSelectEmailAddressesListAdapter.java
@@ -83,7 +83,7 @@
}
public void setArguments(Bundle bundle) {
- mContactIdsFilter = bundle.getLongArray(UiIntentActions.LIST_CONTACTS);
+ mContactIdsFilter = bundle.getLongArray(UiIntentActions.SELECTION_ITEM_LIST);
}
@Override
diff --git a/src/com/android/contacts/list/MultiSelectEmailAddressesListFragment.java b/src/com/android/contacts/list/MultiSelectEmailAddressesListFragment.java
index fb33499..d3aa5ca 100644
--- a/src/com/android/contacts/list/MultiSelectEmailAddressesListFragment.java
+++ b/src/com/android/contacts/list/MultiSelectEmailAddressesListFragment.java
@@ -17,6 +17,7 @@
import android.app.Activity;
import android.content.Intent;
+import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -27,6 +28,8 @@
import com.android.contacts.R;
import com.android.contacts.common.logging.ListEvent;
+import java.util.TreeSet;
+
/** Displays a list of emails with check boxes. */
public class MultiSelectEmailAddressesListFragment
extends MultiSelectContactsListFragment<MultiSelectEmailAddressesListAdapter>{
@@ -92,9 +95,40 @@
}
@Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final long[] selectedIds = getActivity().getIntent().getLongArrayExtra(
+ UiIntentActions.SELECTION_DEFAULT_SELECTION);
+ if (selectedIds != null && selectedIds.length != 0) {
+ final TreeSet<Long> selectedIdsTree = new TreeSet<>();
+ for (int i = 0; i < selectedIds.length; i++) {
+ selectedIdsTree.add(selectedIds[i]);
+ }
+ getAdapter().setSelectedContactIds(selectedIdsTree);
+ onSelectedContactsChanged();
+ }
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ @Override
public void onStart() {
super.onStart();
displayCheckBoxes(true);
+
+ final long[] itemIds = getActivity().getIntent().getLongArrayExtra(
+ UiIntentActions.SELECTION_ITEM_LIST);
+ final boolean[] selectedFlags = getActivity().getIntent().getBooleanArrayExtra(
+ UiIntentActions.SELECTION_DEFAULT_SELECTION);
+ if (itemIds != null && selectedFlags != null && itemIds.length == selectedFlags.length) {
+ TreeSet<Long> selectedIds = new TreeSet<>();
+ for (int i = 0; i < itemIds.length; i++) {
+ if (selectedFlags[i]) {
+ selectedIds.add(itemIds[i]);
+ }
+ }
+ getAdapter().setSelectedContactIds(selectedIds);
+ onSelectedContactsChanged();
+ }
}
@Override
diff --git a/src/com/android/contacts/list/MultiSelectPhoneNumbersListAdapter.java b/src/com/android/contacts/list/MultiSelectPhoneNumbersListAdapter.java
index a545b31..b3574ab 100644
--- a/src/com/android/contacts/list/MultiSelectPhoneNumbersListAdapter.java
+++ b/src/com/android/contacts/list/MultiSelectPhoneNumbersListAdapter.java
@@ -83,7 +83,7 @@
}
public void setArguments(Bundle bundle) {
- mContactIdsFilter = bundle.getLongArray(UiIntentActions.LIST_CONTACTS);
+ mContactIdsFilter = bundle.getLongArray(UiIntentActions.SELECTION_ITEM_LIST);
}
@Override
diff --git a/src/com/android/contacts/list/MultiSelectPhoneNumbersListFragment.java b/src/com/android/contacts/list/MultiSelectPhoneNumbersListFragment.java
index 638a4d4..aea89e4 100644
--- a/src/com/android/contacts/list/MultiSelectPhoneNumbersListFragment.java
+++ b/src/com/android/contacts/list/MultiSelectPhoneNumbersListFragment.java
@@ -17,6 +17,7 @@
import android.app.Activity;
import android.content.Intent;
+import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -27,6 +28,8 @@
import com.android.contacts.R;
import com.android.contacts.common.logging.ListEvent;
+import java.util.TreeSet;
+
/** Displays a list of phone numbers with check boxes. */
public class MultiSelectPhoneNumbersListFragment
extends MultiSelectContactsListFragment<MultiSelectPhoneNumbersListAdapter> {
@@ -92,6 +95,22 @@
}
@Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final long[] selectedIds = getActivity().getIntent().getLongArrayExtra(
+ UiIntentActions.SELECTION_DEFAULT_SELECTION);
+ if (selectedIds != null && selectedIds.length != 0) {
+ final TreeSet<Long> selectedIdsTree = new TreeSet<>();
+ for (int i = 0; i < selectedIds.length; i++) {
+ selectedIdsTree.add(selectedIds[i]);
+ }
+ getAdapter().setSelectedContactIds(selectedIdsTree);
+ onSelectedContactsChanged();
+ }
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ @Override
public void onStart() {
super.onStart();
displayCheckBoxes(true);
diff --git a/src/com/android/contacts/list/UiIntentActions.java b/src/com/android/contacts/list/UiIntentActions.java
index f328fab..b2157fb 100644
--- a/src/com/android/contacts/list/UiIntentActions.java
+++ b/src/com/android/contacts/list/UiIntentActions.java
@@ -59,6 +59,18 @@
"com.android.contacts.extra.SELECTION_SEND_TITLE";
/**
+ * The item ids for multi select picker fragment/adapter
+ */
+ public static final String SELECTION_ITEM_LIST =
+ "com.android.contacts.extra.SELECTION_ITEM_LIST";
+
+ /**
+ * The default selection flags for the multi select picker fragment/adapter
+ */
+ public static final String SELECTION_DEFAULT_SELECTION =
+ "com.android.contacts.extra.SELECTION_DEFAULT_SELECTION";
+
+ /**
* When in LIST_GROUP_ACTION mode, this is the group to display.
*/
public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";