Merge "Make MaterialPalette parcelable" into lmp-mr1-dev
diff --git a/src/com/android/contacts/common/ContactsUtils.java b/src/com/android/contacts/common/ContactsUtils.java
index 857450d..a6e0e0e 100644
--- a/src/com/android/contacts/common/ContactsUtils.java
+++ b/src/com/android/contacts/common/ContactsUtils.java
@@ -41,6 +41,8 @@
     public static final String SCHEME_MAILTO = "mailto";
     public static final String SCHEME_SMSTO = "smsto";
 
+    private static final int DEFAULT_THUMBNAIL_SIZE = 96;
+
     private static int sThumbnailSize = -1;
 
     // TODO find a proper place for the canonical version of these
@@ -139,14 +141,17 @@
             final Cursor c = context.getContentResolver().query(
                     DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
                     new String[] { DisplayPhoto.THUMBNAIL_MAX_DIM }, null, null, null);
-            try {
-                c.moveToFirst();
-                sThumbnailSize = c.getInt(0);
-            } finally {
-                c.close();
+            if (c != null) {
+                try {
+                    if (c.moveToFirst()) {
+                        sThumbnailSize = c.getInt(0);
+                    }
+                } finally {
+                    c.close();
+                }
             }
         }
-        return sThumbnailSize;
+        return sThumbnailSize != -1 ? sThumbnailSize : DEFAULT_THUMBNAIL_SIZE;
     }
 
     private static Intent getCustomImIntent(ImDataItem im, int protocol) {
diff --git a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
index fc6e460..a9bd684 100644
--- a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
@@ -231,7 +231,7 @@
      *
      * @return {@code true} if the dialog show be closed.  {@code false} otherwise.
      */
-    private boolean handleImportRequest(int resId, long subscriptionId) {
+    private boolean handleImportRequest(int resId, int subscriptionId) {
         // There are three possibilities:
         // - more than one accounts -> ask the user
         // - just one account -> use the account without asking the user
@@ -243,7 +243,7 @@
             // Send over to the account selector
             final Bundle args = new Bundle();
             args.putInt(KEY_RES_ID, resId);
-            args.putLong(KEY_SUBSCRIPTION_ID, subscriptionId);
+            args.putInt(KEY_SUBSCRIPTION_ID, subscriptionId);
             SelectAccountDialogFragment.show(
                     getFragmentManager(), this,
                     R.string.dialog_new_contact_account,
@@ -266,7 +266,7 @@
     @Override
     public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
         AccountSelectionUtil.doImport(getActivity(), extraArgs.getInt(KEY_RES_ID),
-                account, extraArgs.getLong(KEY_SUBSCRIPTION_ID));
+                account, extraArgs.getInt(KEY_SUBSCRIPTION_ID));
 
         // At this point the dialog is still showing (which is why we can use getActivity() above)
         // So close it.
diff --git a/src/com/android/contacts/common/list/ContactListAdapter.java b/src/com/android/contacts/common/list/ContactListAdapter.java
index 7e9a2e9..9107d04 100644
--- a/src/com/android/contacts/common/list/ContactListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactListAdapter.java
@@ -350,8 +350,7 @@
         super.changeCursor(partitionIndex, cursor);
 
         // Check if a profile exists
-        if (cursor != null && cursor.getCount() > 0) {
-            cursor.moveToFirst();
+        if (cursor != null && cursor.moveToFirst()) {
             setProfileExists(cursor.getInt(ContactQuery.CONTACT_IS_USER_PROFILE) == 1);
         }
     }
diff --git a/src/com/android/contacts/common/list/CustomContactListFilterActivity.java b/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
index feb7df2..b3253cc 100644
--- a/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
+++ b/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
@@ -144,9 +144,12 @@
                 if (account.dataSet != null) {
                     groupsUri.appendQueryParameter(Groups.DATA_SET, account.dataSet).build();
                 }
+                final Cursor cursor = resolver.query(groupsUri.build(), null, null, null, null);
+                if (cursor == null) {
+                    continue;
+                }
                 android.content.EntityIterator iterator =
-                        ContactsContract.Groups.newEntityIterator(resolver.query(
-                        groupsUri.build(), null, null, null, null));
+                        ContactsContract.Groups.newEntityIterator(cursor);
                 try {
                     boolean hasGroups = false;
 
diff --git a/src/com/android/contacts/common/list/ProfileAndContactsLoader.java b/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
index c19737d..698ef96 100644
--- a/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
+++ b/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
@@ -61,8 +61,8 @@
         Cursor cursor = null;
         try {
             cursor = super.loadInBackground();
-        } catch (NullPointerException e) {
-            // Ignore NPEs thrown by providers
+        } catch (NullPointerException | SecurityException e) {
+            // Ignore NPEs and SecurityExceptions thrown by providers
         }
         final Cursor contactsCursor = cursor;
         cursors.add(contactsCursor);
diff --git a/src/com/android/contacts/common/model/ContactLoader.java b/src/com/android/contacts/common/model/ContactLoader.java
index eba825b..998fb2d 100644
--- a/src/com/android/contacts/common/model/ContactLoader.java
+++ b/src/com/android/contacts/common/model/ContactLoader.java
@@ -63,9 +63,11 @@
 import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -758,6 +760,34 @@
         }
     }
 
+    static private class AccountKey {
+        private final String mAccountName;
+        private final String mAccountType;
+        private final String mDataSet;
+
+        public AccountKey(String accountName, String accountType, String dataSet) {
+            mAccountName = accountName;
+            mAccountType = accountType;
+            mDataSet = dataSet;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mAccountName, mAccountType, mDataSet);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof AccountKey)) {
+                return false;
+            }
+            final AccountKey other = (AccountKey) obj;
+            return Objects.equals(mAccountName, other.mAccountName)
+                && Objects.equals(mAccountType, other.mAccountType)
+                && Objects.equals(mDataSet, other.mDataSet);
+        }
+    }
+
     /**
      * Loads groups meta-data for all groups associated with all constituent raw contacts'
      * accounts.
@@ -765,11 +795,15 @@
     private void loadGroupMetaData(Contact result) {
         StringBuilder selection = new StringBuilder();
         ArrayList<String> selectionArgs = new ArrayList<String>();
+        final HashSet<AccountKey> accountsSeen = new HashSet<>();
         for (RawContact rawContact : result.getRawContacts()) {
             final String accountName = rawContact.getAccountName();
             final String accountType = rawContact.getAccountTypeString();
             final String dataSet = rawContact.getDataSet();
-            if (accountName != null && accountType != null) {
+            final AccountKey accountKey = new AccountKey(accountName, accountType, dataSet);
+            if (accountName != null && accountType != null &&
+                    !accountsSeen.contains(accountKey)) {
+                accountsSeen.add(accountKey);
                 if (selection.length() != 0) {
                     selection.append(" OR ");
                 }
diff --git a/src/com/android/contacts/common/util/AccountSelectionUtil.java b/src/com/android/contacts/common/util/AccountSelectionUtil.java
index c378041..78cc2d5 100644
--- a/src/com/android/contacts/common/util/AccountSelectionUtil.java
+++ b/src/com/android/contacts/common/util/AccountSelectionUtil.java
@@ -161,7 +161,7 @@
     }
 
     public static void doImport(Context context, int resId, AccountWithDataSet account,
-            long subscriptionId) {
+            int subscriptionId) {
         switch (resId) {
             case R.string.import_from_sim: {
                 doImportFromSim(context, account, subscriptionId);
@@ -175,7 +175,7 @@
     }
 
     public static void doImportFromSim(Context context, AccountWithDataSet account,
-            long subscriptionId) {
+            int subscriptionId) {
         Intent importIntent = new Intent(Intent.ACTION_VIEW);
         importIntent.setType("vnd.android.cursor.item/sim-contact");
         if (account != null) {
@@ -183,7 +183,7 @@
             importIntent.putExtra("account_type", account.type);
             importIntent.putExtra("data_set", account.dataSet);
         }
-        importIntent.putExtra("subscription_id", subscriptionId);
+        importIntent.putExtra("subscription_id", (Integer) subscriptionId);
         importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
         context.startActivity(importIntent);
     }