[Issue 2017273] Contacts Aggregator doesn't maintain state of dirty bit...
diff --git a/src/com/android/providers/contacts/OpenHelper.java b/src/com/android/providers/contacts/OpenHelper.java
index f7ce82c..53be513 100644
--- a/src/com/android/providers/contacts/OpenHelper.java
+++ b/src/com/android/providers/contacts/OpenHelper.java
@@ -57,7 +57,7 @@
 /* package */ class OpenHelper extends SQLiteOpenHelper {
     private static final String TAG = "OpenHelper";
 
-    private static final int DATABASE_VERSION = 54;
+    private static final int DATABASE_VERSION = 55;
     private static final String DATABASE_NAME = "contacts2.db";
     private static final String DATABASE_PRESENCE = "presence_db";
 
@@ -568,25 +568,8 @@
         ");");
 
         /**
-         * set contact.dirty whenever the contact is updated and the new version does not explicity
-         * clear the dirty flag
-         *
-         * Want to have a data row that has the server version of the contact. Then when I save
-         * an entry from the server into the provider I will set the server version of the data
-         * while also clearing the dirty flag of the contact.
-         *
-         * increment the contact.version whenever the contact is updated
+         * Automatically delete Data rows when a raw contact is deleted.
          */
-        db.execSQL("CREATE TRIGGER " + Tables.RAW_CONTACTS + "_updated1 "
-                + "   BEFORE UPDATE ON " + Tables.RAW_CONTACTS
-                + " BEGIN "
-                + "   UPDATE " + Tables.RAW_CONTACTS
-                + "     SET "
-                +         RawContacts.VERSION + "=OLD." + RawContacts.VERSION + "+1, "
-                +         RawContacts.DIRTY + "=1"
-                + "     WHERE " + RawContacts._ID + "=OLD." + RawContacts._ID + ";"
-                + " END");
-
         db.execSQL("CREATE TRIGGER " + Tables.RAW_CONTACTS + "_deleted "
                 + "   BEFORE DELETE ON " + Tables.RAW_CONTACTS
                 + " BEGIN "
@@ -596,27 +579,46 @@
                 + "     WHERE " + PhoneLookupColumns.RAW_CONTACT_ID + "=OLD." + RawContacts._ID + ";"
                 + " END");
 
+        /**
+         * Triggers that set {@link RawContacts#DIRTY} and update {@link RawContacts#VERSION}
+         * when the contact is marked for deletion or any time a data row is inserted, updated
+         * or deleted.
+         */
+        db.execSQL("CREATE TRIGGER " + Tables.RAW_CONTACTS + "_marked_deleted "
+                + "   BEFORE UPDATE ON " + Tables.RAW_CONTACTS
+                + " BEGIN "
+                + "   UPDATE " + Tables.RAW_CONTACTS
+                + "     SET "
+                +         RawContacts.VERSION + "=OLD." + RawContacts.VERSION + "+1, "
+                +         RawContacts.DIRTY + "=1"
+                + "     WHERE " + RawContacts._ID + "=OLD." + RawContacts._ID
+                + "       AND NEW." + RawContacts.DELETED + "!= OLD." + RawContacts.DELETED + ";"
+                + " END");
+
         db.execSQL("CREATE TRIGGER " + Tables.DATA + "_updated AFTER UPDATE ON " + Tables.DATA
                 + " BEGIN "
                 + "   UPDATE " + Tables.DATA
                 + "     SET " + Data.DATA_VERSION + "=OLD." + Data.DATA_VERSION + "+1 "
                 + "     WHERE " + Data._ID + "=OLD." + Data._ID + ";"
                 + "   UPDATE " + Tables.RAW_CONTACTS
-                + "     SET " + RawContacts.DIRTY + "=1"
+                + "     SET " + RawContacts.DIRTY + "=1, "
+                + "         " +	RawContacts.VERSION + "=" + RawContacts.VERSION + "+1 "
                 + "     WHERE " + RawContacts._ID + "=OLD." + Data.RAW_CONTACT_ID + ";"
                 + " END");
 
         db.execSQL("CREATE TRIGGER " + Tables.DATA + "_inserted BEFORE INSERT ON " + Tables.DATA
                 + " BEGIN "
                 + "   UPDATE " + Tables.RAW_CONTACTS
-                + "     SET " + RawContacts.DIRTY + "=1"
+                + "     SET " + RawContacts.DIRTY + "=1, "
+                + "         " + RawContacts.VERSION + "=" + RawContacts.VERSION + "+1 "
                 + "     WHERE " + RawContacts._ID + "=NEW." + Data.RAW_CONTACT_ID + ";"
                 + " END");
 
         db.execSQL("CREATE TRIGGER " + Tables.DATA + "_deleted BEFORE DELETE ON " + Tables.DATA
                 + " BEGIN "
                 + "   UPDATE " + Tables.RAW_CONTACTS
-                + "     SET " + RawContacts.DIRTY + "=1"
+                + "     SET " + RawContacts.DIRTY + "=1,"
+                + "         " + RawContacts.VERSION + "=" + RawContacts.VERSION + "+1 "
                 + "     WHERE " + RawContacts._ID + "=OLD." + Data.RAW_CONTACT_ID + ";"
                 + "   DELETE FROM " + Tables.PHONE_LOOKUP
                 + "     WHERE " + PhoneLookupColumns.DATA_ID + "=OLD." + Data._ID + ";"
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index ec253c3..3a31e21 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -392,7 +392,7 @@
                 null));
     }
 
