Merge "Consolidate adb helper methods into single class." into ub-contactsdialer-h-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d7800b4..18e8e92 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1851,4 +1851,7 @@
 
     <!-- Confirm button text for dialog to turn auto-sync on [CHAR LIMIT=30] -->
     <string name="turn_auto_sync_on_dialog_confirm_btn">Turn on</string>
+
+    <!-- No network connection error message [CHAR LIMIT=50] -->
+    <string name="connection_error_message">No connection</string>
 </resources>
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 0d4b4c0..a73d8e7 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -182,6 +182,10 @@
         }
     }
 
+    public void showConnectionErrorMsg() {
+        Snackbar.make(mLayoutRoot, R.string.connection_error_message, Snackbar.LENGTH_LONG).show();
+    }
+
     private final ContactListFilterListener mFilterListener = new ContactListFilterListener() {
         @Override
         public void onContactListFilterChanged() {
@@ -729,7 +733,6 @@
                 }).show();
     }
 
-
     private class SaveServiceListener extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
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/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index a748c06..7a99705 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -57,6 +57,7 @@
 import com.android.contacts.ContactsDrawerActivity;
 import com.android.contacts.R;
 import com.android.contacts.activities.ActionBarAdapter;
+import com.android.contacts.activities.PeopleActivity;
 import com.android.contacts.common.Experiments;
 import com.android.contacts.common.compat.CompatUtils;
 import com.android.contacts.common.list.ContactEntryListFragment;
@@ -548,6 +549,14 @@
             @Override
             public void onRefresh() {
                 mHandler.removeCallbacks(mCancelRefresh);
+
+                final boolean isNetworkConnected = SyncUtil.isNetworkConnected(getContext());
+                if (!isNetworkConnected) {
+                    mSwipeRefreshLayout.setRefreshing(false);
+                    ((PeopleActivity)getActivity()).showConnectionErrorMsg();
+                    return;
+                }
+
                 syncContacts(getFilter());
                 mHandler.postDelayed(mCancelRefresh, Flags.getInstance(getContext())
                         .getInteger(Experiments.PULL_TO_REFRESH_CANCEL_REFRESH_MILLIS));
@@ -570,6 +579,7 @@
         if (filter == null) {
             return;
         }
+
         final Bundle bundle = new Bundle();
         bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
         bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
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";
diff --git a/src/com/android/contacts/util/SyncUtil.java b/src/com/android/contacts/util/SyncUtil.java
index 6c17c05..34e6e8c 100644
--- a/src/com/android/contacts/util/SyncUtil.java
+++ b/src/com/android/contacts/util/SyncUtil.java
@@ -18,6 +18,8 @@
 import android.accounts.Account;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
 import android.provider.ContactsContract;
 
 import com.android.contacts.common.model.account.GoogleAccountType;
@@ -90,4 +92,11 @@
         }
         return SYNC_SETTING_SYNC_ON;
     }
+
+    public static boolean isNetworkConnected(Context context) {
+        ConnectivityManager cm =
+                (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
+        return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
+    }
 }
\ No newline at end of file