Don't pass read-only portions of RawContactDeltaList to contact save service

Bug 23896510

Change-Id: Ie50aa5c0581779c12861072ec838f26d444fb549
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index c3a7f24..10f8f9c 100755
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -56,6 +56,7 @@
 import com.android.contacts.common.model.RawContactDelta;
 import com.android.contacts.common.model.RawContactDeltaList;
 import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.account.AccountType;
 import com.android.contacts.common.model.account.AccountWithDataSet;
 import com.android.contacts.common.util.PermissionsUtil;
 import com.android.contacts.compat.PinnedPositionsCompat;
@@ -66,6 +67,7 @@
 
 import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
@@ -372,8 +374,12 @@
             String saveModeExtraKey, int saveMode, boolean isProfile,
             Class<? extends Activity> callbackActivity, String callbackAction,
             Bundle updatedPhotos, String joinContactIdExtraKey, Long joinContactId) {
-        Intent serviceIntent = new Intent(
-                context, ContactSaveService.class);
+        // Don't pass read-only RawContactDeltas in RawContactDeltaList to contact save service,
+        // because 1. read-only RawContactDeltas are not writable anyway; 2. read-only
+        // RawContactDeltas may be problematic, see b/23896510.
+        removeReadOnlyContacts(context, state);
+
+        Intent serviceIntent = new Intent(context, ContactSaveService.class);
         serviceIntent.setAction(ContactSaveService.ACTION_SAVE_CONTACT);
         serviceIntent.putExtra(EXTRA_CONTACT_STATE, (Parcelable) state);
         serviceIntent.putExtra(EXTRA_SAVE_IS_PROFILE, isProfile);
@@ -398,6 +404,26 @@
         return serviceIntent;
     }
 
+    private static void removeReadOnlyContacts(Context context, RawContactDeltaList state) {
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "Before trimming: " + state.size());
+        }
+        int countReadOnly = 0;
+        final Iterator<RawContactDelta> iterator = state.iterator();
+        while (iterator.hasNext()) {
+            final RawContactDelta rawContactDelta = iterator.next();
+            final AccountType accountType = rawContactDelta.getRawContactAccountType(context);
+            if (accountType != null && !accountType.areContactsWritable()) {
+                countReadOnly++;
+                iterator.remove();
+            }
+        }
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "# of read-only removed: " + countReadOnly);
+            Log.v(TAG, "After trimming: " + state.size());
+        }
+    }
+
     private void saveContact(Intent intent) {
         RawContactDeltaList state = intent.getParcelableExtra(EXTRA_CONTACT_STATE);
         boolean isProfile = intent.getBooleanExtra(EXTRA_SAVE_IS_PROFILE, false);