-    public void testContactDirtySetOnChange() {
+    public void testRawContactDirtySetOnChange() {
         Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
                 createRawContact(mAccount));
         assertDirty(uri, true);
@@ -400,7 +400,7 @@
         assertDirty(uri, false);
     }
 
-    public void testContactDirtyAndVersion() {
+    public void testRawContactDirtyAndVersion() {
         final long rawContactId = createRawContact(mAccount);
         Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId);
         assertDirty(uri, true);
@@ -409,34 +409,19 @@
         ContentValues values = new ContentValues();
         values.put(ContactsContract.RawContacts.DIRTY, 0);
         values.put(ContactsContract.RawContacts.SEND_TO_VOICEMAIL, 1);
+        values.put(ContactsContract.RawContacts.AGGREGATION_MODE,
+                RawContacts.AGGREGATION_MODE_IMMEDITATE);
+        values.put(ContactsContract.RawContacts.STARRED, 1);
         assertEquals(1, mResolver.update(uri, values, null, null));
-        ++version;
         assertEquals(version, getVersion(uri));
 
         assertDirty(uri, false);
 
-        values = new ContentValues();
-        values.put(ContactsContract.RawContacts.SEND_TO_VOICEMAIL, 0);
-        assertEquals(1, mResolver.update(uri, values, null, null));
-        ++version;
-        assertEquals(version, getVersion(uri));
-
-        assertDirty(uri, true);
-
-        clearDirty(uri);
-        assertDirty(uri, false);
-        ++version;
-        assertEquals(version, getVersion(uri));
-
         Uri emailUri = insertEmail(rawContactId, "goo@woo.com");
         assertDirty(uri, true);
         ++version;
-        version = getVersion(uri);
-
-        clearDirty(uri);
-        assertDirty(uri, false);
-        ++version;
         assertEquals(version, getVersion(uri));
+        clearDirty(uri);
 
         values = new ContentValues();
         values.put(Email.DATA, "goo@hoo.com");
@@ -444,21 +429,42 @@
         assertDirty(uri, true);
         ++version;
         assertEquals(version, getVersion(uri));
-
         clearDirty(uri);
-        assertDirty(uri, false);
+
+        mResolver.delete(emailUri, null, null);
+        assertDirty(uri, true);
         ++version;
         assertEquals(version, getVersion(uri));
     }
 
-    public void testContactVersionUpdates() {
+    public void testRawContactClearDirty() {
+        final long rawContactId = createRawContact(mAccount);
         Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
-                createRawContact(mAccount));
+                rawContactId);
         long version = getVersion(uri);
-        ContentValues values = new ContentValues();
-        values.put(ContactsContract.RawContacts.SEND_TO_VOICEMAIL, 1);
-        mResolver.update(uri, values, null, null);
-        assertEquals(version + 1, getVersion(uri));
+        insertEmail(rawContactId, "goo@woo.com");
+        assertDirty(uri, true);
+        version++;
+        assertEquals(version, getVersion(uri));
+
+        clearDirty(uri);
+        assertDirty(uri, false);
+        assertEquals(version, getVersion(uri));
+    }
+
+    public void testRawContactDeletionSetsDirty() {
+        final long rawContactId = createRawContact(mAccount);
+        Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
+                rawContactId);
+        long version = getVersion(uri);
+        clearDirty(uri);
+        assertDirty(uri, false);
+
+        mResolver.delete(uri, null, null);
+        assertStoredValues(uri, RawContacts.DELETED, "1");
+        assertDirty(uri, true);
+        version++;
+        assertEquals(version, getVersion(uri));
     }
 }