Merge "Fix crash when separating multiple empty raw contacts"
diff --git a/src/com/android/contacts/model/EntitySet.java b/src/com/android/contacts/model/EntitySet.java
index 83fe338..830f8da 100644
--- a/src/com/android/contacts/model/EntitySet.java
+++ b/src/com/android/contacts/model/EntitySet.java
@@ -130,11 +130,13 @@
         // Second pass builds actual operations
         for (EntityDelta delta : this) {
             final int firstBatch = diff.size();
-            backRefs[rawContactIndex++] = firstBatch;
+            final boolean isInsert = delta.isContactInsert();
+            backRefs[rawContactIndex++] = isInsert ? firstBatch : -1;
+
             delta.buildDiff(diff);
 
             // Only create rules for inserts
-            if (!delta.isContactInsert()) continue;
+            if (!isInsert) continue;
 
             // If we are going to split all contacts, there is no point in first combining them
             if (mSplitRawContacts) continue;
@@ -208,18 +210,25 @@
         builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_SEPARATE);
 
         Long rawContactId1 = get(index1).getValues().getAsLong(RawContacts._ID);
+        int backRef1 = backRefs[index1];
         if (rawContactId1 != null && rawContactId1 >= 0) {
             builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
+        } else if (backRef1 >= 0) {
+            builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, backRef1);
         } else {
-            builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, backRefs[index1]);
+            return;
         }
 
         Long rawContactId2 = get(index2).getValues().getAsLong(RawContacts._ID);
+        int backRef2 = backRefs[index2];
         if (rawContactId2 != null && rawContactId2 >= 0) {
             builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
+        } else if (backRef2 >= 0) {
+            builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, backRef2);
         } else {
-            builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, backRefs[index2]);
+            return;
         }
+
         diff.add(builder.build());
     }
 
diff --git a/tests/src/com/android/contacts/EntitySetTests.java b/tests/src/com/android/contacts/EntitySetTests.java
index edfca6d..037c927 100644
--- a/tests/src/com/android/contacts/EntitySetTests.java
+++ b/tests/src/com/android/contacts/EntitySetTests.java
@@ -358,6 +358,58 @@
         assertEquals("Unexpected exception updates", 2, exceptionCount);
     }
 
+    public void testInsertInsertSeparate() {
+        // This assumes getInsert() will return back an "empty" raw
+        // contact meaning it will contain no actual information
+        final EntityDelta insertFirst = getInsert();
+        final EntityDelta insertSecond = getInsert();
+        final EntitySet set = buildSet(insertFirst, insertSecond);
+
+        // This would normally build a TYPE_KEEP_SEPARATE aggregation exception,
+        // but since the raw contacts won't be added because they are empty,
+        // we should get 0 exceptions back
+        set.splitRawContacts();
+
+        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+        final int exceptionCount = countExceptionUpdates(diff);
+        assertEquals("Unexpected exception updates", 0, exceptionCount);
+    }
+
+    public void testUpdateInsertSeparate() {
+        // This assumes getInsert() will return back an "empty" raw
+        // contact meaning it will contain no actual information
+        final EntityDelta update = getUpdate(CONTACT_FIRST);
+        final EntityDelta insert = getInsert();
+        final EntitySet set = buildSet(update, insert);
+
+        // This would normally build a KEEP_SEPARATE aggregation exception,
+        // but since the insert won't be added because it is empty,
+        // we should get 0 exceptions back
+        set.splitRawContacts();
+
+        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+        final int exceptionCount = countExceptionUpdates(diff);
+        assertEquals("Unexpected exception updates", 0, exceptionCount);
+    }
+
+    public void testUpdateInsertInsertSeparate() {
+        // This assumes getInsert() will return back an "empty" raw
+        // contact meaning it will contain no actual information
+        final EntityDelta update = getUpdate(CONTACT_FIRST);
+        final EntityDelta insertFirst = getInsert();
+        final EntityDelta insertSecond = getInsert();
+        final EntitySet set = buildSet(update, insertFirst, insertSecond);
+
+        // This would normally build a KEEP_SEPARATE aggregation exception,
+        // but since the inserts won't be added because they are empty,
+        // we should get 0 exceptions back
+        set.splitRawContacts();
+
+        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+        final int exceptionCount = countExceptionUpdates(diff);
+        assertEquals("Unexpected exception updates", 0, exceptionCount);
+    }
+
     public void testMergeDataRemoteInsert() {
         final EntitySet first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
                 buildPhone(PHONE_RED)));