Adding contacts delta api.

Updates and inserts can be detected through the use of a new timestamp
field in the contacts table.

Deletes can be detected by querying the new deleted_contacts table.

Bug: 8182147
Change-Id: I5c1e596f4e1aa58528afc29396f79cb4051e229c
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index 25b8a00..1c0fd7f 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -19,6 +19,7 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -77,6 +78,9 @@
 
 import com.android.common.content.SyncStateContentProviderHelper;
 import com.android.providers.contacts.aggregation.util.CommonNicknameCache;
+import com.android.providers.contacts.database.ContactsTableUtil;
+import com.android.providers.contacts.database.DeletedContactsTableUtil;
+import com.android.providers.contacts.database.MoreDatabaseUtils;
 import com.android.providers.contacts.util.NeededForTesting;
 import com.google.android.collect.Sets;
 
@@ -109,13 +113,14 @@
      *   700-799 Jelly Bean
      * </pre>
      */
-    static final int DATABASE_VERSION = 709;
+    static final int DATABASE_VERSION = 710;
 
     private static final String DATABASE_NAME = "contacts2.db";
     private static final String DATABASE_PRESENCE = "presence_db";
 
     public interface Tables {
         public static final String CONTACTS = "contacts";
+        public static final String DELETED_CONTACTS = "deleted_contacts";
         public static final String RAW_CONTACTS = "raw_contacts";
         public static final String STREAM_ITEMS = "stream_items";
         public static final String STREAM_ITEM_PHOTOS = "stream_item_photos";
@@ -361,6 +366,8 @@
                 + Contacts.SEND_TO_VOICEMAIL;
         public static final String CONCRETE_LOOKUP_KEY = Tables.CONTACTS + "."
                 + Contacts.LOOKUP_KEY;
+        public static final String CONCRETE_CONTACT_LAST_UPDATED_TIMESTAMP = Tables.CONTACTS + "."
+                + Contacts.CONTACT_LAST_UPDATED_TIMESTAMP;
         public static final String PHONEBOOK_LABEL_PRIMARY = "phonebook_label";
         public static final String PHONEBOOK_BUCKET_PRIMARY = "phonebook_bucket";
         public static final String PHONEBOOK_LABEL_ALTERNATIVE = "phonebook_label_alt";
@@ -961,16 +968,14 @@
                 Contacts.STARRED + " INTEGER NOT NULL DEFAULT 0," +
                 Contacts.HAS_PHONE_NUMBER + " INTEGER NOT NULL DEFAULT 0," +
                 Contacts.LOOKUP_KEY + " TEXT," +
-                ContactsColumns.LAST_STATUS_UPDATE_ID + " INTEGER REFERENCES data(_id)" +
+                ContactsColumns.LAST_STATUS_UPDATE_ID + " INTEGER REFERENCES data(_id)," +
+                Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + " INTEGER" +
         ");");
 
-        db.execSQL("CREATE INDEX contacts_has_phone_index ON " + Tables.CONTACTS + " (" +
-                Contacts.HAS_PHONE_NUMBER +
-        ");");
+        ContactsTableUtil.createIndexes(db);
 
-        db.execSQL("CREATE INDEX contacts_name_raw_contact_id_index ON " + Tables.CONTACTS + " (" +
-                Contacts.NAME_RAW_CONTACT_ID +
-        ");");
+        // deleted_contacts table
+        DeletedContactsTableUtil.create(db);
 
         // Raw_contacts table
         db.execSQL("CREATE TABLE " + Tables.RAW_CONTACTS + " (" +
@@ -1339,6 +1344,12 @@
 
         ContentResolver.requestSync(null /* all accounts */,
                 ContactsContract.AUTHORITY, new Bundle());
+
+        // Only send broadcasts for regular contacts db.
+        if (dbForProfile() == 0) {
+            mContext.sendBroadcast(new Intent(ContactsContract.Intents.CONTACTS_DATABASE_CREATED),
+                    android.Manifest.permission.READ_CONTACTS);
+        }
     }
 
     protected void initializeAutoIncrementSequences(SQLiteDatabase db) {
@@ -1608,7 +1619,8 @@
                 + Contacts.PHOTO_FILE_ID + ", "
                 + "CAST(" + Clauses.CONTACT_VISIBLE + " AS INTEGER) AS "
                         + Contacts.IN_VISIBLE_GROUP + ", "
-                + ContactsColumns.LAST_STATUS_UPDATE_ID;
+                + ContactsColumns.LAST_STATUS_UPDATE_ID + ", "
+                + ContactsColumns.CONCRETE_CONTACT_LAST_UPDATED_TIMESTAMP;
 
         String contactOptionColumns =
                 ContactsColumns.CONCRETE_CUSTOM_RINGTONE
@@ -2463,6 +2475,12 @@
             oldVersion = 709;
         }
 
+        if (oldVersion < 710) {
+            upgradeToVersion710(db);
+            upgradeViewsAndTriggers = true;
+            oldVersion = 710;
+        }
+
         if (upgradeViewsAndTriggers) {
             createContactsViews(db);
             createGroupsView(db);
@@ -3925,6 +3943,29 @@
                 + " ADD " + RawContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE + " INTEGER;");
     }
 
+    private void upgradeToVersion710(SQLiteDatabase db) {
+
+        // Adding timestamp to contacts table.
+        db.execSQL("ALTER TABLE contacts"
+                + " ADD contact_last_updated_timestamp INTEGER;");
+
+        db.execSQL("UPDATE contacts"
+                + " SET contact_last_updated_timestamp"
+                + " = " + System.currentTimeMillis());
+
+        db.execSQL("CREATE INDEX contacts_contact_last_updated_timestamp_index "
+                + "ON contacts(contact_last_updated_timestamp)");
+
+        // New deleted contacts table.
+        db.execSQL("CREATE TABLE deleted_contacts (" +
+                "contact_id INTEGER PRIMARY KEY," +
+                "contact_deleted_timestamp INTEGER NOT NULL default 0"
+                + ");");
+
+        db.execSQL("CREATE INDEX deleted_contacts_contact_deleted_timestamp_index "
+                + "ON deleted_contacts(contact_deleted_timestamp)");
+    }
+
     public String extractHandleFromEmailAddress(String email) {
         Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(email);
         if (tokens.length == 0) {
@@ -4041,6 +4082,8 @@
                     "contacts_has_phone_index", "9000 500");
             updateIndexStats(db, Tables.CONTACTS,
                     "contacts_name_raw_contact_id_index", "9000 1");
+            updateIndexStats(db, Tables.CONTACTS, MoreDatabaseUtils.buildIndexName(Tables.CONTACTS,
+                    Contacts.CONTACT_LAST_UPDATED_TIMESTAMP), "9000 10");
 
             updateIndexStats(db, Tables.RAW_CONTACTS,
                     "raw_contacts_contact_id_index", "10000 2");
@@ -4188,6 +4231,7 @@
         db.execSQL("DELETE FROM " + Tables.CALLS + ";");
         db.execSQL("DELETE FROM " + Tables.DIRECTORIES + ";");
         db.execSQL("DELETE FROM " + Tables.SEARCH_INDEX + ";");
+        db.execSQL("DELETE FROM " + Tables.DELETED_CONTACTS + ";");
 
         initializeCache(db);
 
@@ -4834,29 +4878,6 @@
     }
 
     /**
-     * Delete the aggregate contact if it has no constituent raw contacts other
-     * than the supplied one.
-     */
-    public void removeContactIfSingleton(long rawContactId) {
-        SQLiteDatabase db = getWritableDatabase();
-
-        // Obtain contact ID from the supplied raw contact ID
-        String contactIdFromRawContactId = "(SELECT " + RawContacts.CONTACT_ID + " FROM "
-                + Tables.RAW_CONTACTS + " WHERE " + RawContacts._ID + "=" + rawContactId + ")";
-
-        // Find other raw contacts in the same aggregate contact
-        String otherRawContacts = "(SELECT contacts1." + RawContacts._ID + " FROM "
-                + Tables.RAW_CONTACTS + " contacts1 JOIN " + Tables.RAW_CONTACTS + " contacts2 ON ("
-                + "contacts1." + RawContacts.CONTACT_ID + "=contacts2." + RawContacts.CONTACT_ID
-                + ") WHERE contacts1." + RawContacts._ID + "!=" + rawContactId + ""
-                + " AND contacts2." + RawContacts._ID + "=" + rawContactId + ")";
-
-        db.execSQL("DELETE FROM " + Tables.CONTACTS
-                + " WHERE " + Contacts._ID + "=" + contactIdFromRawContactId
-                + " AND NOT EXISTS " + otherRawContacts + ";");
-    }
-
-    /**
      * Returns the value from the {@link Tables#PROPERTIES} table.
      */
     public String getProperty(String key, String defaultValue) {
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index cf9068a..e18117d 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -142,6 +142,8 @@
 import com.android.providers.contacts.aggregation.ContactAggregator.AggregationSuggestionParameter;
 import com.android.providers.contacts.aggregation.ProfileAggregator;
 import com.android.providers.contacts.aggregation.util.CommonNicknameCache;
+import com.android.providers.contacts.database.ContactsTableUtil;
+import com.android.providers.contacts.database.DeletedContactsTableUtil;
 import com.android.providers.contacts.util.Clock;
 import com.android.providers.contacts.util.DbQueryUtils;
 import com.android.providers.contacts.util.NeededForTesting;
@@ -194,6 +196,7 @@
     private static final int BACKGROUND_TASK_UPDATE_DIRECTORIES = 8;
     private static final int BACKGROUND_TASK_CHANGE_LOCALE = 9;
     private static final int BACKGROUND_TASK_CLEANUP_PHOTOS = 10;
+    private static final int BACKGROUND_TASK_CLEAN_DELETE_LOG = 11;
 
     /** Default for the maximum number of returned aggregation suggestions. */
     private static final int DEFAULT_MAX_SUGGESTIONS = 5;
@@ -369,6 +372,9 @@
     private static final int DISPLAY_PHOTO_ID = 22000;
     private static final int PHOTO_DIMENSIONS = 22001;
 
+    private static final int DELETED_CONTACTS = 23000;
+    private static final int DELETED_CONTACTS_ID = 23001;
+
     // Inserts into URIs in this map will direct to the profile database if the parent record's
     // value (looked up from the ContentValues object with the key specified by the value in this
     // map) is in the profile ID-space (see {@link ProfileDatabaseHelper#PROFILE_ID_SPACE}).
@@ -577,6 +583,7 @@
             .add(Contacts.STARRED)
             .add(Contacts.TIMES_CONTACTED)
             .add(Contacts.HAS_PHONE_NUMBER)
+            .add(Contacts.CONTACT_LAST_UPDATED_TIMESTAMP)
             .build();
 
     private static final ProjectionMap sContactsPresenceColumns = ProjectionMap.builder()
@@ -906,6 +913,11 @@
             .add(Groups.SYNC4)
             .build();
 
+    private static final ProjectionMap sDeletedContactsProjectionMap = ProjectionMap.builder()
+            .add(ContactsContract.DeletedContacts.CONTACT_ID)
+            .add(ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP)
+            .build();
+
     /**
      * Contains {@link Groups} columns along with summary details.
      *
@@ -1237,6 +1249,9 @@
 
         matcher.addURI(ContactsContract.AUTHORITY, "display_photo/#", DISPLAY_PHOTO_ID);
         matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS);
+
+        matcher.addURI(ContactsContract.AUTHORITY, "deleted_contacts", DELETED_CONTACTS);
+        matcher.addURI(ContactsContract.AUTHORITY, "deleted_contacts/#", DELETED_CONTACTS_ID);
     }
 
     private static class DirectoryInfo {
@@ -1628,6 +1643,11 @@
                     break;
                 }
             }
+
+            case BACKGROUND_TASK_CLEAN_DELETE_LOG: {
+                final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
+                DeletedContactsTableUtil.deleteOldLogs(db);
+            }
         }
     }
 
@@ -2286,6 +2306,9 @@
             db.execSQL(mSb.toString());
         }
 
+        final Set<Long> changedRawContacts = mTransactionContext.get().getChangedRawContactIds();
+        ContactsTableUtil.updateContactLastUpdate(db, changedRawContacts);
+
         // Update sync states.
         for (Map.Entry<Long, Object> entry : mTransactionContext.get().getUpdatedSyncStates()) {
             long id = entry.getKey();
@@ -2707,9 +2730,7 @@
         DataRowHandler rowHandler = getDataRowHandler(mimeType);
         final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
         id = rowHandler.insert(db, mTransactionContext.get(), rawContactId, mValues);
-        if (!callerIsSyncAdapter) {
-            mTransactionContext.get().markRawContactDirty(rawContactId);
-        }
+        mTransactionContext.get().markRawContactDirtyAndChanged(rawContactId, callerIsSyncAdapter);
         mTransactionContext.get().rawContactUpdated(rawContactId);
         return id;
     }
@@ -2932,9 +2953,8 @@
                 String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE);
                 DataRowHandler rowHandler = getDataRowHandler(mimeType);
                 count += rowHandler.delete(db, mTransactionContext.get(), c);
-                if (!callerIsSyncAdapter) {
-                    mTransactionContext.get().markRawContactDirty(rawContactId);
-                }
+                mTransactionContext.get().markRawContactDirtyAndChanged(rawContactId,
+                        callerIsSyncAdapter);
             }
         } finally {
             c.close();
@@ -3026,7 +3046,8 @@
                     if (c.getLong(1) != 0) {
                         final long rawContactId = c.getLong(0);
                         insertDataGroupMembership(rawContactId, result);
-                        mTransactionContext.get().markRawContactDirty(rawContactId);
+                        mTransactionContext.get().markRawContactDirtyAndChanged(rawContactId,
+                                callerIsSyncAdapter);
                     }
                 }
             } finally {
@@ -3617,7 +3638,9 @@
 
         mProviderStatusUpdateNeeded = true;
 
-        return db.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null);
+        int result = ContactsTableUtil.deleteContact(db, contactId);
+        scheduleBackgroundTask(BACKGROUND_TASK_CLEAN_DELETE_LOG);
+        return result;
     }
 
     public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) {
@@ -3640,14 +3663,24 @@
         }
 
         if (callerIsSyncAdapter || rawContactIsLocal(rawContactId)) {
+
+            // When a raw contact is deleted, a sqlite trigger deletes the parent contact.
+            // TODO: all contact deletes was consolidated into ContactTableUtil but this one can't
+            // because it's in a trigger.  Consider removing trigger and replacing with java code.
+            // This has to happen before the raw contact is deleted since it relies on the number
+            // of raw contacts.
+            ContactsTableUtil.deleteContactIfSingleton(db, rawContactId);
+
             db.delete(Tables.PRESENCE,
                     PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null);
             int count = db.delete(Tables.RAW_CONTACTS,
                     RawContacts._ID + "=" + rawContactId, null);
+
             mAggregator.get().updateAggregateData(mTransactionContext.get(), contactId);
+            mTransactionContext.get().markRawContactChangedOrDeletedOrInserted(rawContactId);
             return count;
         } else {
-            mDbHelper.get().removeContactIfSingleton(rawContactId);
+            ContactsTableUtil.deleteContactIfSingleton(db, rawContactId);
             return markRawContactAsDeleted(db, rawContactId, callerIsSyncAdapter);
         }
     }
@@ -4350,6 +4383,7 @@
                 // and change accounts at the same time.)
                 mTransactionContext.get().rawContactInserted(rawContactId, accountId);
             }
+            mTransactionContext.get().markRawContactChangedOrDeletedOrInserted(rawContactId);
         }
         return count;
     }
@@ -4487,6 +4521,8 @@
                 values, Contacts.TIMES_CONTACTED);
         ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED,
                 values, Contacts.STARRED);
+        mValues.put(Contacts.CONTACT_LAST_UPDATED_TIMESTAMP,
+                Clock.getInstance().currentTimeMillis());
 
         int rslt = db.update(Tables.CONTACTS, mValues, Contacts._ID + "=?",
                 mSelectionArgs1);
@@ -6178,6 +6214,21 @@
                 return completeName(uri, projection);
             }
 
+            case DELETED_CONTACTS: {
+                qb.setTables(Tables.DELETED_CONTACTS);
+                qb.setProjectionMap(sDeletedContactsProjectionMap);
+                break;
+            }
+
+            case DELETED_CONTACTS_ID: {
+                String id = uri.getLastPathSegment();
+                qb.setTables(Tables.DELETED_CONTACTS);
+                qb.setProjectionMap(sDeletedContactsProjectionMap);
+                qb.appendWhere(ContactsContract.DeletedContacts.CONTACT_ID + "=?");
+                selectionArgs = insertSelectionArg(selectionArgs, id);
+                break;
+            }
+
             default:
                 return mLegacyApiSupport.query(uri, projection, selection, selectionArgs,
                         sortOrder, limit);
diff --git a/src/com/android/providers/contacts/DataRowHandler.java b/src/com/android/providers/contacts/DataRowHandler.java
index 0366532..a20da06 100644
--- a/src/com/android/providers/contacts/DataRowHandler.java
+++ b/src/com/android/providers/contacts/DataRowHandler.java
@@ -162,9 +162,7 @@
             txContext.invalidateSearchIndexForRawContact(rawContactId);
         }
 
-        if (!callerIsSyncAdapter) {
-            txContext.markRawContactDirty(rawContactId);
-        }
+        txContext.markRawContactDirtyAndChanged(rawContactId, callerIsSyncAdapter);
 
         return true;
     }
diff --git a/src/com/android/providers/contacts/TransactionContext.java b/src/com/android/providers/contacts/TransactionContext.java
index 2bbacf0..d8c93ef 100644
--- a/src/com/android/providers/contacts/TransactionContext.java
+++ b/src/com/android/providers/contacts/TransactionContext.java
@@ -35,6 +35,11 @@
     private HashMap<Long, Long> mInsertedRawContactsAccounts;
     private HashSet<Long> mUpdatedRawContacts;
     private HashSet<Long> mDirtyRawContacts;
+    // Set used to track what has been changed and deleted. This is needed so we can update the
+    // contact last touch timestamp.  Dirty set above is only set when sync adapter is false.
+    // {@see android.provider.ContactsContract#CALLER_IS_SYNCADAPTER}. While the set below will
+    // contain all changed contacts.
+    private HashSet<Long> mChangedRawContacts;
     private HashSet<Long> mStaleSearchIndexRawContacts;
     private HashSet<Long> mStaleSearchIndexContacts;
     private HashMap<Long, Object> mUpdatedSyncStates;
@@ -50,6 +55,8 @@
     public void rawContactInserted(long rawContactId, long accountId) {
         if (mInsertedRawContactsAccounts == null) mInsertedRawContactsAccounts = Maps.newHashMap();
         mInsertedRawContactsAccounts.put(rawContactId, accountId);
+
+        markRawContactChangedOrDeletedOrInserted(rawContactId);
     }
 
     public void rawContactUpdated(long rawContactId) {
@@ -57,9 +64,22 @@
         mUpdatedRawContacts.add(rawContactId);
     }
 
-    public void markRawContactDirty(long rawContactId) {
-        if (mDirtyRawContacts == null) mDirtyRawContacts = Sets.newHashSet();
-        mDirtyRawContacts.add(rawContactId);
+    public void markRawContactDirtyAndChanged(long rawContactId, boolean isSyncAdapter) {
+        if (!isSyncAdapter) {
+            if (mDirtyRawContacts == null) {
+                mDirtyRawContacts = Sets.newHashSet();
+            }
+            mDirtyRawContacts.add(rawContactId);
+        }
+
+        markRawContactChangedOrDeletedOrInserted(rawContactId);
+    }
+
+    public void markRawContactChangedOrDeletedOrInserted(long rawContactId) {
+        if (mChangedRawContacts == null) {
+            mChangedRawContacts = Sets.newHashSet();
+        }
+        mChangedRawContacts.add(rawContactId);
     }
 
     public void syncStateUpdated(long rowId, Object data) {
@@ -92,6 +112,11 @@
         return mDirtyRawContacts;
     }
 
+    public Set<Long> getChangedRawContactIds() {
+        if (mChangedRawContacts == null) mChangedRawContacts = Sets.newHashSet();
+        return mChangedRawContacts;
+    }
+
     public Set<Long> getStaleSearchIndexRawContactIds() {
         if (mStaleSearchIndexRawContacts == null) mStaleSearchIndexRawContacts = Sets.newHashSet();
         return mStaleSearchIndexRawContacts;
@@ -122,6 +147,7 @@
         mUpdatedRawContacts = null;
         mUpdatedSyncStates = null;
         mDirtyRawContacts = null;
+        mChangedRawContacts = null;
     }
 
     public void clearSearchIndexUpdates() {
diff --git a/src/com/android/providers/contacts/aggregation/ContactAggregator.java b/src/com/android/providers/contacts/aggregation/ContactAggregator.java
index baae2e5..6c53fa0 100644
--- a/src/com/android/providers/contacts/aggregation/ContactAggregator.java
+++ b/src/com/android/providers/contacts/aggregation/ContactAggregator.java
@@ -63,6 +63,9 @@
 import com.android.providers.contacts.aggregation.util.CommonNicknameCache;
 import com.android.providers.contacts.aggregation.util.ContactMatcher;
 import com.android.providers.contacts.aggregation.util.ContactMatcher.MatchScore;
+import com.android.providers.contacts.database.ContactsTableUtil;
+import com.android.providers.contacts.util.Clock;
+
 import com.google.android.collect.Maps;
 
 import java.util.ArrayList;
@@ -143,7 +146,6 @@
     private SQLiteStatement mAggregatedPresenceReplace;
     private SQLiteStatement mPresenceContactIdUpdate;
     private SQLiteStatement mRawContactCountQuery;
-    private SQLiteStatement mContactDelete;
     private SQLiteStatement mAggregatedPresenceDelete;
     private SQLiteStatement mMarkForAggregation;
     private SQLiteStatement mPhotoIdUpdate;
@@ -300,10 +302,6 @@
                 " WHERE " + RawContacts.CONTACT_ID + "=?"
                         + " AND " + RawContacts._ID + "<>?");
 
-        mContactDelete = db.compileStatement(
-                "DELETE FROM " + Tables.CONTACTS +
-                " WHERE " + Contacts._ID + "=?");
-
         mAggregatedPresenceDelete = db.compileStatement(
                 "DELETE FROM " + Tables.AGGREGATED_PRESENCE +
                 " WHERE " + AggregatedPresenceColumns.CONTACT_ID + "=?");
@@ -778,8 +776,7 @@
             // Joining with an existing aggregate
             if (currentContactContentsCount == 0) {
                 // Delete a previous aggregate if it only contained this raw contact
-                mContactDelete.bindLong(1, currentContactId);
-                mContactDelete.execute();
+                ContactsTableUtil.deleteContact(db, currentContactId);
 
                 mAggregatedPresenceDelete.bindLong(1, currentContactId);
                 mAggregatedPresenceDelete.execute();
@@ -1763,7 +1760,8 @@
                         + Contacts.TIMES_CONTACTED + "=?, "
                         + Contacts.STARRED + "=?, "
                         + Contacts.HAS_PHONE_NUMBER + "=?, "
-                        + Contacts.LOOKUP_KEY + "=? " +
+                        + Contacts.LOOKUP_KEY + "=?, "
+                        + Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + "=? " +
                 " WHERE " + Contacts._ID + "=?";
 
         String INSERT_SQL =
@@ -1777,8 +1775,10 @@
                         + Contacts.TIMES_CONTACTED + ", "
                         + Contacts.STARRED + ", "
                         + Contacts.HAS_PHONE_NUMBER + ", "
-                        + Contacts.LOOKUP_KEY + ") " +
-                " VALUES (?,?,?,?,?,?,?,?,?,?)";
+                        + Contacts.LOOKUP_KEY + ", "
+                        + Contacts.CONTACT_LAST_UPDATED_TIMESTAMP
+                        + ") " +
+                " VALUES (?,?,?,?,?,?,?,?,?,?,?)";
 
         int NAME_RAW_CONTACT_ID = 1;
         int PHOTO_ID = 2;
@@ -1790,7 +1790,8 @@
         int STARRED = 8;
         int HAS_PHONE_NUMBER = 9;
         int LOOKUP_KEY = 10;
-        int CONTACT_ID = 11;
+        int CONTACT_LAST_UPDATED_TIMESTAMP = 11;
+        int CONTACT_ID = 12;
     }
 
     /**
@@ -1954,6 +1955,8 @@
                 hasPhoneNumber);
         statement.bindString(ContactReplaceSqlStatement.LOOKUP_KEY,
                 Uri.encode(lookupKey.toString()));
+        statement.bindLong(ContactReplaceSqlStatement.CONTACT_LAST_UPDATED_TIMESTAMP,
+                Clock.getInstance().currentTimeMillis());
     }
 
     /**
diff --git a/src/com/android/providers/contacts/database/ContactsTableUtil.java b/src/com/android/providers/contacts/database/ContactsTableUtil.java
new file mode 100644
index 0000000..7a0f425
--- /dev/null
+++ b/src/com/android/providers/contacts/database/ContactsTableUtil.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.database;
+
+import static android.provider.ContactsContract.Contacts;
+import static com.android.providers.contacts.ContactsDatabaseHelper.Tables;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.provider.ContactsContract;
+
+import com.android.common.io.MoreCloseables;
+import com.android.providers.contacts.util.Clock;
+
+import java.util.Set;
+
+/**
+ * Methods for operating on the contacts table.
+ */
+public class ContactsTableUtil {
+
+    /**
+     * Drop indexes if present.  Create indexes.
+     *
+     * @param db The sqlite database instance.
+     */
+    public static void createIndexes(SQLiteDatabase db) {
+        final String table = Tables.CONTACTS;
+
+        db.execSQL("CREATE INDEX contacts_has_phone_index ON " + table + " (" +
+                Contacts.HAS_PHONE_NUMBER +
+                ");");
+
+        db.execSQL("CREATE INDEX contacts_name_raw_contact_id_index ON " + table + " (" +
+                Contacts.NAME_RAW_CONTACT_ID +
+                ");");
+
+        db.execSQL(MoreDatabaseUtils.buildCreateIndexSql(table,
+                Contacts.CONTACT_LAST_UPDATED_TIMESTAMP));
+    }
+
+    /**
+     * Refreshes the last updated timestamp of the contact with the current time.
+     *
+     * @param db The sqlite database instance.
+     * @param rawContactIds A set of raw contacts ids to refresh the contact for.
+     */
+    public static void updateContactLastUpdate(SQLiteDatabase db, Set<Long> rawContactIds) {
+        if (rawContactIds.isEmpty()) {
+            return;
+        }
+
+        final Long[] bindArgs = rawContactIds.toArray(new Long[rawContactIds.size()]);
+        db.execSQL(buildUpdateLastUpdateSql(rawContactIds), bindArgs);
+    }
+
+    /**
+     * Build a sql to update the last updated timestamp for contacts.
+     *
+     * @param rawContactIds The raw contact ids that contacts should be updated for.
+     * @return The update sql statement.
+     */
+    private static String buildUpdateLastUpdateSql(Set<Long> rawContactIds) {
+        final String bindSql = MoreDatabaseUtils.buildBindArgString(rawContactIds.size());
+        final String sql = "UPDATE " + Tables.CONTACTS
+                + " SET " + Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + " = "
+                + Clock.getInstance().currentTimeMillis()
+                + " WHERE " + Contacts._ID + " IN ( "
+                + "  SELECT " + ContactsContract.RawContacts.CONTACT_ID
+                + "  FROM " + Tables.RAW_CONTACTS
+                + "  WHERE " + ContactsContract.RawContacts._ID + " IN (" + bindSql + ") "
+                + ")";
+        return sql;
+    }
+
+    /**
+     * Delete a contact identified by the contact id.
+     *
+     * @param db The sqlite database instance.
+     * @param contactId The contact id to delete.
+     * @return The number of records deleted.
+     */
+    public static int deleteContact(SQLiteDatabase db, long contactId) {
+        DeletedContactsTableUtil.insertDeletedContact(db, contactId);
+        return db.delete(Tables.CONTACTS, Contacts._ID + " = ?", new String[]{contactId + ""});
+    }
+
+    /**
+     * Delete the aggregate contact if it has no constituent raw contacts other than the supplied
+     * one.
+     */
+    public static void deleteContactIfSingleton(SQLiteDatabase db, long rawContactId) {
+        // This query will find a contact id if the contact has a raw contacts other than the one
+        // passed in.
+        final String sql = "select " + ContactsContract.RawContacts.CONTACT_ID + ", count(1)"
+                + " from " + Tables.RAW_CONTACTS
+                + " where " + ContactsContract.RawContacts.CONTACT_ID + " ="
+                + "  (select " + ContactsContract.RawContacts.CONTACT_ID
+                + "   from " + Tables.RAW_CONTACTS
+                + "   where " + ContactsContract.RawContacts._ID + " = ?)"
+                + " group by " + ContactsContract.RawContacts.CONTACT_ID;
+        final Cursor cursor = db.rawQuery(sql, new String[]{rawContactId + ""});
+        try {
+            if (cursor.moveToNext()) {
+                long contactId = cursor.getLong(0);
+                long numRawContacts = cursor.getLong(1);
+
+                if (numRawContacts == 1) {
+                    // Only one raw contact, we can delete the parent.
+                    deleteContact(db, contactId);
+                }
+            }
+        } finally {
+            MoreCloseables.closeQuietly(cursor);
+        }
+    }
+}
diff --git a/src/com/android/providers/contacts/database/DeletedContactsTableUtil.java b/src/com/android/providers/contacts/database/DeletedContactsTableUtil.java
new file mode 100644
index 0000000..31cf885
--- /dev/null
+++ b/src/com/android/providers/contacts/database/DeletedContactsTableUtil.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.database;
+
+import android.content.ContentValues;
+import android.database.sqlite.SQLiteDatabase;
+import android.provider.ContactsContract;
+
+import com.android.providers.contacts.ContactsDatabaseHelper;
+import com.android.providers.contacts.util.Clock;
+
+/**
+ * Methods for operating on the deleted_contacts table.
+ */
+public class DeletedContactsTableUtil {
+
+    /**
+     * Create deleted_contacts tables and indexes.
+     *
+     * @param db The sqlite database instance.
+     */
+    public static void create(SQLiteDatabase db) {
+        // Deleted contacts log
+        db.execSQL("CREATE TABLE " + ContactsDatabaseHelper.Tables.DELETED_CONTACTS + " (" +
+                ContactsContract.DeletedContacts.CONTACT_ID + " INTEGER PRIMARY KEY," +
+                ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP +
+                " INTEGER NOT NULL default 0"
+                + ");");
+
+        db.execSQL(MoreDatabaseUtils.buildCreateIndexSql(
+                ContactsDatabaseHelper.Tables.DELETED_CONTACTS,
+                ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP));
+    }
+
+    /**
+     * Inserts a deleted contact log record.
+     *
+     * @param db The SQLiteDatabase instance.
+     * @param contactId The contact id to insert.
+     * @return The row id
+     */
+    public static long insertDeletedContact(SQLiteDatabase db, long contactId) {
+        ContentValues values = new ContentValues();
+        values.put(ContactsContract.DeletedContacts.CONTACT_ID, contactId);
+        values.put(ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP,
+                Clock.getInstance().currentTimeMillis());
+        // a.k.a upsert
+        return db.insertWithOnConflict(ContactsDatabaseHelper.Tables.DELETED_CONTACTS, null, values,
+                SQLiteDatabase.CONFLICT_REPLACE);
+    }
+
+    /**
+     * Deletes old log records.
+     *
+     * @param db The database instance to use.
+     */
+    public static int deleteOldLogs(SQLiteDatabase db) {
+
+        long time = Clock.getInstance().currentTimeMillis() -
+                ContactsContract.DeletedContacts.DAYS_KEPT_MILLISECONDS;
+
+        String[] args = new String[]{time + ""};
+
+        return db.delete(ContactsDatabaseHelper.Tables.DELETED_CONTACTS,
+                ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP + " < ?", args);
+    }
+}
diff --git a/src/com/android/providers/contacts/database/MoreDatabaseUtils.java b/src/com/android/providers/contacts/database/MoreDatabaseUtils.java
new file mode 100644
index 0000000..a03fc25
--- /dev/null
+++ b/src/com/android/providers/contacts/database/MoreDatabaseUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.database;
+
+/**
+ * Static methods for database operations.
+ */
+public class MoreDatabaseUtils {
+
+    /**
+     * Builds a CREATE INDEX ddl statement for a given table and field.
+     *
+     * @param table The table name.
+     * @param field The field to index.
+     * @return The create index sql statement.
+     */
+    public static String buildCreateIndexSql(String table, String field) {
+        return "CREATE INDEX " + buildIndexName(table, field) + " ON " + table
+                + "(" + field + ")";
+    }
+
+    /**
+     * Builds a DROP INDEX ddl statement for a given table and field.
+     *
+     * @param table The table name that was originally used to create the index.
+     * @param field The field that was originally used to create the index.
+     * @return The drop index sql statement.
+     */
+    public static String buildDropIndexSql(String table, String field) {
+        return "DROP INDEX IF EXISTS " + buildIndexName(table, field);
+    }
+
+    /**
+     * The index is created with a name using the following convention:
+     * <p>
+     * [table name]_[field name]_index
+     */
+    public static String buildIndexName(String table, String field) {
+        return table + "_" + field + "_index";
+    }
+
+    /**
+     * Build a bind arg where clause.
+     * <p>
+     * e.g. Calling this method with value of 4 results in:
+     * <p>
+     * "?,?,?,?"
+     *
+     * @param numArgs The number of arguments.
+     * @return A string that can be used for bind args in a sql where clause.
+     */
+    public static String buildBindArgString(int numArgs) {
+        final StringBuilder sb = new StringBuilder();
+        String delimiter = "";
+        for (int i = 0; i < numArgs; i++) {
+            sb.append(delimiter).append("?");
+            delimiter = ",";
+        }
+        return sb.toString();
+    }
+}
diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
index 8e763f1..a67785c 100644
--- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
@@ -59,6 +59,10 @@
 import android.util.Log;
 
 import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
+import com.android.providers.contacts.testutil.CommonDatabaseUtils;
+import com.android.providers.contacts.testutil.DataUtil;
+import com.android.providers.contacts.testutil.RawContactUtil;
+import com.android.providers.contacts.testutil.TestUtil;
 import com.android.providers.contacts.util.Hex;
 import com.android.providers.contacts.util.MockClock;
 import com.google.android.collect.Sets;
@@ -151,38 +155,6 @@
         return mActor.provider;
     }
 
-    protected Uri maybeAddAccountQueryParameters(Uri uri, Account account) {
-        if (account == null) {
-            return uri;
-        }
-        return uri.buildUpon()
-                .appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
-                .appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type)
-                .build();
-    }
-
-    protected long createRawContact() {
-        return createRawContact(null);
-    }
-
-    protected long createRawContactWithName() {
-        return createRawContactWithName(null);
-    }
-
-    protected long createRawContactWithName(Account account) {
-        return createRawContactWithName("John", "Doe", account);
-    }
-
-    protected long createRawContactWithName(String firstName, String lastName) {
-        return createRawContactWithName(firstName, lastName, null);
-    }
-
-    protected long createRawContactWithName(String firstName, String lastName, Account account) {
-        long rawContactId = createRawContact(account);
-        insertStructuredName(rawContactId, firstName, lastName);
-        return rawContactId;
-    }
-
     protected Uri setCallerIsSyncAdapter(Uri uri, Account account) {
         if (account == null) {
             return uri;
@@ -194,14 +166,6 @@
         return builder.build();
     }
 
-    protected long createRawContact(Account account, String... extras) {
-        ContentValues values = new ContentValues();
-        extrasVarArgsToValues(values, extras);
-        final Uri uri = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account);
-        Uri contactUri = mResolver.insert(uri, values);
-        return ContentUris.parseId(contactUri);
-    }
-
     protected int updateItem(Uri uri, long id, String... extras) {
         Uri itemUri = ContentUris.withAppendedId(uri, id);
         return updateItem(itemUri, extras);
@@ -209,17 +173,10 @@
 
     protected int updateItem(Uri uri, String... extras) {
         ContentValues values = new ContentValues();
-        extrasVarArgsToValues(values, extras);
+        CommonDatabaseUtils.extrasVarArgsToValues(values, extras);
         return mResolver.update(uri, values, null, null);
     }
 
-    private static void extrasVarArgsToValues(ContentValues values, String... extras) {
-        for (int i = 0; i < extras.length; ) {
-            values.put(extras[i], extras[i + 1]);
-            i += 2;
-        }
-    }
-
     protected long createGroup(Account account, String sourceId, String title) {
         return createGroup(account, sourceId, title, 1, false, false);
     }
@@ -241,7 +198,7 @@
         values.put(Groups.GROUP_VISIBLE, visible);
         values.put(Groups.AUTO_ADD, autoAdd ? 1 : 0);
         values.put(Groups.FAVORITES, favorite ? 1 : 0);
-        final Uri uri = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account);
+        final Uri uri = TestUtil.maybeAddAccountQueryParameters(Groups.CONTENT_URI, account);
         return ContentUris.parseId(mResolver.insert(uri, values));
     }
 
@@ -263,32 +220,6 @@
         mResolver.insert(Settings.CONTENT_URI, values);
     }
 
-    protected Uri insertStructuredName(long rawContactId, String givenName, String familyName) {
-        ContentValues values = new ContentValues();
-        StringBuilder sb = new StringBuilder();
-        if (givenName != null) {
-            sb.append(givenName);
-        }
-        if (givenName != null && familyName != null) {
-            sb.append(" ");
-        }
-        if (familyName != null) {
-            sb.append(familyName);
-        }
-        values.put(StructuredName.DISPLAY_NAME, sb.toString());
-        values.put(StructuredName.GIVEN_NAME, givenName);
-        values.put(StructuredName.FAMILY_NAME, familyName);
-
-        return insertStructuredName(rawContactId, values);
-    }
-
-    protected Uri insertStructuredName(long rawContactId, ContentValues values) {
-        values.put(Data.RAW_CONTACT_ID, rawContactId);
-        values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
-        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
-        return resultUri;
-    }
-
     protected Uri insertOrganization(long rawContactId, ContentValues values) {
         return insertOrganization(rawContactId, values, false);
     }
@@ -507,21 +438,17 @@
 
     protected Uri insertStreamItem(long rawContactId, ContentValues values, Account account) {
         return mResolver.insert(
-                maybeAddAccountQueryParameters(
-                        Uri.withAppendedPath(
-                                ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
-                                RawContacts.StreamItems.CONTENT_DIRECTORY),
-                        account),
+                TestUtil.maybeAddAccountQueryParameters(Uri.withAppendedPath(
+                        ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
+                        RawContacts.StreamItems.CONTENT_DIRECTORY), account),
                 values);
     }
 
     protected Uri insertStreamItemPhoto(long streamItemId, ContentValues values, Account account) {
         return mResolver.insert(
-                maybeAddAccountQueryParameters(
-                        Uri.withAppendedPath(
-                                ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId),
-                                StreamItems.StreamItemPhotos.CONTENT_DIRECTORY),
-                        account),
+                TestUtil.maybeAddAccountQueryParameters(Uri.withAppendedPath(
+                        ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId),
+                        StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), account),
                 values);
     }
 
@@ -1543,11 +1470,11 @@
 
             final long groupId = createGroup(mAccount, "gsid1", "title1");
 
-            long rawContactId = createRawContact();
+            long rawContactId = RawContactUtil.createRawContact(mResolver);
             insertGroupMembership(rawContactId, groupId);
 
             if (givenName != null || familyName != null) {
-                insertStructuredName(rawContactId, givenName, familyName);
+                DataUtil.insertStructuredName(mResolver, rawContactId, givenName, familyName);
             }
             if (nickname != null) {
                 insertNickname(rawContactId, nickname);
diff --git a/tests/src/com/android/providers/contacts/CallerInfoIntegrationTest.java b/tests/src/com/android/providers/contacts/CallerInfoIntegrationTest.java
index 4c0d2df..78b9ec5 100644
--- a/tests/src/com/android/providers/contacts/CallerInfoIntegrationTest.java
+++ b/tests/src/com/android/providers/contacts/CallerInfoIntegrationTest.java
@@ -23,6 +23,7 @@
 import android.test.suitebuilder.annotation.MediumTest;
 
 import com.android.internal.telephony.CallerInfo;
+import com.android.providers.contacts.testutil.DataUtil;
 
 /**
  * Integration test for {@link CallerInfo} and {@link ContactsProvider2}.
@@ -44,7 +45,7 @@
         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         long rawContactId = ContentUris.parseId(rawContactUri);
 
-        insertStructuredName(rawContactId, "Hot", "Tamale");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Hot", "Tamale");
         insertPhoneNumber(rawContactId, "800-466-4411");
 
         CallerInfo callerInfo = CallerInfo.getCallerInfo(getProvider().getContext(), "18004664411");
diff --git a/tests/src/com/android/providers/contacts/ContactLookupKeyTest.java b/tests/src/com/android/providers/contacts/ContactLookupKeyTest.java
index 08f3a07..047e8ea 100644
--- a/tests/src/com/android/providers/contacts/ContactLookupKeyTest.java
+++ b/tests/src/com/android/providers/contacts/ContactLookupKeyTest.java
@@ -24,6 +24,7 @@
 import android.test.suitebuilder.annotation.MediumTest;
 
 import com.android.providers.contacts.ContactLookupKey.LookupKeySegment;
+import com.android.providers.contacts.testutil.RawContactUtil;
 
 import java.util.ArrayList;
 
@@ -40,8 +41,8 @@
 public class ContactLookupKeyTest extends BaseContactsProvider2Test {
 
     public void testLookupKeyUsingDisplayNameAndNoAccount() {
-        long rawContactId1 = createRawContactWithName("John", "Doe");
-        long rawContactId2 = createRawContactWithName("johndoe", null);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "johndoe", null);
         setAggregationException(
                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
 
@@ -68,13 +69,13 @@
     }
 
     public void testLookupKeyUsingSourceIdAndNoAccount() {
-        long rawContactId1 = createRawContactWithName("John", "Doe");
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.SOURCE_ID, "123");
 
-        long rawContactId2 = createRawContactWithName("johndoe", null);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "johndoe", null);
         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.SOURCE_ID, "4.5.6");
 
-        long rawContactId3 = createRawContactWithName("john", "dough");
+        long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "john", "dough");
         storeValue(RawContacts.CONTENT_URI, rawContactId3, RawContacts.SOURCE_ID, "http://foo?bar");
 
         setAggregationException(
@@ -94,12 +95,12 @@
     }
 
     public void testLookupKeySameSourceIdDifferentAccounts() {
-        long rawContactId1 = createRawContactWithName("Dear", "Doe");
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "Dear", "Doe");
         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.ACCOUNT_TYPE, "foo");
         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.ACCOUNT_NAME, "FOO");
         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.SOURCE_ID, "1");
 
-        long rawContactId2 = createRawContactWithName("Deer", "Dough");
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "Deer", "Dough");
         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.ACCOUNT_TYPE, "bar");
         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.ACCOUNT_NAME, "BAR");
         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.SOURCE_ID, "1");
@@ -125,13 +126,13 @@
     }
 
     public void testLookupKeyChoosingLargestContact() {
-        long rawContactId1 = createRawContactWithName("John", "Doe");
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.SOURCE_ID, "1");
 
-        long rawContactId2 = createRawContactWithName("John", "Doe");
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.SOURCE_ID, "2");
 
-        long rawContactId3 = createRawContactWithName("John", "Doe");
+        long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
         storeValue(RawContacts.CONTENT_URI, rawContactId3, RawContacts.SOURCE_ID, "3");
         setAggregationException(
                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
@@ -165,7 +166,7 @@
     }
 
     public void testGetLookupUri() {
-        long rawContactId1 = createRawContactWithName("John", "Doe");
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.SOURCE_ID, "1");
 
         long contactId = queryContactId(rawContactId1);
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index 3f8b001..da3a125 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -21,6 +21,7 @@
 import android.accounts.Account;
 import android.content.ContentProviderOperation;
 import android.content.ContentProviderResult;
+import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Entity;
@@ -68,7 +69,6 @@
 import android.text.TextUtils;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.providers.contacts.ContactsDatabaseHelper;
 import com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns;
 import com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns;
 import com.android.providers.contacts.ContactsDatabaseHelper.DataUsageStatColumns;
@@ -76,6 +76,13 @@
 import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns;
 import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns;
 import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
+import com.android.providers.contacts.testutil.CommonDatabaseUtils;
+import com.android.providers.contacts.testutil.ContactUtil;
+import com.android.providers.contacts.testutil.DataUtil;
+import com.android.providers.contacts.testutil.DatabaseAsserts;
+import com.android.providers.contacts.testutil.DeletedContactUtil;
+import com.android.providers.contacts.testutil.RawContactUtil;
+import com.android.providers.contacts.testutil.TestUtil;
 import com.android.providers.contacts.tests.R;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Sets;
@@ -86,6 +93,7 @@
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
@@ -102,8 +110,7 @@
 @LargeTest
 public class ContactsProvider2Test extends BaseContactsProvider2Test {
 
-    private static final Account ACCOUNT_1 = new Account("account_name_1", "account_type_1");
-    private static final Account ACCOUNT_2 = new Account("account_name_2", "account_type_2");
+    private static final String TAG = ContactsProvider2Test.class.getSimpleName();
 
     public void testContactsProjection() {
         assertProjection(Contacts.CONTENT_URI, new String[]{
@@ -140,6 +147,7 @@
                 Contacts.CONTACT_STATUS_RES_PACKAGE,
                 Contacts.CONTACT_STATUS_LABEL,
                 Contacts.CONTACT_STATUS_ICON,
+                Contacts.CONTACT_LAST_UPDATED_TIMESTAMP
         });
     }
 
@@ -178,6 +186,7 @@
                 Contacts.CONTACT_STATUS_RES_PACKAGE,
                 Contacts.CONTACT_STATUS_LABEL,
                 Contacts.CONTACT_STATUS_ICON,
+                Contacts.CONTACT_LAST_UPDATED_TIMESTAMP,
                 DataUsageStatColumns.TIMES_USED,
                 DataUsageStatColumns.LAST_TIME_USED,
         });
@@ -220,6 +229,7 @@
                 Contacts.CONTACT_STATUS_RES_PACKAGE,
                 Contacts.CONTACT_STATUS_LABEL,
                 Contacts.CONTACT_STATUS_ICON,
+                Contacts.CONTACT_LAST_UPDATED_TIMESTAMP,
                 DataUsageStatColumns.TIMES_USED,
                 DataUsageStatColumns.LAST_TIME_USED,
                 Phone.NUMBER,
@@ -264,7 +274,7 @@
                 Contacts.CONTACT_STATUS_RES_PACKAGE,
                 Contacts.CONTACT_STATUS_LABEL,
                 Contacts.CONTACT_STATUS_ICON,
-
+                Contacts.CONTACT_LAST_UPDATED_TIMESTAMP,
                 SearchSnippetColumns.SNIPPET,
         });
     }
@@ -386,6 +396,7 @@
                 Contacts.CONTACT_STATUS_RES_PACKAGE,
                 Contacts.CONTACT_STATUS_LABEL,
                 Contacts.CONTACT_STATUS_ICON,
+                Contacts.CONTACT_LAST_UPDATED_TIMESTAMP,
                 GroupMembership.GROUP_SOURCE_ID,
         });
     }
@@ -460,6 +471,7 @@
                 Contacts.CONTACT_STATUS_RES_PACKAGE,
                 Contacts.CONTACT_STATUS_LABEL,
                 Contacts.CONTACT_STATUS_ICON,
+                Contacts.CONTACT_LAST_UPDATED_TIMESTAMP,
                 GroupMembership.GROUP_SOURCE_ID,
         });
     }
@@ -550,6 +562,7 @@
                 Contacts.CONTACT_STATUS_RES_PACKAGE,
                 Contacts.CONTACT_STATUS_LABEL,
                 Contacts.CONTACT_STATUS_ICON,
+                Contacts.CONTACT_LAST_UPDATED_TIMESTAMP,
                 GroupMembership.GROUP_SOURCE_ID,
         });
     }
@@ -770,7 +783,7 @@
     public void testDataDirectoryWithLookupUri() {
         ContentValues values = new ContentValues();
 
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         insertPhoneNumber(rawContactId, "555-GOOG-411");
         insertEmail(rawContactId, "google@android.com");
 
@@ -817,12 +830,12 @@
         Account account1 = new Account("act1", "actype1");
         Account account2 = new Account("act2", "actype2");
 
-        long rawContactId1 = createRawContactWithName(account1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, account1);
         insertImHandle(rawContactId1, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk");
         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", StatusUpdates.IDLE, "Busy", 90,
                 StatusUpdates.CAPABILITY_HAS_CAMERA, false);
 
-        long rawContactId2 = createRawContact(account2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, account2);
         setAggregationException(
                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
 
@@ -839,12 +852,12 @@
         Account account1 = new Account("act1", "actype1");
         Account account2 = new Account("act2", "actype2");
 
-        long rawContactId1 = createRawContactWithName(account1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, account1);
         insertImHandle(rawContactId1, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk");
         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", StatusUpdates.IDLE, "Busy", 90,
                 StatusUpdates.CAPABILITY_HAS_CAMERA, false);
 
-        long rawContactId2 = createRawContact(account2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, account2);
         setAggregationException(
                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
 
@@ -931,7 +944,7 @@
     }
 
     public void testDataInsert() {
-        long rawContactId = createRawContactWithName("John", "Doe");
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
 
         ContentValues values = new ContentValues();
         putDataValues(values, rawContactId);
@@ -960,13 +973,13 @@
     public void testRawContactDataQuery() {
         Account account1 = new Account("a", "b");
         Account account2 = new Account("c", "d");
-        long rawContactId1 = createRawContact(account1);
-        Uri dataUri1 = insertStructuredName(rawContactId1, "John", "Doe");
-        long rawContactId2 = createRawContact(account2);
-        Uri dataUri2 = insertStructuredName(rawContactId2, "Jane", "Doe");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, account1);
+        Uri dataUri1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "John", "Doe");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, account2);
+        Uri dataUri2 = DataUtil.insertStructuredName(mResolver, rawContactId2, "Jane", "Doe");
 
-        Uri uri1 = maybeAddAccountQueryParameters(dataUri1, account1);
-        Uri uri2 = maybeAddAccountQueryParameters(dataUri2, account2);
+        Uri uri1 = TestUtil.maybeAddAccountQueryParameters(dataUri1, account1);
+        Uri uri2 = TestUtil.maybeAddAccountQueryParameters(dataUri2, account2);
         assertStoredValue(uri1, Data._ID, ContentUris.parseId(dataUri1)) ;
         assertStoredValue(uri2, Data._ID, ContentUris.parseId(dataUri2)) ;
     }
@@ -983,7 +996,7 @@
         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         long rawContactId = ContentUris.parseId(rawContactUri);
 
-        insertStructuredName(rawContactId, "Meghan", "Knox");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Meghan", "Knox");
         Uri uri = insertPhoneNumber(rawContactId, "18004664411");
         long phoneId = ContentUris.parseId(uri);
 
@@ -1009,10 +1022,10 @@
     }
 
     public void testPhonesWithMergedContacts() {
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         insertPhoneNumber(rawContactId1, "123456789", true);
 
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         insertPhoneNumber(rawContactId2, "123456789", true);
 
         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
@@ -1048,7 +1061,7 @@
     }
 
     public void testPhonesNormalizedNumber() {
-        final long rawContactId = createRawContact();
+        final long rawContactId = RawContactUtil.createRawContact(mResolver);
 
         // Write both a number and a normalized number. Those should be written as-is
         final ContentValues values = new ContentValues();
@@ -1168,10 +1181,12 @@
                 Phone.CONTENT_FILTER_URI.equals(baseFilterUri)
                         || Callable.CONTENT_FILTER_URI.equals(baseFilterUri));
 
-        final long rawContactId1 = createRawContactWithName("Hot", "Tamale", ACCOUNT_1);
+        final long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "Hot",
+                "Tamale", TestUtil.ACCOUNT_1);
         insertPhoneNumber(rawContactId1, "1-800-466-4411");
 
-        final long rawContactId2 = createRawContactWithName("Chilled", "Guacamole", ACCOUNT_2);
+        final long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "Chilled",
+                "Guacamole", TestUtil.ACCOUNT_2);
         insertPhoneNumber(rawContactId2, "1-800-466-5432");
         insertPhoneNumber(rawContactId2, "0@example.com", false, Phone.TYPE_PAGER);
         insertPhoneNumber(rawContactId2, "1@example.com", false, Phone.TYPE_PAGER);
@@ -1257,10 +1272,10 @@
     }
 
     public void testPhonesFilterSearchParams() {
-        final long rid1 = createRawContactWithName("Dad", null);
+        final long rid1 = RawContactUtil.createRawContactWithName(mResolver, "Dad", null);
         insertPhoneNumber(rid1, "123-456-7890");
 
-        final long rid2 = createRawContactWithName("Mam", null);
+        final long rid2 = RawContactUtil.createRawContactWithName(mResolver, "Mam", null);
         insertPhoneNumber(rid2, "323-123-4567");
 
         // By default, "dad" will match both the display name and the phone number.
@@ -1299,7 +1314,7 @@
         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         long rawContactId = ContentUris.parseId(rawContactUri);
 
-        insertStructuredName(rawContactId, "Hot", "Tamale");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Hot", "Tamale");
         insertPhoneNumber(rawContactId, "18004664411");
 
         // We'll create two lookup records, 18004664411 and +18004664411, and the below lookup
@@ -1340,7 +1355,7 @@
         rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         rawContactId = ContentUris.parseId(rawContactUri);
 
-        insertStructuredName(rawContactId, "Hot", "Tamale");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Hot", "Tamale");
         insertPhoneNumber(rawContactId, "+1-650-861-0000");
 
         values.clear();
@@ -1372,7 +1387,7 @@
         rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         rawContactId = ContentUris.parseId(rawContactUri);
 
-        insertStructuredName(rawContactId, "Hot1", "Tamale");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Hot1", "Tamale");
         insertPhoneNumber(rawContactId, "650-861-0001");
 
         values.clear();
@@ -1392,7 +1407,7 @@
         rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         rawContactId = ContentUris.parseId(rawContactUri);
 
-        insertStructuredName(rawContactId, "Hot2", "Tamale");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Hot2", "Tamale");
         insertPhoneNumber(rawContactId, "861-0002");
 
         values.clear();
@@ -1415,7 +1430,7 @@
         values.put(RawContacts.CUSTOM_RINGTONE, "d");
         values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
         long rawContactId = ContentUris.parseId(mResolver.insert(RawContacts.CONTENT_URI, values));
-        insertStructuredName(rawContactId, "Senor", "Chang");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Senor", "Chang");
         insertPhoneNumber(rawContactId, fullNumber);
 
         // Full number should definitely match.
@@ -1451,7 +1466,7 @@
         values.put(RawContacts.CUSTOM_RINGTONE, "d");
         values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
         long rawContactId = ContentUris.parseId(mResolver.insert(RawContacts.CONTENT_URI, values));
-        insertStructuredName(rawContactId, "Senor", "Chang");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Senor", "Chang");
         insertPhoneNumber(rawContactId, storedNumber);
 
         assertEquals(1, getCount(Uri.withAppendedPath(
@@ -1487,7 +1502,7 @@
             values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
             long rawContactId = ContentUris.parseId(
                     mResolver.insert(RawContacts.CONTENT_URI, values));
-            insertStructuredName(rawContactId, "Senor", "Chang");
+            DataUtil.insertStructuredName(mResolver, rawContactId, "Senor", "Chang");
             insertPhoneNumber(rawContactId, fullNumber);
             insertPhoneNumber(rawContactId, "5103337596");
             insertPhoneNumber(rawContactId, "+19012345678");
@@ -1532,7 +1547,7 @@
         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         long rawContactId = ContentUris.parseId(rawContactUri);
 
-        insertStructuredName(rawContactId, "Hot", "Tamale");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Hot", "Tamale");
         Uri phoneUri = insertPhoneNumber(rawContactId, "18004664411");
 
         Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411");
@@ -1566,11 +1581,11 @@
 
     /** Tests if {@link Callable#CONTENT_URI} returns both phones and sip addresses. */
     public void testCallablesQuery() {
-        long rawContactId1 = createRawContactWithName("Meghan", "Knox");
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "Meghan", "Knox");
         long phoneId1 = ContentUris.parseId(insertPhoneNumber(rawContactId1, "18004664411"));
         long contactId1 = queryContactId(rawContactId1);
 
-        long rawContactId2 = createRawContactWithName("John", "Doe");
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
         long sipAddressId2 = ContentUris.parseId(
                 insertSipAddress(rawContactId2, "sip@example.com"));
         long contactId2 = queryContactId(rawContactId2);
@@ -1612,7 +1627,7 @@
         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         final long rawContactId = ContentUris.parseId(rawContactUri);
 
-        insertStructuredName(rawContactId, "Meghan", "Knox");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Meghan", "Knox");
         final Uri emailUri = insertEmail(rawContactId, "meghan@acme.com");
         final long emailId = ContentUris.parseId(emailUri);
 
@@ -1661,7 +1676,7 @@
     }
 
     public void testEmailsLookupQuery() {
-        long rawContactId = createRawContactWithName("Hot", "Tamale");
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale");
         insertEmail(rawContactId, "tamale@acme.com");
 
         Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "tamale@acme.com");
@@ -1681,11 +1696,13 @@
     }
 
     public void testEmailsFilterQuery() {
-        long rawContactId1 = createRawContactWithName("Hot", "Tamale", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale",
+                TestUtil.ACCOUNT_1);
         insertEmail(rawContactId1, "tamale@acme.com");
         insertEmail(rawContactId1, "tamale@acme.com");
 
-        long rawContactId2 = createRawContactWithName("Hot", "Tamale", ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale",
+                TestUtil.ACCOUNT_2);
         insertEmail(rawContactId2, "tamale@acme.com");
 
         Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tam");
@@ -1714,7 +1731,7 @@
      * Tests if ContactsProvider2 returns addresses according to registration order.
      */
     public void testEmailFilterDefaultSortOrder() {
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         insertEmail(rawContactId1, "address1@email.com");
         insertEmail(rawContactId1, "address2@email.com");
         insertEmail(rawContactId1, "address3@email.com");
@@ -1733,7 +1750,7 @@
      * Tests if ContactsProvider2 returns primary addresses before the other addresses.
      */
     public void testEmailFilterPrimaryAddress() {
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         insertEmail(rawContactId1, "address1@email.com");
         insertEmail(rawContactId1, "address2@email.com", true);
         ContentValues v1 = new ContentValues();
@@ -1750,9 +1767,9 @@
      * other address.
      */
     public void testEmailFilterPrimaryAccount() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, TestUtil.ACCOUNT_1);
         insertEmail(rawContactId1, "account1@email.com");
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, TestUtil.ACCOUNT_2);
         insertEmail(rawContactId2, "account2@email.com");
         ContentValues v1 = new ContentValues();
         v1.put(Email.ADDRESS, "account1@email.com");
@@ -1760,25 +1777,25 @@
         v2.put(Email.ADDRESS, "account2@email.com");
 
         Uri filterUri1 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc")
-                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, ACCOUNT_1.name)
-                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE, ACCOUNT_1.type)
+                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, TestUtil.ACCOUNT_1.name)
+                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE, TestUtil.ACCOUNT_1.type)
                 .build();
         assertStoredValuesOrderly(filterUri1, new ContentValues[] { v1, v2 });
 
         Uri filterUri2 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc")
-                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, ACCOUNT_2.name)
-                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE, ACCOUNT_2.type)
+                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, TestUtil.ACCOUNT_2.name)
+                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE, TestUtil.ACCOUNT_2.type)
                 .build();
         assertStoredValuesOrderly(filterUri2, new ContentValues[] { v2, v1 });
 
         // Just with PRIMARY_ACCOUNT_NAME
         Uri filterUri3 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc")
-                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, ACCOUNT_1.name)
+                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, TestUtil.ACCOUNT_1.name)
                 .build();
         assertStoredValuesOrderly(filterUri3, new ContentValues[]{v1, v2});
 
         Uri filterUri4 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc")
-                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, ACCOUNT_2.name)
+                .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, TestUtil.ACCOUNT_2.name)
                 .build();
         assertStoredValuesOrderly(filterUri4, new ContentValues[] { v2, v1 });
     }
@@ -1788,7 +1805,7 @@
      */
     public void testEmailFilterSameDomainAccountOrder() {
         final Account account = new Account("tester@email.com", "not_used");
-        final long rawContactId = createRawContact(account);
+        final long rawContactId = RawContactUtil.createRawContact(mResolver, account);
         insertEmail(rawContactId, "account1@testemail.com");
         insertEmail(rawContactId, "account1@email.com");
 
@@ -1806,7 +1823,7 @@
      * Test "default" emails are sorted above emails used last.
      */
     public void testEmailFilterSuperPrimaryOverUsageSort() {
-        final long rawContactId = createRawContact(ACCOUNT_1);
+        final long rawContactId = RawContactUtil.createRawContact(mResolver, TestUtil.ACCOUNT_1);
         final Uri emailUri1 = insertEmail(rawContactId, "account1@testemail.com");
         final Uri emailUri2 = insertEmail(rawContactId, "account2@testemail.com");
         insertEmail(rawContactId, "account3@testemail.com", true, true);
@@ -1832,7 +1849,7 @@
      * contact ui.
      */
     public void testEmailFilterUsageOverPrimarySort() {
-        final long rawContactId = createRawContact(ACCOUNT_1);
+        final long rawContactId = RawContactUtil.createRawContact(mResolver, TestUtil.ACCOUNT_1);
         final Uri emailUri1 = insertEmail(rawContactId, "account1@testemail.com");
         final Uri emailUri2 = insertEmail(rawContactId, "account2@testemail.com");
         insertEmail(rawContactId, "account3@testemail.com", true);
@@ -1853,11 +1870,11 @@
 
     /** Tests {@link DataUsageFeedback} correctly promotes a data row instead of a raw contact. */
     public void testEmailFilterSortOrderWithFeedback() {
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         String address1 = "address1@email.com";
         insertEmail(rawContactId1, address1);
 
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         String address2 = "address2@email.com";
         insertEmail(rawContactId2, address2);
         String address3 = "address3@email.com";
@@ -1909,7 +1926,7 @@
      * {@link DataUsageStatColumns#LAST_TIME_USED}
      */
     public void testEmailFilterSortOrderWithOldHistory() {
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         long dataId1 = ContentUris.parseId(insertEmail(rawContactId1, "address1@email.com"));
         long dataId2 = ContentUris.parseId(insertEmail(rawContactId1, "address2@email.com"));
         long dataId3 = ContentUris.parseId(insertEmail(rawContactId1, "address3@email.com"));
@@ -1970,7 +1987,7 @@
     }
 
     public void testPostalsQuery() {
-        long rawContactId = createRawContactWithName("Alice", "Nextore");
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Alice", "Nextore");
         Uri dataUri = insertPostalAddress(rawContactId, "1600 Amphiteatre Ave, Mountain View");
         final long dataId = ContentUris.parseId(dataUri);
 
@@ -2030,7 +2047,8 @@
     }
 
     public void testContactablesQuery() {
-        final long rawContactId = createRawContactWithName("Hot", "Tamale");
+        final long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot",
+                "Tamale");
 
         insertPhoneNumber(rawContactId, "510-123-5769");
         insertEmail(rawContactId, "tamale@acme.com");
@@ -2077,15 +2095,17 @@
 
     public void testContactablesMultipleQuery() {
 
-        final long rawContactId = createRawContactWithName("Hot", "Tamale");
+        final long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot",
+                "Tamale");
         insertPhoneNumber(rawContactId, "510-123-5769");
         insertEmail(rawContactId, "tamale@acme.com");
         insertEmail(rawContactId, "hot@google.com");
 
-        final long rawContactId2 = createRawContactWithName("Cold", "Tamago");
+        final long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "Cold",
+                "Tamago");
         insertEmail(rawContactId2, "eggs@farmers.org");
 
-        final long rawContactId3 = createRawContactWithName("John", "Doe");
+        final long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
         insertPhoneNumber(rawContactId3, "518-354-1111");
         insertEmail(rawContactId3, "doeadeer@afemaledeer.com");
 
@@ -2202,7 +2222,7 @@
         nameValues.put(StructuredName.FAMILY_NAME, "Goulash");
         nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "goo");
         nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "LASH");
-        Uri nameUri = insertStructuredName(rawContactId, nameValues);
+        Uri nameUri = DataUtil.insertStructuredName(mResolver, rawContactId, nameValues);
 
         long contactId = queryContactId(rawContactId);
         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
@@ -2236,7 +2256,7 @@
                 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO |
                 StatusUpdates.CAPABILITY_HAS_VOICE);
 
-        insertStructuredName(rawContactId, "James", "Bond");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "James", "Bond");
 
         long contactId = queryContactId(rawContactId);
         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
@@ -2262,7 +2282,7 @@
                 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO |
                 StatusUpdates.CAPABILITY_HAS_VOICE);
 
-        insertStructuredName(rawContactId, "James", "Bond");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "James", "Bond");
 
         long contactId = queryContactId(rawContactId);
         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
@@ -2352,23 +2372,23 @@
 
     public void testQueryContactStrequentFrequentOrder() {
         // Prepare test data
-        final long rid1 = createRawContact();
+        final long rid1 = RawContactUtil.createRawContact(mResolver);
         final long did1 = ContentUris.parseId(insertPhoneNumber(rid1, "1"));
         final long did1e = ContentUris.parseId(insertEmail(rid1, "1@email.com"));
 
-        final long rid2 = createRawContact();
+        final long rid2 = RawContactUtil.createRawContact(mResolver);
         final long did2 = ContentUris.parseId(insertPhoneNumber(rid2, "2"));
 
-        final long rid3 = createRawContact();
+        final long rid3 = RawContactUtil.createRawContact(mResolver);
         final long did3 = ContentUris.parseId(insertPhoneNumber(rid3, "3"));
 
-        final long rid4 = createRawContact();
+        final long rid4 = RawContactUtil.createRawContact(mResolver);
         final long did4 = ContentUris.parseId(insertPhoneNumber(rid4, "4"));
 
-        final long rid5 = createRawContact();
+        final long rid5 = RawContactUtil.createRawContact(mResolver);
         final long did5 = ContentUris.parseId(insertPhoneNumber(rid5, "5"));
 
-        final long rid6 = createRawContact();
+        final long rid6 = RawContactUtil.createRawContact(mResolver);
         final long did6 = ContentUris.parseId(insertPhoneNumber(rid6, "6"));
 
         final long cid1 = queryContactId(rid1);
@@ -2740,7 +2760,7 @@
         mActor.removePermissions("android.permission.WRITE_PROFILE");
 
         // Create a non-profile contact.
-        long rawContactId = createRawContactWithName("Domo", "Arigato");
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Domo", "Arigato");
         long dataId = getStoredLongValue(Data.CONTENT_URI,
                 Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?",
                 new String[]{String.valueOf(rawContactId), StructuredName.CONTENT_ITEM_TYPE},
@@ -2889,7 +2909,8 @@
         // Insert a profile record with a new data set.
         Account account = new Account("a", "b");
         String dataSet = "c";
-        Uri profileUri = maybeAddAccountQueryParameters(Profile.CONTENT_RAW_CONTACTS_URI, account)
+        Uri profileUri = TestUtil.maybeAddAccountQueryParameters(Profile.CONTENT_RAW_CONTACTS_URI,
+                account)
                 .buildUpon().appendQueryParameter(RawContacts.DATA_SET, dataSet).build();
         ContentValues values = new ContentValues();
         long rawContactId = ContentUris.parseId(mResolver.insert(profileUri, values));
@@ -2920,7 +2941,7 @@
         ContentValues values = new ContentValues();
         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         long rawContactId = ContentUris.parseId(rawContactUri);
-        insertStructuredName(rawContactId, "John", "Doe");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe");
         Uri photoUri = insertPhoto(rawContactId);
         long photoId = ContentUris.parseId(photoUri);
         insertPhoneNumber(rawContactId, "18004664411");
@@ -2972,8 +2993,8 @@
         Account account2 = new Account("c", "d");
         long groupId1 = createGroup(account1, "e", "f");
         long groupId2 = createGroup(account2, "g", "h");
-        Uri uri1 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account1);
-        Uri uri2 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account2);
+        Uri uri1 = TestUtil.maybeAddAccountQueryParameters(Groups.CONTENT_URI, account1);
+        Uri uri2 = TestUtil.maybeAddAccountQueryParameters(Groups.CONTENT_URI, account2);
         assertEquals(1, getCount(uri1, null, null));
         assertEquals(1, getCount(uri2, null, null));
         assertStoredValue(uri1, Groups._ID + "=" + groupId1, null, Groups._ID, groupId1) ;
@@ -3007,7 +3028,7 @@
     }
 
     public void testGroupCreationAfterMembershipInsert() {
-        long rawContactId1 = createRawContact(mAccount);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount);
         Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1");
 
         long groupId = assertSingleGroup(NO_LONG, mAccount, "gsid1", null);
@@ -3016,7 +3037,7 @@
     }
 
     public void testGroupReuseAfterMembershipInsert() {
-        long rawContactId1 = createRawContact(mAccount);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount);
         long groupId1 = createGroup(mAccount, "gsid1", "title1");
         Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1");
 
@@ -3026,7 +3047,7 @@
     }
 
     public void testGroupInsertFailureOnGroupIdConflict() {
-        long rawContactId1 = createRawContact(mAccount);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount);
         long groupId1 = createGroup(mAccount, "gsid1", "title1");
 
         ContentValues values = new ContentValues();
@@ -3110,13 +3131,16 @@
 
         // Prepare raw contact id not used at all, to test group summary uri won't be confused
         // with it.
-        final long rawContactId0 = createRawContactWithName("firstName0", "lastName0");
+        final long rawContactId0 = RawContactUtil.createRawContactWithName(mResolver, "firstName0",
+                "lastName0");
 
-        final long rawContactId1 = createRawContactWithName("firstName1", "lastName1");
+        final long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "firstName1",
+                "lastName1");
         insertEmail(rawContactId1, "address1@email.com");
         insertGroupMembership(rawContactId1, groupId1);
 
-        final long rawContactId2 = createRawContactWithName("firstName2", "lastName2");
+        final long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "firstName2",
+                "lastName2");
         insertEmail(rawContactId2, "address2@email.com");
         insertPhoneNumber(rawContactId2, "222-222-2222");
         insertGroupMembership(rawContactId2, groupId1);
@@ -3158,7 +3182,8 @@
         assertStoredValues(Groups.CONTENT_SUMMARY_URI, new ContentValues[] { v1, v2, v3 });
 
         // Introduce new raw contact, pretending the user added another info.
-        final long rawContactId3 = createRawContactWithName("firstName3", "lastName3");
+        final long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "firstName3",
+                "lastName3");
         insertEmail(rawContactId3, "address3@email.com");
         insertPhoneNumber(rawContactId3, "333-333-3333");
         insertGroupMembership(rawContactId3, groupId2);
@@ -3226,8 +3251,8 @@
         createSettings(account1, "0", "0");
         createSettings(account2, "1", "1");
         createSettings(account3, "1", "0");
-        Uri uri1 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account1);
-        Uri uri2 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account2);
+        Uri uri1 = TestUtil.maybeAddAccountQueryParameters(Settings.CONTENT_URI, account1);
+        Uri uri2 = TestUtil.maybeAddAccountQueryParameters(Settings.CONTENT_URI, account2);
         Uri uri3 = Settings.CONTENT_URI.buildUpon()
                 .appendQueryParameter(RawContacts.ACCOUNT_NAME, account3.getAccountName())
                 .appendQueryParameter(RawContacts.ACCOUNT_TYPE, account3.getAccountType())
@@ -3264,37 +3289,37 @@
     }
 
     public void testDisplayNameParsingWhenPartsUnspecified() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr.");
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         assertStructuredName(rawContactId, "Mr.", "John", "Kevin", "von Smith", "Jr.");
     }
 
     public void testDisplayNameParsingWhenPartsAreNull() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr.");
         values.putNull(StructuredName.GIVEN_NAME);
         values.putNull(StructuredName.FAMILY_NAME);
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
         assertStructuredName(rawContactId, "Mr.", "John", "Kevin", "von Smith", "Jr.");
     }
 
     public void testDisplayNameParsingWhenPartsSpecified() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr.");
         values.put(StructuredName.FAMILY_NAME, "Johnson");
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         assertStructuredName(rawContactId, null, null, null, "Johnson", null);
     }
 
     public void testContactWithoutPhoneticName() {
         ContactLocaleUtils.setLocale(Locale.ENGLISH);
-        final long rawContactId = createRawContact(null);
+        final long rawContactId = RawContactUtil.createRawContact(mResolver, null);
 
         ContentValues values = new ContentValues();
         values.put(StructuredName.PREFIX, "Mr");
@@ -3302,7 +3327,7 @@
         values.put(StructuredName.MIDDLE_NAME, "K.");
         values.put(StructuredName.FAMILY_NAME, "Doe");
         values.put(StructuredName.SUFFIX, "Jr.");
-        Uri dataUri = insertStructuredName(rawContactId, values);
+        Uri dataUri = DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         values.clear();
         values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME);
@@ -3343,12 +3368,12 @@
         }
         ContactLocaleUtils.setLocale(Locale.SIMPLIFIED_CHINESE);
 
-        long rawContactId = createRawContact(null);
+        long rawContactId = RawContactUtil.createRawContact(mResolver, null);
 
         ContentValues values = new ContentValues();
         // "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"
         values.put(StructuredName.DISPLAY_NAME, "\u6BB5\u5C0F\u6D9B");
-        Uri dataUri = insertStructuredName(rawContactId, values);
+        Uri dataUri = DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         values.clear();
         values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME);
@@ -3409,12 +3434,12 @@
             return;
         }
         ContactLocaleUtils.setLocale(Locale.JAPAN);
-        long rawContactId = createRawContact(null);
+        long rawContactId = RawContactUtil.createRawContact(mResolver, null);
 
         ContentValues values = new ContentValues();
         values.put(StructuredName.GIVEN_NAME, "\u7A7A\u6D77");
         values.put(StructuredName.PHONETIC_GIVEN_NAME, "\u304B\u3044\u304F\u3046");
-        Uri dataUri = insertStructuredName(rawContactId, values);
+        Uri dataUri = DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         values.clear();
         values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME);
@@ -3456,10 +3481,10 @@
     }
 
     public void testDisplayNameUpdate() {
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         insertEmail(rawContactId1, "potato@acme.com", true);
 
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         insertPhoneNumber(rawContactId2, "123456789", true);
 
         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
@@ -3467,14 +3492,14 @@
 
         assertAggregated(rawContactId1, rawContactId2, "123456789");
 
-        insertStructuredName(rawContactId2, "Potato", "Head");
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Potato", "Head");
 
         assertAggregated(rawContactId1, rawContactId2, "Potato Head");
         assertNetworkNotified(true);
     }
 
     public void testDisplayNameFromData() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
 
@@ -3505,12 +3530,12 @@
         values.put(StructuredName.GIVEN_NAME, "James");
         values.put(StructuredName.MIDDLE_NAME, "P.");
         values.put(StructuredName.FAMILY_NAME, "Sullivan");
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
         assertStoredValue(uri, Contacts.DISPLAY_NAME, "James P. Sullivan");
     }
 
     public void testDisplayNameFromOrganizationWithoutPhoneticName() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
 
@@ -3543,7 +3568,7 @@
             return;
         }
         ContactLocaleUtils.setLocale(Locale.JAPAN);
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
 
@@ -3572,7 +3597,7 @@
         }
         ContactLocaleUtils.setLocale(Locale.SIMPLIFIED_CHINESE);
 
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
 
@@ -3595,7 +3620,7 @@
     }
 
     public void testLookupByOrganization() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
 
@@ -3648,7 +3673,7 @@
     }
 
     public void testSearchSnippetOrganization() throws Exception {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
 
         // Some random data element
@@ -3680,11 +3705,11 @@
     }
 
     public void testSearchSnippetEmail() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
 
-        insertStructuredName(rawContactId, "John", "Doe");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe");
         Uri dataUri = insertEmail(rawContactId, "acme@corp.com", true, Email.TYPE_CUSTOM, "Custom");
 
         Uri filterUri = buildFilterUri("acme", true);
@@ -3709,11 +3734,11 @@
     }
 
     public void testSearchSnippetPhone() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
 
-        insertStructuredName(rawContactId, "Cave", "Johnson");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Cave", "Johnson");
         insertPhoneNumber(rawContactId, "(860) 555-1234");
 
         values.clear();
@@ -3746,7 +3771,7 @@
     }
 
     public void testSearchSnippetNickname() throws Exception {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
 
@@ -3761,9 +3786,9 @@
     }
 
     public void testSearchSnippetEmptyForNameInDisplayName() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
-        insertStructuredName(rawContactId, "Cave", "Johnson");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Cave", "Johnson");
         insertEmail(rawContactId, "cave@aperturescience.com", true);
 
         ContentValues emptySnippet = new ContentValues();
@@ -3776,7 +3801,7 @@
     }
 
     public void testSearchSnippetEmptyForNicknameInDisplayName() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         insertNickname(rawContactId, "Caveman");
         insertEmail(rawContactId, "cave@aperturescience.com", true);
@@ -3790,7 +3815,7 @@
     }
 
     public void testSearchSnippetEmptyForCompanyInDisplayName() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues company = new ContentValues();
         company.clear();
@@ -3808,7 +3833,7 @@
     }
 
     public void testSearchSnippetEmptyForPhoneInDisplayName() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         insertPhoneNumber(rawContactId, "860-555-1234");
         insertEmail(rawContactId, "860@aperturescience.com", true);
@@ -3822,7 +3847,7 @@
     }
 
     public void testSearchSnippetEmptyForEmailInDisplayName() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         insertEmail(rawContactId, "cave@aperturescience.com", true);
         insertNote(rawContactId, "Cave Johnson is president of Aperture Science");
@@ -3836,8 +3861,8 @@
     }
 
     public void testDisplayNameUpdateFromStructuredNameUpdate() {
-        long rawContactId = createRawContact();
-        Uri nameUri = insertStructuredName(rawContactId, "Slinky", "Dog");
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
+        Uri nameUri = DataUtil.insertStructuredName(mResolver, rawContactId, "Slinky", "Dog");
 
         long contactId = queryContactId(rawContactId);
 
@@ -3879,7 +3904,7 @@
     }
 
     public void testSendToVoicemailDefault() {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
 
         Cursor c = queryContact(contactId);
@@ -3890,7 +3915,7 @@
     }
 
     public void testSetSendToVoicemailAndRingtone() {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
 
         updateSendToVoicemailAndRingtone(contactId, true, "foo");
@@ -3903,11 +3928,11 @@
     }
 
     public void testSendToVoicemailAndRingtoneAfterAggregation() {
-        long rawContactId1 = createRawContactWithName("a", "b");
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "a", "b");
         long contactId1 = queryContactId(rawContactId1);
         updateSendToVoicemailAndRingtone(contactId1, true, "foo");
 
-        long rawContactId2 = createRawContactWithName("c", "d");
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "c", "d");
         long contactId2 = queryContactId(rawContactId2);
         updateSendToVoicemailAndRingtone(contactId2, true, "bar");
 
@@ -3920,11 +3945,11 @@
     }
 
     public void testDoNotSendToVoicemailAfterAggregation() {
-        long rawContactId1 = createRawContactWithName("e", "f");
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "e", "f");
         long contactId1 = queryContactId(rawContactId1);
         updateSendToVoicemailAndRingtone(contactId1, true, null);
 
-        long rawContactId2 = createRawContactWithName("g", "h");
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "g", "h");
         long contactId2 = queryContactId(rawContactId2);
         updateSendToVoicemailAndRingtone(contactId2, false, null);
 
@@ -3937,11 +3962,11 @@
     }
 
     public void testSetSendToVoicemailAndRingtonePreservedAfterJoinAndSplit() {
-        long rawContactId1 = createRawContactWithName("i", "j");
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "i", "j");
         long contactId1 = queryContactId(rawContactId1);
         updateSendToVoicemailAndRingtone(contactId1, true, "foo");
 
-        long rawContactId2 = createRawContactWithName("k", "l");
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "k", "l");
         long contactId2 = queryContactId(rawContactId2);
         updateSendToVoicemailAndRingtone(contactId2, false, "bar");
 
@@ -3958,7 +3983,7 @@
     }
 
     public void testStatusUpdateInsert() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
         long dataId = ContentUris.parseId(imUri);
 
@@ -4011,7 +4036,7 @@
     }
 
     public void testStatusUpdateInferAttribution() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
         long dataId = ContentUris.parseId(imUri);
 
@@ -4032,7 +4057,7 @@
     }
 
     public void testStatusUpdateMatchingImOrEmail() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
         insertImHandle(rawContactId, Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im");
         insertEmail(rawContactId, "m@acme.com");
@@ -4076,7 +4101,7 @@
     }
 
     public void testStatusUpdateUpdateAndDelete() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
 
         long contactId = queryContactId(rawContactId);
@@ -4151,7 +4176,7 @@
     }
 
     public void testStatusUpdateUpdateToNull() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
 
         long contactId = queryContactId(rawContactId);
@@ -4179,7 +4204,7 @@
     }
 
     public void testStatusUpdateWithTimestamp() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
         insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk");
 
@@ -4212,7 +4237,7 @@
     // Stream item query test cases.
 
     public void testQueryStreamItemsByRawContactId() {
-        long rawContactId = createRawContact(mAccount);
+        long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount);
         ContentValues values = buildGenericStreamItemValues();
         insertStreamItem(rawContactId, values, mAccount);
         assertStoredValues(
@@ -4223,7 +4248,7 @@
     }
 
     public void testQueryStreamItemsByContactId() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = buildGenericStreamItemValues();
         insertStreamItem(rawContactId, values, null);
@@ -4235,7 +4260,7 @@
     }
 
     public void testQueryStreamItemsByLookupKey() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         String lookupKey = queryLookupKey(contactId);
         ContentValues values = buildGenericStreamItemValues();
@@ -4248,7 +4273,7 @@
     }
 
     public void testQueryStreamItemsByLookupKeyAndContactId() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         String lookupKey = queryLookupKey(contactId);
         ContentValues values = buildGenericStreamItemValues();
@@ -4263,14 +4288,14 @@
     }
 
     public void testQueryStreamItems() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = buildGenericStreamItemValues();
         insertStreamItem(rawContactId, values, null);
         assertStoredValues(StreamItems.CONTENT_URI, values);
     }
 
     public void testQueryStreamItemsWithSelection() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues firstValues = buildGenericStreamItemValues();
         insertStreamItem(rawContactId, firstValues, null);
 
@@ -4288,7 +4313,7 @@
     }
 
     public void testQueryStreamItemById() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues firstValues = buildGenericStreamItemValues();
         Uri resultUri = insertStreamItem(rawContactId, firstValues, null);
         long firstStreamItemId = ContentUris.parseId(resultUri);
@@ -4310,7 +4335,7 @@
     // Stream item photo insertion + query test cases.
 
     public void testQueryStreamItemPhotoWithSelection() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = buildGenericStreamItemValues();
         Uri resultUri = insertStreamItem(rawContactId, values, null);
         long streamItemId = ContentUris.parseId(resultUri);
@@ -4327,7 +4352,7 @@
     }
 
     public void testQueryStreamItemPhotoByStreamItemId() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
 
         // Insert a first stream item.
         ContentValues firstValues = buildGenericStreamItemValues();
@@ -4358,7 +4383,7 @@
     }
 
     public void testQueryStreamItemPhotoByStreamItemPhotoId() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
 
         // Insert a first stream item.
         ContentValues firstValues = buildGenericStreamItemValues();
@@ -4424,7 +4449,7 @@
     }
 
     public void testInsertStreamItemWithContentValues() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = buildGenericStreamItemValues();
         values.put(StreamItems.RAW_CONTACT_ID, rawContactId);
         mResolver.insert(StreamItems.CONTENT_URI, values);
@@ -4434,7 +4459,7 @@
     }
 
     public void testInsertStreamItemOverLimit() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = buildGenericStreamItemValues();
         values.put(StreamItems.RAW_CONTACT_ID, rawContactId);
 
@@ -4469,7 +4494,7 @@
     }
 
     public void testInsertStreamItemOlderThanOldestInLimit() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = buildGenericStreamItemValues();
         values.put(StreamItems.RAW_CONTACT_ID, rawContactId);
 
@@ -4492,7 +4517,7 @@
     // Stream item photo insertion test cases.
 
     public void testInsertStreamItemsAndPhotosInBatch() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues streamItemValues = buildGenericStreamItemValues();
         ContentValues streamItemPhotoValues = buildGenericStreamItemPhotoValues(0);
 
@@ -4546,7 +4571,7 @@
     // Stream item update test cases.
 
     public void testUpdateStreamItemById() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = buildGenericStreamItemValues();
         Uri resultUri = insertStreamItem(rawContactId, values, null);
         long streamItemId = ContentUris.parseId(resultUri);
@@ -4559,7 +4584,7 @@
     }
 
     public void testUpdateStreamItemWithContentValues() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = buildGenericStreamItemValues();
         Uri resultUri = insertStreamItem(rawContactId, values, null);
         long streamItemId = ContentUris.parseId(resultUri);
@@ -4574,7 +4599,7 @@
     // Stream item photo update test cases.
 
     public void testUpdateStreamItemPhotoById() throws IOException {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = buildGenericStreamItemValues();
         Uri resultUri = insertStreamItem(rawContactId, values, null);
         long streamItemId = ContentUris.parseId(resultUri);
@@ -4602,7 +4627,7 @@
     }
 
     public void testUpdateStreamItemPhotoWithContentValues() throws IOException {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = buildGenericStreamItemValues();
         Uri resultUri = insertStreamItem(rawContactId, values, null);
         long streamItemId = ContentUris.parseId(resultUri);
@@ -4631,7 +4656,7 @@
     // Stream item deletion test cases.
 
     public void testDeleteStreamItemById() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues firstValues = buildGenericStreamItemValues();
         Uri resultUri = insertStreamItem(rawContactId, firstValues, null);
         long firstStreamItemId = ContentUris.parseId(resultUri);
@@ -4651,7 +4676,7 @@
     }
 
     public void testDeleteStreamItemWithSelection() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues firstValues = buildGenericStreamItemValues();
         insertStreamItem(rawContactId, firstValues, null);
 
@@ -4672,7 +4697,7 @@
     // Stream item photo deletion test cases.
 
     public void testDeleteStreamItemPhotoById() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long streamItemId = ContentUris.parseId(
                 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null));
         long streamItemPhotoId = ContentUris.parseId(
@@ -4696,7 +4721,7 @@
     }
 
     public void testDeleteStreamItemPhotoWithSelection() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long streamItemId = ContentUris.parseId(
                 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null));
         ContentValues firstPhotoValues = buildGenericStreamItemPhotoValues(0);
@@ -4713,7 +4738,7 @@
     }
 
     public void testDeleteStreamItemsWhenRawContactDeleted() {
-        long rawContactId = createRawContact(mAccount);
+        long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount);
         Uri streamItemUri = insertStreamItem(rawContactId,
                 buildGenericStreamItemValues(), mAccount);
         Uri streamItemPhotoUri = insertStreamItemPhoto(ContentUris.parseId(streamItemUri),
@@ -4802,7 +4827,7 @@
     }
 
     public void testStreamItemReadRequiresReadSocialStreamPermission() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         String lookupKey = queryLookupKey(contactId);
         long streamItemId = ContentUris.parseId(
@@ -4854,7 +4879,7 @@
     }
 
     public void testStreamItemPhotoReadRequiresReadSocialStreamPermission() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long streamItemId = ContentUris.parseId(
                 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null));
         long streamItemPhotoId = ContentUris.parseId(
@@ -4878,7 +4903,7 @@
     }
 
     public void testStreamItemModificationRequiresWriteSocialStreamPermission() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long streamItemId = ContentUris.parseId(
                 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null));
         mActor.removePermissions("android.permission.WRITE_SOCIAL_STREAM");
@@ -4907,7 +4932,7 @@
     }
 
     public void testStreamItemPhotoModificationRequiresWriteSocialStreamPermission() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long streamItemId = ContentUris.parseId(
                 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null));
         long streamItemPhotoId = ContentUris.parseId(
@@ -4944,7 +4969,7 @@
     public void testStatusUpdateDoesNotRequireReadOrWriteSocialStreamPermission() {
         int protocol1 = Im.PROTOCOL_GOOGLE_TALK;
         String handle1 = "test@gmail.com";
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         insertImHandle(rawContactId, protocol1, null, handle1);
         mActor.removePermissions("android.permission.READ_SOCIAL_STREAM");
         mActor.removePermissions("android.permission.WRITE_SOCIAL_STREAM");
@@ -4981,7 +5006,7 @@
         int protocol1 = Im.PROTOCOL_GOOGLE_TALK;
         String handle1 = "test@gmail.com";
 
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         insertImHandle(rawContactId1, protocol1, null, handle1);
 
         insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AVAILABLE, "Green",
@@ -5043,7 +5068,7 @@
     }
 
     public void testContactVisibilityUpdateOnMembershipChange() {
-        long rawContactId = createRawContact(mAccount);
+        long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount);
         assertVisibility(rawContactId, "0");
 
         long visibleGroupId = createGroup(mAccount, "123", "Visible", 1);
@@ -5109,30 +5134,33 @@
         long groupId1 = createGroup(mAccount, "gsid1", "title1");
         long groupId2 = createGroup(mAccount, "gsid2", "title2");
 
-        id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c0");
+        id = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.SOURCE_ID, "c0");
         insertGroupMembership(id, "gsid1");
         insertEmail(id, "c0@email.com");
         insertPhoneNumber(id, "5551212c0");
 
-        long c1 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c1");
+        long c1 = id = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.SOURCE_ID,
+                "c1");
         Uri id_1_0 = insertGroupMembership(id, "gsid1");
         Uri id_1_1 = insertGroupMembership(id, "gsid2");
         Uri id_1_2 = insertEmail(id, "c1@email.com");
         Uri id_1_3 = insertPhoneNumber(id, "5551212c1");
 
-        long c2 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c2");
+        long c2 = id = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.SOURCE_ID,
+                "c2");
         Uri id_2_0 = insertGroupMembership(id, "gsid1");
         Uri id_2_1 = insertEmail(id, "c2@email.com");
         Uri id_2_2 = insertPhoneNumber(id, "5551212c2");
 
-        long c3 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c3");
+        long c3 = id = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.SOURCE_ID,
+                "c3");
         Uri id_3_0 = insertGroupMembership(id, groupId2);
         Uri id_3_1 = insertEmail(id, "c3@email.com");
         Uri id_3_2 = insertPhoneNumber(id, "5551212c3");
 
         EntityIterator iterator = RawContacts.newEntityIterator(mResolver.query(
-                maybeAddAccountQueryParameters(RawContactsEntity.CONTENT_URI, mAccount), null,
-                RawContacts.SOURCE_ID + " in ('c1', 'c2', 'c3')", null, null));
+                TestUtil.maybeAddAccountQueryParameters(RawContactsEntity.CONTENT_URI, mAccount),
+                null, RawContacts.SOURCE_ID + " in ('c1', 'c2', 'c3')", null, null));
         Entity entity;
         ContentValues[] subValues;
         entity = iterator.next();
@@ -5189,7 +5217,7 @@
     }
 
     public void testDataCreateUpdateDeleteByMimeType() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
 
         ContentValues values = new ContentValues();
         values.put(Data.RAW_CONTACT_ID, rawContactId);
@@ -5252,11 +5280,11 @@
     public void testRawContactQuery() {
         Account account1 = new Account("a", "b");
         Account account2 = new Account("c", "d");
-        long rawContactId1 = createRawContact(account1);
-        long rawContactId2 = createRawContact(account2);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, account1);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, account2);
 
-        Uri uri1 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account1);
-        Uri uri2 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account2);
+        Uri uri1 = TestUtil.maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account1);
+        Uri uri2 = TestUtil.maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account2);
         assertEquals(1, getCount(uri1, null, null));
         assertEquals(1, getCount(uri2, null, null));
         assertStoredValue(uri1, RawContacts._ID, rawContactId1) ;
@@ -5269,7 +5297,7 @@
     }
 
     public void testRawContactDeletion() {
-        long rawContactId = createRawContact(mAccount);
+        long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount);
         Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
 
         insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com");
@@ -5300,8 +5328,8 @@
     }
 
     public void testRawContactDeletionKeepingAggregateContact() {
-        long rawContactId1 = createRawContactWithName(mAccount);
-        long rawContactId2 = createRawContactWithName(mAccount);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, mAccount);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, mAccount);
         setAggregationException(
                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
 
@@ -5315,7 +5343,7 @@
     }
 
     public void testRawContactDeletion_byAccountParam() {
-        long rawContactId = createRawContact(mAccount);
+        long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount);
         Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
 
         insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com");
@@ -5351,7 +5379,7 @@
     }
 
     public void testRawContactDeletion_byAccountSelection() {
-        long rawContactId = createRawContact(mAccount);
+        long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount);
         Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
 
         // Do not delete if we are deleting with wrong account.
@@ -5377,14 +5405,14 @@
      */
     public void testAccountsToString() {
         final Set<Account> EXPECTED_0 = Sets.newHashSet();
-        final Set<Account> EXPECTED_1 = Sets.newHashSet(ACCOUNT_1);
-        final Set<Account> EXPECTED_2 = Sets.newHashSet(ACCOUNT_2);
-        final Set<Account> EXPECTED_1_2 = Sets.newHashSet(ACCOUNT_1, ACCOUNT_2);
+        final Set<Account> EXPECTED_1 = Sets.newHashSet(TestUtil.ACCOUNT_1);
+        final Set<Account> EXPECTED_2 = Sets.newHashSet(TestUtil.ACCOUNT_2);
+        final Set<Account> EXPECTED_1_2 = Sets.newHashSet(TestUtil.ACCOUNT_1, TestUtil.ACCOUNT_2);
 
         final Set<Account> ACTUAL_0 = Sets.newHashSet();
-        final Set<Account> ACTUAL_1 = Sets.newHashSet(ACCOUNT_1);
-        final Set<Account> ACTUAL_2 = Sets.newHashSet(ACCOUNT_2);
-        final Set<Account> ACTUAL_1_2 = Sets.newHashSet(ACCOUNT_2, ACCOUNT_1);
+        final Set<Account> ACTUAL_1 = Sets.newHashSet(TestUtil.ACCOUNT_1);
+        final Set<Account> ACTUAL_2 = Sets.newHashSet(TestUtil.ACCOUNT_2);
+        final Set<Account> ACTUAL_1_2 = Sets.newHashSet(TestUtil.ACCOUNT_2, TestUtil.ACCOUNT_1);
 
         assertTrue(EXPECTED_0.equals(accountsToStringToAccounts(ACTUAL_0)));
         assertFalse(EXPECTED_0.equals(accountsToStringToAccounts(ACTUAL_1)));
@@ -5425,10 +5453,10 @@
         final ContactsProvider2 cp = (ContactsProvider2) getProvider();
 
         final Account[] ACCOUNTS_0 = new Account[] {};
-        final Account[] ACCOUNTS_1 = new Account[] {ACCOUNT_1};
-        final Account[] ACCOUNTS_2 = new Account[] {ACCOUNT_2};
-        final Account[] ACCOUNTS_1_2 = new Account[] {ACCOUNT_1, ACCOUNT_2};
-        final Account[] ACCOUNTS_2_1 = new Account[] {ACCOUNT_2, ACCOUNT_1};
+        final Account[] ACCOUNTS_1 = new Account[] {TestUtil.ACCOUNT_1};
+        final Account[] ACCOUNTS_2 = new Account[] {TestUtil.ACCOUNT_2};
+        final Account[] ACCOUNTS_1_2 = new Account[] {TestUtil.ACCOUNT_1, TestUtil.ACCOUNT_2};
+        final Account[] ACCOUNTS_2_1 = new Account[] {TestUtil.ACCOUNT_2, TestUtil.ACCOUNT_1};
 
         // Add ACCOUNT_1
 
@@ -5471,7 +5499,7 @@
     public void testAccountsUpdated() {
         // This is to ensure we do not delete contacts with null, null (account name, type)
         // accidentally.
-        long rawContactId3 = createRawContactWithName("James", "Sullivan");
+        long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "James", "Sullivan");
         insertPhoneNumber(rawContactId3, "5234567890");
         Uri rawContact3 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId3);
         assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null));
@@ -5483,9 +5511,9 @@
         assertStoredValue(rawContact3, RawContacts.ACCOUNT_NAME, null);
         assertStoredValue(rawContact3, RawContacts.ACCOUNT_TYPE, null);
 
-        long rawContactId1 = createRawContact(mAccount);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount);
         insertEmail(rawContactId1, "account1@email.com");
-        long rawContactId2 = createRawContact(mAccountTwo);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, mAccountTwo);
         insertEmail(rawContactId2, "account2@email.com");
         insertImHandle(rawContactId2, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com");
         insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com",
@@ -5505,9 +5533,11 @@
         mActor.setAccounts(new Account[]{readOnlyAccount, mAccount});
         cp.onAccountsUpdated(new Account[]{readOnlyAccount, mAccount});
 
-        long rawContactId1 = createRawContactWithName("John", "Doe", readOnlyAccount);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                readOnlyAccount);
         Uri photoUri1 = insertPhoto(rawContactId1);
-        long rawContactId2 = createRawContactWithName("john", "doe", mAccount);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "john", "doe",
+                mAccount);
         Uri photoUri2 = insertPhoto(rawContactId2);
         storeValue(photoUri2, Photo.IS_SUPER_PRIMARY, "1");
 
@@ -5548,7 +5578,7 @@
         cp.onAccountsUpdated(new Account[]{doomedAccount, safeAccount});
 
         // Create a doomed raw contact, stream item, and photo.
-        long doomedRawContactId = createRawContactWithName(doomedAccount);
+        long doomedRawContactId = RawContactUtil.createRawContactWithName(mResolver, doomedAccount);
         Uri doomedStreamItemUri =
                 insertStreamItem(doomedRawContactId, buildGenericStreamItemValues(), doomedAccount);
         long doomedStreamItemId = ContentUris.parseId(doomedStreamItemUri);
@@ -5556,7 +5586,7 @@
                 doomedStreamItemId, buildGenericStreamItemPhotoValues(0), doomedAccount);
 
         // Create a safe raw contact, stream item, and photo.
-        long safeRawContactId = createRawContactWithName(safeAccount);
+        long safeRawContactId = RawContactUtil.createRawContactWithName(mResolver, safeAccount);
         Uri safeStreamItemUri =
                 insertStreamItem(safeRawContactId, buildGenericStreamItemValues(), safeAccount);
         long safeStreamItemId = ContentUris.parseId(safeStreamItemUri);
@@ -5583,8 +5613,10 @@
     }
 
     public void testContactDeletion() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_2);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                TestUtil.ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                TestUtil.ACCOUNT_2);
 
         long contactId = queryContactId(rawContactId1);
 
@@ -5597,10 +5629,10 @@
     }
 
     public void testMarkAsDirtyParameter() {
-        long rawContactId = createRawContact(mAccount);
+        long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount);
         Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
 
-        Uri uri = insertStructuredName(rawContactId, "John", "Doe");
+        Uri uri = DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe");
         clearDirty(rawContactUri);
         Uri updateUri = setCallerIsSyncAdapter(uri, mAccount);
 
@@ -5613,7 +5645,7 @@
     }
 
     public void testRawContactDirtyAndVersion() {
-        final long rawContactId = createRawContact(mAccount);
+        final long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount);
         Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId);
         assertDirty(uri, false);
         long version = getVersion(uri);
@@ -5654,7 +5686,7 @@
     }
 
     public void testRawContactClearDirty() {
-        final long rawContactId = createRawContact(mAccount);
+        final long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount);
         Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
                 rawContactId);
         long version = getVersion(uri);
@@ -5669,7 +5701,7 @@
     }
 
     public void testRawContactDeletionSetsDirty() {
-        final long rawContactId = createRawContact(mAccount);
+        final long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount);
         Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
                 rawContactId);
         long version = getVersion(uri);
@@ -5740,7 +5772,7 @@
         ContentValues values = new ContentValues();
         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         long rawContactId = ContentUris.parseId(rawContactUri);
-        insertStructuredName(rawContactId, "John", "Doe");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe");
         long dataId = ContentUris.parseId(insertPhoto(rawContactId, R.drawable.earth_normal));
         long photoFileId = getStoredLongValue(Data.CONTENT_URI, Data._ID + "=?",
                 new String[]{String.valueOf(dataId)}, Photo.PHOTO_FILE_ID);
@@ -5753,7 +5785,7 @@
     }
 
     public void testGetPhotoViaLookupUri() throws IOException {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
         Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri);
@@ -5780,7 +5812,7 @@
     }
 
     public void testInputStreamForPhoto() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
         insertPhoto(rawContactId);
@@ -5803,11 +5835,11 @@
     }
 
     public void testSuperPrimaryPhoto() {
-        long rawContactId1 = createRawContact(new Account("a", "a"));
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, new Account("a", "a"));
         Uri photoUri1 = insertPhoto(rawContactId1, R.drawable.earth_normal);
         long photoId1 = ContentUris.parseId(photoUri1);
 
-        long rawContactId2 = createRawContact(new Account("b", "b"));
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, new Account("b", "b"));
         Uri photoUri2 = insertPhoto(rawContactId2, R.drawable.earth_normal);
         long photoId2 = ContentUris.parseId(photoUri2);
 
@@ -5845,7 +5877,7 @@
         ContentValues values = new ContentValues();
         Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         long rawContactId = ContentUris.parseId(rawContactUri);
-        insertStructuredName(rawContactId, "John", "Doe");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe");
 
         Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI,
                 queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY);
@@ -5904,7 +5936,7 @@
     }
 
     public void testOpenDisplayPhotoForContactId() throws IOException {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
         insertPhoto(rawContactId, R.drawable.earth_normal);
         Uri photoUri = Contacts.CONTENT_URI.buildUpon()
@@ -5916,7 +5948,7 @@
     }
 
     public void testOpenDisplayPhotoForContactLookupKey() throws IOException {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
         String lookupKey = queryLookupKey(contactId);
         insertPhoto(rawContactId, R.drawable.earth_normal);
@@ -5929,7 +5961,7 @@
     }
 
     public void testOpenDisplayPhotoForContactLookupKeyAndId() throws IOException {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
         String lookupKey = queryLookupKey(contactId);
         insertPhoto(rawContactId, R.drawable.earth_normal);
@@ -5943,7 +5975,7 @@
     }
 
     public void testOpenDisplayPhotoForRawContactId() throws IOException {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         insertPhoto(rawContactId, R.drawable.earth_normal);
         Uri photoUri = RawContacts.CONTENT_URI.buildUpon()
                 .appendPath(String.valueOf(rawContactId))
@@ -5954,7 +5986,7 @@
     }
 
     public void testOpenDisplayPhotoByPhotoUri() throws IOException {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
         insertPhoto(rawContactId, R.drawable.earth_normal);
 
@@ -5968,7 +6000,7 @@
     }
 
     public void testPhotoUriForDisplayPhoto() {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
 
         // Photo being inserted is larger than a thumbnail, so it will be stored as a file.
@@ -5991,7 +6023,7 @@
     }
 
     public void testPhotoUriForThumbnailPhoto() throws IOException {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
 
         // Photo being inserted is a thumbnail, so it will only be stored in a BLOB.  The photo URI
@@ -6020,7 +6052,7 @@
     }
 
     public void testWriteNewPhotoToAssetFile() throws Exception {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
 
         // Load in a huge photo.
@@ -6060,7 +6092,7 @@
     }
 
     public void testWriteUpdatedPhotoToAssetFile() throws Exception {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
 
         // Insert a large photo first.
@@ -6131,14 +6163,14 @@
         provider.cleanupPhotoStore();
 
         // Insert a couple of contacts with photos.
-        long rawContactId1 = createRawContactWithName();
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver);
         long contactId1 = queryContactId(rawContactId1);
         long dataId1 = ContentUris.parseId(insertPhoto(rawContactId1, R.drawable.earth_normal));
         long photoFileId1 =
                 getStoredLongValue(ContentUris.withAppendedId(Data.CONTENT_URI, dataId1),
                         Photo.PHOTO_FILE_ID);
 
-        long rawContactId2 = createRawContactWithName();
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver);
         long contactId2 = queryContactId(rawContactId2);
         long dataId2 = ContentUris.parseId(insertPhoto(rawContactId2, R.drawable.earth_normal));
         long photoFileId2 =
@@ -6158,7 +6190,7 @@
 
         // Insert a third raw contact that has a bogus photo file ID.
         long bogusFileId = 1234567;
-        long rawContactId3 = createRawContactWithName();
+        long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver);
         long contactId3 = queryContactId(rawContactId3);
         values.clear();
         values.put(Data.RAW_CONTACT_ID, rawContactId3);
@@ -6172,7 +6204,7 @@
         // Insert a fourth raw contact with a stream item that has a photo, then remove that photo
         // from the photo store.
         Account socialAccount = new Account("social", "social");
-        long rawContactId4 = createRawContactWithName(socialAccount);
+        long rawContactId4 = RawContactUtil.createRawContactWithName(mResolver, socialAccount);
         Uri streamItemUri =
                 insertStreamItem(rawContactId4, buildGenericStreamItemValues(), socialAccount);
         long streamItemId = ContentUris.parseId(streamItemUri);
@@ -6272,7 +6304,7 @@
     }
 
     public void testOverwritePhotoWithThumbnail() throws IOException {
-        long rawContactId = createRawContactWithName();
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
         long contactId = queryContactId(rawContactId);
         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
 
@@ -6300,9 +6332,9 @@
     }
 
     public void testUpdateRawContactSetStarred() {
-        long rawContactId1 = createRawContactWithName();
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver);
         Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1);
-        long rawContactId2 = createRawContactWithName();
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver);
         Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2);
         setAggregationException(
                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
@@ -6336,11 +6368,11 @@
     }
 
     public void testSetAndClearSuperPrimaryEmail() {
-        long rawContactId1 = createRawContact(new Account("a", "a"));
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, new Account("a", "a"));
         Uri mailUri11 = insertEmail(rawContactId1, "test1@domain1.com");
         Uri mailUri12 = insertEmail(rawContactId1, "test2@domain1.com");
 
-        long rawContactId2 = createRawContact(new Account("b", "b"));
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, new Account("b", "b"));
         Uri mailUri21 = insertEmail(rawContactId2, "test1@domain2.com");
         Uri mailUri22 = insertEmail(rawContactId2, "test2@domain2.com");
 
@@ -6437,7 +6469,7 @@
      * are each called from its own test
      */
     public void testChangingPrimary(boolean inUpdate, boolean withSuperPrimary) {
-        long rawContactId = createRawContact(new Account("a", "a"));
+        long rawContactId = RawContactUtil.createRawContact(mResolver, new Account("a", "a"));
         Uri mailUri1 = insertEmail(rawContactId, "test1@domain1.com", true);
 
         if (withSuperPrimary) {
@@ -6512,14 +6544,14 @@
         Uri uri = Contacts.CONTENT_URI.buildUpon()
                 .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build();
 
-        createRawContact();
-        createRawContactWithName("James", "Sullivan");
-        createRawContactWithName("The Abominable", "Snowman");
-        createRawContactWithName("Mike", "Wazowski");
-        createRawContactWithName("randall", "boggs");
-        createRawContactWithName("Boo", null);
-        createRawContactWithName("Mary", null);
-        createRawContactWithName("Roz", null);
+        RawContactUtil.createRawContact(mResolver);
+        RawContactUtil.createRawContactWithName(mResolver, "James", "Sullivan");
+        RawContactUtil.createRawContactWithName(mResolver, "The Abominable", "Snowman");
+        RawContactUtil.createRawContactWithName(mResolver, "Mike", "Wazowski");
+        RawContactUtil.createRawContactWithName(mResolver, "randall", "boggs");
+        RawContactUtil.createRawContactWithName(mResolver, "Boo", null);
+        RawContactUtil.createRawContactWithName(mResolver, "Mary", null);
+        RawContactUtil.createRawContactWithName(mResolver, "Roz", null);
 
         Cursor cursor = mResolver.query(uri,
                 new String[]{Contacts.DISPLAY_NAME},
@@ -6547,13 +6579,13 @@
         Uri uri = Contacts.CONTENT_URI.buildUpon()
                 .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build();
 
-        createRawContactWithName("Josef", "Sacher");
-        createRawContactWithName("Franz", "Schiller");
-        createRawContactWithName("Eckart", "Steiff");
-        createRawContactWithName("Klaus", "Seiler");
-        createRawContactWithName("Lars", "Sultan");
-        createRawContactWithName("Heidi", "Rilke");
-        createRawContactWithName("Suse", "Thomas");
+        RawContactUtil.createRawContactWithName(mResolver, "Josef", "Sacher");
+        RawContactUtil.createRawContactWithName(mResolver, "Franz", "Schiller");
+        RawContactUtil.createRawContactWithName(mResolver, "Eckart", "Steiff");
+        RawContactUtil.createRawContactWithName(mResolver, "Klaus", "Seiler");
+        RawContactUtil.createRawContactWithName(mResolver, "Lars", "Sultan");
+        RawContactUtil.createRawContactWithName(mResolver, "Heidi", "Rilke");
+        RawContactUtil.createRawContactWithName(mResolver, "Suse", "Thomas");
 
         Cursor cursor = mResolver.query(uri,
                 new String[]{Contacts.DISPLAY_NAME},
@@ -6641,7 +6673,8 @@
         values.put(RawContacts.ACCOUNT_NAME, red.name);
         values.put(RawContacts.ACCOUNT_TYPE, red.type);
 
-        final Uri insertUri = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, blue);
+        final Uri insertUri = TestUtil.maybeAddAccountQueryParameters(RawContacts.CONTENT_URI,
+                blue);
         try {
             mResolver.insert(insertUri, values);
             fail("Able to insert RawContact with inconsistent account details");
@@ -6655,7 +6688,7 @@
     }
 
     public void testProviderStatusOnlyLocalContacts() throws Exception {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         assertProviderStatus(ProviderStatus.STATUS_NORMAL);
         mResolver.delete(
                 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), null, null);
@@ -6664,8 +6697,8 @@
 
     public void testProviderStatusWithAccounts() throws Exception {
         assertProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS);
-        mActor.setAccounts(new Account[]{ACCOUNT_1});
-        ((ContactsProvider2)getProvider()).onAccountsUpdated(new Account[]{ACCOUNT_1});
+        mActor.setAccounts(new Account[]{TestUtil.ACCOUNT_1});
+        ((ContactsProvider2)getProvider()).onAccountsUpdated(new Account[]{TestUtil.ACCOUNT_1});
         assertProviderStatus(ProviderStatus.STATUS_NORMAL);
         mActor.setAccounts(new Account[0]);
         ((ContactsProvider2)getProvider()).onAccountsUpdated(new Account[0]);
@@ -6720,11 +6753,13 @@
     }
 
     private VCardTestUriCreator createVCardTestContacts() {
-        final long rawContactId1 = createRawContact(mAccount, RawContacts.SOURCE_ID, "4:12");
-        insertStructuredName(rawContactId1, "John", "Doe");
+        final long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount,
+                RawContacts.SOURCE_ID, "4:12");
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "John", "Doe");
 
-        final long rawContactId2 = createRawContact(mAccount, RawContacts.SOURCE_ID, "3:4%121");
-        insertStructuredName(rawContactId2, "Jane", "Doh");
+        final long rawContactId2 = RawContactUtil.createRawContact(mResolver, mAccount,
+                RawContacts.SOURCE_ID, "3:4%121");
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Jane", "Doh");
 
         final long contactId1 = queryContactId(rawContactId1);
         final long contactId2 = queryContactId(rawContactId2);
@@ -6837,9 +6872,9 @@
         long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */);
         long g3 = createGroup(mAccountTwo, "g3", "t3", 0, true /* autoAdd */, false /* favorite */);
         long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, false/* favorite */);
-        long r1 = createRawContact(mAccount);
-        long r2 = createRawContact(mAccountTwo);
-        long r3 = createRawContact(null);
+        long r1 = RawContactUtil.createRawContact(mResolver, mAccount);
+        long r2 = RawContactUtil.createRawContact(mResolver, mAccountTwo);
+        long r3 = RawContactUtil.createRawContact(mResolver, null);
 
         Cursor c = queryGroupMemberships(mAccount);
         try {
@@ -6863,12 +6898,12 @@
     }
 
     public void testNoAutoAddMembershipAfterGroupCreation() {
-        long r1 = createRawContact(mAccount);
-        long r2 = createRawContact(mAccount);
-        long r3 = createRawContact(mAccount);
-        long r4 = createRawContact(mAccountTwo);
-        long r5 = createRawContact(mAccountTwo);
-        long r6 = createRawContact(null);
+        long r1 = RawContactUtil.createRawContact(mResolver, mAccount);
+        long r2 = RawContactUtil.createRawContact(mResolver, mAccount);
+        long r3 = RawContactUtil.createRawContact(mResolver, mAccount);
+        long r4 = RawContactUtil.createRawContact(mResolver, mAccountTwo);
+        long r5 = RawContactUtil.createRawContact(mResolver, mAccountTwo);
+        long r6 = RawContactUtil.createRawContact(mResolver, null);
 
         assertNoRowsAndClose(queryGroupMemberships(mAccount));
         assertNoRowsAndClose(queryGroupMemberships(mAccountTwo));
@@ -6887,13 +6922,13 @@
     // favorites group removed
     // no change to starred status
     public void testFavoritesMembershipAfterGroupCreation() {
-        long r1 = createRawContact(mAccount, RawContacts.STARRED, "1");
-        long r2 = createRawContact(mAccount);
-        long r3 = createRawContact(mAccount, RawContacts.STARRED, "1");
-        long r4 = createRawContact(mAccountTwo, RawContacts.STARRED, "1");
-        long r5 = createRawContact(mAccountTwo);
-        long r6 = createRawContact(null, RawContacts.STARRED, "1");
-        long r7 = createRawContact(null);
+        long r1 = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.STARRED, "1");
+        long r2 = RawContactUtil.createRawContact(mResolver, mAccount);
+        long r3 = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.STARRED, "1");
+        long r4 = RawContactUtil.createRawContact(mResolver, mAccountTwo, RawContacts.STARRED, "1");
+        long r5 = RawContactUtil.createRawContact(mResolver, mAccountTwo);
+        long r6 = RawContactUtil.createRawContact(mResolver, null, RawContacts.STARRED, "1");
+        long r7 = RawContactUtil.createRawContact(mResolver, null);
 
         assertNoRowsAndClose(queryGroupMemberships(mAccount));
         assertNoRowsAndClose(queryGroupMemberships(mAccountTwo));
@@ -6963,9 +6998,9 @@
         long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false/* favorite */);
         long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, true /* favorite */);
         long g5 = createGroup(mAccountTwo, "g5", "t5", 0, false /* autoAdd */, false/* favorite */);
-        long r1 = createRawContact(mAccount, RawContacts.STARRED, "1");
-        long r2 = createRawContact(mAccount);
-        long r3 = createRawContact(mAccountTwo);
+        long r1 = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.STARRED, "1");
+        long r2 = RawContactUtil.createRawContact(mResolver, mAccount);
+        long r3 = RawContactUtil.createRawContact(mResolver, mAccountTwo);
 
         assertNoRowsAndClose(queryGroupMemberships(mAccountTwo));
         Cursor c = queryGroupMemberships(mAccount);
@@ -7038,9 +7073,9 @@
         long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false/* favorite */);
         long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, true /* favorite */);
         long g5 = createGroup(mAccountTwo, "g5", "t5", 0, false /* autoAdd */, false/* favorite */);
-        long r1 = createRawContact(mAccount);
-        long r2 = createRawContact(mAccount);
-        long r3 = createRawContact(mAccountTwo);
+        long r1 = RawContactUtil.createRawContact(mResolver, mAccount);
+        long r2 = RawContactUtil.createRawContact(mResolver, mAccount);
+        long r3 = RawContactUtil.createRawContact(mResolver, mAccountTwo);
 
         assertFalse(queryRawContactIsStarred(r1));
         assertFalse(queryRawContactIsStarred(r2));
@@ -7104,7 +7139,7 @@
     }
 
     public void testReadOnlyRawContact() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
         storeValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "first");
         storeValue(rawContactUri, RawContacts.RAW_CONTACT_IS_READ_ONLY, 1);
@@ -7120,7 +7155,7 @@
     }
 
     public void testReadOnlyDataRow() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         Uri emailUri = insertEmail(rawContactId, "email");
         Uri phoneUri = insertPhoneNumber(rawContactId, "555-1111");
 
@@ -7138,11 +7173,11 @@
     }
 
     public void testContactWithReadOnlyRawContact() {
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1);
         storeValue(rawContactUri1, RawContacts.CUSTOM_RINGTONE, "first");
 
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2);
         storeValue(rawContactUri2, RawContacts.CUSTOM_RINGTONE, "second");
         storeValue(rawContactUri2, RawContacts.RAW_CONTACT_IS_READ_ONLY, 1);
@@ -7251,23 +7286,23 @@
 
         final long startTime = sMockClock.currentTimeMillis();
 
-        final long rid1 = createRawContactWithName("contact", "a");
+        final long rid1 = RawContactUtil.createRawContactWithName(mResolver, "contact", "a");
         final long did1a = ContentUris.parseId(insertEmail(rid1, "email_1_a@email.com"));
         final long did1b = ContentUris.parseId(insertEmail(rid1, "email_1_b@email.com"));
         final long did1p = ContentUris.parseId(insertPhoneNumber(rid1, "555-555-5555"));
 
-        final long rid2 = createRawContactWithName("contact", "b");
+        final long rid2 = RawContactUtil.createRawContactWithName(mResolver, "contact", "b");
         final long did2a = ContentUris.parseId(insertEmail(rid2, "email_2_a@email.com"));
         final long did2p = ContentUris.parseId(insertPhoneNumber(rid2, "555-555-5556"));
 
         // Aggregate 1 and 2
         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rid1, rid2);
 
-        final long rid3 = createRawContactWithName("contact", "c");
+        final long rid3 = RawContactUtil.createRawContactWithName(mResolver, "contact", "c");
         final long did3a = ContentUris.parseId(insertEmail(rid3, "email_3@email.com"));
         final long did3p = ContentUris.parseId(insertPhoneNumber(rid3, "555-3333"));
 
-        final long rid4 = createRawContactWithName("contact", "d");
+        final long rid4 = RawContactUtil.createRawContactWithName(mResolver, "contact", "d");
         final long did4p = ContentUris.parseId(insertPhoneNumber(rid4, "555-4444"));
 
         final long cid1 = queryContactId(rid1);
@@ -7422,8 +7457,271 @@
         assertTrue(mResolver.delete(DataUsageFeedback.DELETE_USAGE_URI, null, null) > 0);
     }
 
+    /*******************************************************
+     * Delta api tests.
+     */
+    public void testContactDelete_hasDeleteLog() {
+        sMockClock.install();
+        long start = sMockClock.currentTimeMillis();
+        DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete();
+        DatabaseAsserts.assertHasDeleteLogGreaterThan(mResolver, ids.mContactId, start);
+
+        // Clean up. Must also remove raw contact.
+        RawContactUtil.delete(mResolver, ids.mRawContactId, true);
+    }
+
+    public void testContactDelete_marksRawContactsForDeletion() {
+        DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete();
+
+        String[] projection = new String[]{ContactsContract.RawContacts.DIRTY,
+                ContactsContract.RawContacts.DELETED};
+        List<String[]> records = RawContactUtil.queryByContactId(mResolver, ids.mContactId,
+                projection);
+        for (String[] arr : records) {
+            assertEquals("1", arr[0]);
+            assertEquals("1", arr[1]);
+        }
+
+        // Clean up
+        RawContactUtil.delete(mResolver, ids.mRawContactId, true);
+    }
+
+    public void testContactUpdate_updatesContactUpdatedTimestamp() {
+        sMockClock.install();
+        DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
+
+        long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+
+        ContentValues values = new ContentValues();
+        values.put(ContactsContract.Contacts.STARRED, 1);
+
+        sMockClock.advance();
+        ContactUtil.update(mResolver, ids.mContactId, values);
+
+        long newTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+        assertTrue(newTime > baseTime);
+
+        // Clean up
+        RawContactUtil.delete(mResolver, ids.mRawContactId, true);
+    }
+
+    // This implicitly tests the Contact create case.
+    public void testRawContactCreate_updatesContactUpdatedTimestamp() {
+        long startTime = System.currentTimeMillis();
+
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver);
+        long lastUpdated = getContactLastUpdatedTimestampByRawContactId(mResolver, rawContactId);
+
+        assertTrue(lastUpdated > startTime);
+
+        // Clean up
+        RawContactUtil.delete(mResolver, rawContactId, true);
+    }
+
+    public void testRawContactUpdate_updatesContactUpdatedTimestamp() {
+        DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
+
+        long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+
+        ContentValues values = new ContentValues();
+        values.put(ContactsContract.RawContacts.STARRED, 1);
+        RawContactUtil.update(mResolver, ids.mRawContactId, values);
+
+        long newTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+        assertTrue(newTime > baseTime);
+
+        // Clean up
+        RawContactUtil.delete(mResolver, ids.mRawContactId, true);
+    }
+
+    public void testRawContactPsuedoDelete_hasDeleteLogForContact() {
+        DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
+
+        long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+
+        RawContactUtil.delete(mResolver, ids.mRawContactId, false);
+
+        DatabaseAsserts.assertHasDeleteLogGreaterThan(mResolver, ids.mContactId, baseTime);
+
+        // clean up
+        RawContactUtil.delete(mResolver, ids.mRawContactId, true);
+    }
+
+    public void testRawContactDelete_hasDeleteLogForContact() {
+        DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
+
+        long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+
+        RawContactUtil.delete(mResolver, ids.mRawContactId, true);
+
+        DatabaseAsserts.assertHasDeleteLogGreaterThan(mResolver, ids.mContactId, baseTime);
+
+        // already clean
+    }
+
+    private long getContactLastUpdatedTimestampByRawContactId(ContentResolver resolver,
+            long rawContactId) {
+        long contactId = RawContactUtil.queryContactIdByRawContactId(mResolver, rawContactId);
+        MoreAsserts.assertNotEqual(CommonDatabaseUtils.NOT_FOUND, contactId);
+
+        return ContactUtil.queryContactLastUpdatedTimestamp(mResolver, contactId);
+    }
+
+    public void testDataInsert_updatesContactLastUpdatedTimestamp() {
+        sMockClock.install();
+        DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
+        long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+
+        sMockClock.advance();
+        insertPhoneNumberAndReturnDataId(ids.mRawContactId);
+
+        long newTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+        assertTrue(newTime > baseTime);
+
+        // Clean up
+        RawContactUtil.delete(mResolver, ids.mRawContactId, true);
+    }
+
+    public void testDataDelete_updatesContactLastUpdatedTimestamp() {
+        sMockClock.install();
+        DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
+
+        long dataId = insertPhoneNumberAndReturnDataId(ids.mRawContactId);
+
+        long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+
+        sMockClock.advance();
+        DataUtil.delete(mResolver, dataId);
+
+        long newTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+        assertTrue(newTime > baseTime);
+
+        // Clean up
+        RawContactUtil.delete(mResolver, ids.mRawContactId, true);
+    }
+
+    public void testDataUpdate_updatesContactLastUpdatedTimestamp() {
+        sMockClock.install();
+        DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
+
+        long dataId = insertPhoneNumberAndReturnDataId(ids.mRawContactId);
+
+        long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+
+        sMockClock.advance();
+        ContentValues values = new ContentValues();
+        values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, "555-5555");
+        DataUtil.update(mResolver, dataId, values);
+
+        long newTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
+        assertTrue(newTime > baseTime);
+
+        // Clean up
+        RawContactUtil.delete(mResolver, ids.mRawContactId, true);
+    }
+
+    private long insertPhoneNumberAndReturnDataId(long rawContactId) {
+        Uri uri = insertPhoneNumber(rawContactId, "1-800-GOOG-411");
+        return ContentUris.parseId(uri);
+    }
+
+    public void testDeletedContactsDelete_isUnsupported() {
+        final Uri URI = ContactsContract.DeletedContacts.CONTENT_URI;
+        DatabaseAsserts.assertDeleteIsUnsupported(mResolver, URI);
+
+        Uri uri = ContentUris.withAppendedId(URI, 1L);
+        DatabaseAsserts.assertDeleteIsUnsupported(mResolver, uri);
+    }
+
+    public void testDeletedContactsInsert_isUnsupported() {
+        final Uri URI = ContactsContract.DeletedContacts.CONTENT_URI;
+        DatabaseAsserts.assertInsertIsUnsupported(mResolver, URI);
+    }
+
+
+    public void testQueryDeletedContactsByContactId() {
+        DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete();
+
+        MoreAsserts.assertNotEqual(CommonDatabaseUtils.NOT_FOUND,
+                DeletedContactUtil.queryDeletedTimestampForContactId(mResolver, ids.mContactId));
+    }
+
+    public void testQueryDeletedContactsAll() {
+        final int numDeletes = 10;
+
+        // Since we cannot clean out delete log from previous tests, we need to account for that
+        // by querying for the count first.
+        final long startCount = DeletedContactUtil.getCount(mResolver);
+
+        for (int i = 0; i < numDeletes; i++) {
+            assertContactCreateDelete();
+        }
+
+        final long endCount = DeletedContactUtil.getCount(mResolver);
+
+        assertEquals(numDeletes, endCount - startCount);
+    }
+
+    public void testQueryDeletedContactsSinceTimestamp() {
+        sMockClock.install();
+
+        // Before
+        final HashSet<Long> beforeIds = new HashSet<Long>();
+        beforeIds.add(assertContactCreateDelete().mContactId);
+        beforeIds.add(assertContactCreateDelete().mContactId);
+
+        final long start = sMockClock.currentTimeMillis();
+
+        // After
+        final HashSet<Long> afterIds = new HashSet<Long>();
+        afterIds.add(assertContactCreateDelete().mContactId);
+        afterIds.add(assertContactCreateDelete().mContactId);
+        afterIds.add(assertContactCreateDelete().mContactId);
+
+        final String[] projection = new String[]{
+                ContactsContract.DeletedContacts.CONTACT_ID,
+                ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP
+        };
+        final List<String[]> records = DeletedContactUtil.querySinceTimestamp(mResolver, projection,
+                start);
+        for (String[] record : records) {
+            // Check ids to make sure we only have the ones that came after the time.
+            final long contactId = Long.parseLong(record[0]);
+            assertFalse(beforeIds.contains(contactId));
+            assertTrue(afterIds.contains(contactId));
+
+            // Check times to make sure they came after
+            assertTrue(Long.parseLong(record[1]) > start);
+        }
+    }
+
+    /**
+     * Create a contact. Assert it's not present in the delete log. Delete it.
+     * And assert that the contact record is no longer present.
+     *
+     * @return The contact id and raw contact id that was created.
+     */
+    private DatabaseAsserts.ContactIdPair assertContactCreateDelete() {
+        DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
+
+        assertEquals(CommonDatabaseUtils.NOT_FOUND,
+                DeletedContactUtil.queryDeletedTimestampForContactId(mResolver, ids.mContactId));
+
+        sMockClock.advance();
+        ContactUtil.delete(mResolver, ids.mContactId);
+
+        assertFalse(ContactUtil.recordExistsForContactId(mResolver, ids.mContactId));
+
+        return ids;
+    }
+    /**
+     * End delta api tests.
+     ******************************************************/
+
+
     private Cursor queryGroupMemberships(Account account) {
-        Cursor c = mResolver.query(maybeAddAccountQueryParameters(Data.CONTENT_URI, account),
+        Cursor c = mResolver.query(TestUtil.maybeAddAccountQueryParameters(Data.CONTENT_URI,
+                account),
                 new String[]{GroupMembership.GROUP_ROW_ID, GroupMembership.RAW_CONTACT_ID},
                 Data.MIMETYPE + "=?", new String[]{GroupMembership.CONTENT_ITEM_TYPE},
                 GroupMembership.GROUP_SOURCE_ID);
@@ -7475,7 +7773,7 @@
             long groupId, int chatMode) {
         long rawContactId = createRawContact(values, phoneNumber, email, presenceStatus,
                 timesContacted, starred, groupId, chatMode);
-        insertStructuredName(rawContactId, firstName, givenName);
+        DataUtil.insertStructuredName(mResolver, rawContactId, firstName, givenName);
         return rawContactId;
     }
 
@@ -7484,7 +7782,7 @@
             long groupId, int chatMode, boolean isUserProfile) {
         long rawContactId = createRawContact(values, phoneNumber, email, presenceStatus,
                 timesContacted, starred, groupId, chatMode, isUserProfile);
-        insertStructuredName(rawContactId, firstName, givenName);
+        DataUtil.insertStructuredName(mResolver, rawContactId, firstName, givenName);
         return rawContactId;
     }
 
diff --git a/tests/src/com/android/providers/contacts/DirectoryTest.java b/tests/src/com/android/providers/contacts/DirectoryTest.java
index c62824b..99f05ce 100644
--- a/tests/src/com/android/providers/contacts/DirectoryTest.java
+++ b/tests/src/com/android/providers/contacts/DirectoryTest.java
@@ -28,6 +28,8 @@
 import android.provider.ContactsContract.Directory;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import com.android.providers.contacts.testutil.RawContactUtil;
+
 
 /**
  * Unit tests for {@link ContactsProvider2}, directory functionality.
@@ -74,7 +76,8 @@
     }
 
     public void testForwardingToLocalContacts() {
-        long contactId = queryContactId(createRawContactWithName("John", "Doe"));
+        long contactId = queryContactId(RawContactUtil.createRawContactWithName(mResolver, "John",
+                "Doe"));
 
         Uri contentUri = Contacts.CONTENT_URI.buildUpon().appendQueryParameter(
                 ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT)).build();
@@ -92,13 +95,14 @@
     public void testForwardingToLocalInvisibleContacts() {
 
         // Visible because there is no account
-        long contactId1 = queryContactId(createRawContactWithName("Bob", "Parr"));
+        long contactId1 = queryContactId(RawContactUtil.createRawContactWithName(mResolver, "Bob",
+                "Parr"));
 
         Account account = new Account("accountName", "accountType");
         long groupId = createGroup(account, "sid", "def",
                 0 /* visible */,  true /* auto-add */, false /* fav */);
-        long contactId2 = queryContactId(createRawContactWithName("Helen", "Parr",
-                account));
+        long contactId2 = queryContactId(RawContactUtil.createRawContactWithName(mResolver, "Helen",
+                "Parr", account));
 
         Uri contentUri = Contacts.CONTENT_URI.buildUpon().appendQueryParameter(
                 ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.LOCAL_INVISIBLE))
diff --git a/tests/src/com/android/providers/contacts/GlobalSearchSupportTest.java b/tests/src/com/android/providers/contacts/GlobalSearchSupportTest.java
index f63845f..8036289 100644
--- a/tests/src/com/android/providers/contacts/GlobalSearchSupportTest.java
+++ b/tests/src/com/android/providers/contacts/GlobalSearchSupportTest.java
@@ -25,10 +25,12 @@
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.Intents;
 import android.provider.ContactsContract.StatusUpdates;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import com.android.providers.contacts.testutil.DataUtil;
+import com.android.providers.contacts.testutil.RawContactUtil;
+
 /**
  * Unit tests for {@link GlobalSearchSupport}.
  * <p>
@@ -48,8 +50,8 @@
         // Creating an AUTO_ADD group will exclude all ungrouped contacts from global search
         createGroup(account, "any", "any", 0 /* visible */, true /* auto-add */, false /* fav */);
 
-        long rawContactId = createRawContact(account);
-        insertStructuredName(rawContactId, "Deer", "Dough");
+        long rawContactId = RawContactUtil.createRawContact(mResolver, account);
+        DataUtil.insertStructuredName(mResolver, rawContactId, "Deer", "Dough");
 
         // Remove the new contact from all groups
         mResolver.delete(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId
diff --git a/tests/src/com/android/providers/contacts/GroupsTest.java b/tests/src/com/android/providers/contacts/GroupsTest.java
index 15cfc71..fa4e3ff 100644
--- a/tests/src/com/android/providers/contacts/GroupsTest.java
+++ b/tests/src/com/android/providers/contacts/GroupsTest.java
@@ -34,6 +34,8 @@
 
 import com.google.android.collect.Lists;
 
+import com.android.providers.contacts.testutil.RawContactUtil;
+
 import java.util.ArrayList;
 
 /**
@@ -254,7 +256,7 @@
         final Uri groupUri = ContentUris.withAppendedId(Groups.CONTENT_URI, groupId);
 
         // Create contact with specific membership
-        final long rawContactId = this.createRawContact(sTestAccount);
+        final long rawContactId = RawContactUtil.createRawContact(this.mResolver, sTestAccount);
         final long contactId = this.queryContactId(rawContactId);
         final Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
 
@@ -277,7 +279,7 @@
     }
 
     public void testLocalSingleVisible() {
-        final long rawContactId = this.createRawContact();
+        final long rawContactId = RawContactUtil.createRawContact(this.mResolver);
 
         // Single, local contacts should always be visible
         assertRawContactVisible(rawContactId, true);
@@ -285,8 +287,8 @@
 
     public void testLocalMixedVisible() {
         // Aggregate, when mixed with local, should become visible
-        final long rawContactId1 = this.createRawContact();
-        final long rawContactId2 = this.createRawContact(sTestAccount);
+        final long rawContactId1 = RawContactUtil.createRawContact(this.mResolver);
+        final long rawContactId2 = RawContactUtil.createRawContact(this.mResolver, sTestAccount);
 
         final long groupId = this.createGroup(sTestAccount, GROUP_ID, GROUP_ID, 0);
         this.insertGroupMembership(rawContactId2, groupId);
@@ -308,7 +310,7 @@
     }
 
     public void testUngroupedVisible() {
-        final long rawContactId = this.createRawContact(sTestAccount);
+        final long rawContactId = RawContactUtil.createRawContact(this.mResolver, sTestAccount);
 
         final ContentValues values = new ContentValues();
         values.put(Settings.ACCOUNT_NAME, sTestAccount.name);
@@ -329,8 +331,8 @@
     }
 
     public void testMultipleSourcesVisible() {
-        final long rawContactId1 = this.createRawContact(sTestAccount);
-        final long rawContactId2 = this.createRawContact(sSecondAccount);
+        final long rawContactId1 = RawContactUtil.createRawContact(this.mResolver, sTestAccount);
+        final long rawContactId2 = RawContactUtil.createRawContact(this.mResolver, sSecondAccount);
 
         final long groupId = this.createGroup(sTestAccount, GROUP_ID, GROUP_ID, 0);
         this.insertGroupMembership(rawContactId1, groupId);
diff --git a/tests/src/com/android/providers/contacts/SearchIndexManagerTest.java b/tests/src/com/android/providers/contacts/SearchIndexManagerTest.java
index ac6e5e3..dd1bc71 100644
--- a/tests/src/com/android/providers/contacts/SearchIndexManagerTest.java
+++ b/tests/src/com/android/providers/contacts/SearchIndexManagerTest.java
@@ -29,6 +29,9 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.Suppress;
 
+import com.android.providers.contacts.testutil.DataUtil;
+import com.android.providers.contacts.testutil.RawContactUtil;
+
 import java.text.Collator;
 import java.util.Arrays;
 import java.util.Locale;
@@ -46,12 +49,12 @@
 public class SearchIndexManagerTest extends BaseContactsProvider2Test {
 
     public void testSearchIndexForStructuredName() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
-        insertStructuredName(rawContactId, "John", "Doe");
+        DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe");
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, "Bob I. Parr");
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
         values.clear();
         values.put(StructuredName.PREFIX, "Mrs.");
         values.put(StructuredName.GIVEN_NAME, "Helen");
@@ -60,7 +63,7 @@
         values.put(StructuredName.SUFFIX, "PhD");
         values.put(StructuredName.PHONETIC_FAMILY_NAME, "par");
         values.put(StructuredName.PHONETIC_GIVEN_NAME, "helen");
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         assertSearchIndex(
                 contactId, null, "John Doe Bob I Parr Helen I Parr PhD par helen parhelen", null);
@@ -72,11 +75,11 @@
             return;
         }
 
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, "\u695A\u8FAD");    // CHUCI
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         assertSearchIndex(
                 contactId, null, "\u695A\u8FAD \u695A\u8FAD CI \u8FAD CHUCI CC C", null);
@@ -89,10 +92,10 @@
         }
         ContactLocaleUtils.setLocale(Locale.SIMPLIFIED_CHINESE);
 
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, "\u695A\u8FAD");    // CHUCI
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         assertStoredValue(buildSearchUri("\u695A\u8FAD"), SearchSnippetColumns.SNIPPET, null);
         assertStoredValue(buildSearchUri("\u8FAD"), SearchSnippetColumns.SNIPPET, null);
@@ -108,11 +111,11 @@
             return;
         }
 
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, "\uC774\uC0C1\uC77C");    // Lee Sang Il
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         assertSearchIndex(contactId, null,
                 "\uC774\uC0C1\uC77C \uC0C1\uC77C \u1109\u110B \u110B\u1109\u110B", null);
@@ -124,10 +127,10 @@
             return;
         }
 
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, "\uC774\uC0C1\uC77C");   // Lee Sang Il
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         // Full name: Lee Sang Il
         assertStoredValue(buildSearchUri("\uC774\uC0C1\uC77C"), SearchSnippetColumns.SNIPPET, null);
@@ -148,13 +151,13 @@
             return;
         }
 
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
 
         // Sun Woo Young Nyeu
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, "\uC120\uC6B0\uC6A9\uB140");
 
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
 
         // Full name: Sun Woo Young Nyeu
         assertStoredValue(
@@ -172,7 +175,7 @@
     }
 
     public void testSearchIndexForOrganization() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         ContentValues values = new ContentValues();
         values.put(Organization.COMPANY, "Acme Inc.");
@@ -190,7 +193,7 @@
     }
 
     public void testSearchIndexForPhoneNumber() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         insertPhoneNumber(rawContactId, "800555GOOG");
         insertPhoneNumber(rawContactId, "8005551234");
@@ -199,7 +202,7 @@
     }
 
     public void testSearchIndexForEmail() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         insertEmail(rawContactId, "Bob Parr <incredible@android.com>");
         insertEmail(rawContactId, "bob_parr@android.com");
@@ -209,7 +212,7 @@
     }
 
     public void testSearchIndexForNickname() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         insertNickname(rawContactId, "incredible");
 
@@ -217,7 +220,7 @@
     }
 
     public void testSearchIndexForStructuredPostal() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         insertPostalAddress(rawContactId, "1600 Amphitheatre Pkwy\nMountain View, CA 94043");
         ContentValues values = new ContentValues();
@@ -232,7 +235,7 @@
     }
 
     public void testSearchIndexForIm() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         insertImHandle(rawContactId, Im.PROTOCOL_JABBER, null, "bp@android.com");
         insertImHandle(rawContactId, Im.PROTOCOL_CUSTOM, "android_im", "android@android.com");
@@ -242,7 +245,7 @@
     }
 
     public void testSearchIndexForNote() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
         insertNote(rawContactId, "Please note: three notes or more make up a chord.");
 
@@ -251,7 +254,7 @@
     }
 
     public void testSnippetArgs() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         insertNote(rawContactId, "Please note: three notes or more make up a chord.");
 
         assertStoredValue(
@@ -260,12 +263,12 @@
     }
 
     public void testEmptyFilter() {
-        createRawContactWithName("John", "Doe");
+        RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
         assertEquals(0, getCount(buildSearchUri(""), null, null));
     }
 
     public void testSearchByName() {
-        createRawContactWithName("John Jay", "Doe");
+        RawContactUtil.createRawContactWithName(mResolver, "John Jay", "Doe");
 
         // We are supposed to find the contact, but return a null snippet
         assertStoredValue(buildSearchUri("john"), SearchSnippetColumns.SNIPPET, null);
@@ -274,7 +277,7 @@
     }
 
     public void testSearchByPrefixName() {
-        createRawContactWithName("John Jay", "Doe");
+        RawContactUtil.createRawContactWithName(mResolver, "John Jay", "Doe");
 
         // prefix searches
         assertStoredValue(buildSearchUri("jo ja"), SearchSnippetColumns.SNIPPET, null);
@@ -283,7 +286,7 @@
     }
 
     public void testGermanUmlautFullameCapitalizationSearch() {
-        createRawContactWithName("Matthäus BJÖRN Bünyamin", "Reißer");
+        RawContactUtil.createRawContactWithName(mResolver, "Matthäus BJÖRN Bünyamin", "Reißer");
 
         // make sure we can find those, independent of the capitalization
         assertStoredValue(buildSearchUri("matthäus"), SearchSnippetColumns.SNIPPET, null);
@@ -371,7 +374,7 @@
     }
 
     public void testNameWithHyphen() {
-        createRawContactWithName("First", "Last-name");
+        RawContactUtil.createRawContactWithName(mResolver, "First", "Last-name");
 
         assertStoredValue(buildSearchUri("First"), SearchSnippetColumns.SNIPPET, null);
         assertStoredValue(buildSearchUri("Last"), SearchSnippetColumns.SNIPPET, null);
@@ -388,7 +391,7 @@
 
     /** Same as {@link #testNameWithHyphen} except the name has double hyphens. */
     public void testNameWithDoubleHyphens() {
-        createRawContactWithName("First", "Last--name");
+        RawContactUtil.createRawContactWithName(mResolver, "First", "Last--name");
 
         assertStoredValue(buildSearchUri("First"), SearchSnippetColumns.SNIPPET, null);
         assertStoredValue(buildSearchUri("Last"), SearchSnippetColumns.SNIPPET, null);
@@ -401,7 +404,7 @@
     }
 
     public void testNameWithPunctuations() {
-        createRawContactWithName("First", "O'Neill");
+        RawContactUtil.createRawContactWithName(mResolver, "First", "O'Neill");
 
         assertStoredValue(buildSearchUri("first"), SearchSnippetColumns.SNIPPET, null);
         assertStoredValue(buildSearchUri("oneill"), SearchSnippetColumns.SNIPPET, null);
@@ -409,7 +412,7 @@
     }
 
     public void testSearchByEmailAddress() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         insertPhoneNumber(rawContactId, "1234567890");
         insertEmail(rawContactId, "john@doe.com");
         insertNote(rawContactId, "a hundred dollar note for doe@john.com and bob parr");
@@ -422,7 +425,7 @@
     }
 
     public void testSearchByPhoneNumber() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         insertPhoneNumber(rawContactId, "330142685300");
         insertPhoneNumber(rawContactId, "(800)GOOG-123");
         insertEmail(rawContactId, "john@doe.com");
@@ -444,7 +447,7 @@
      * Test case for bug 5904515
      */
     public void testSearchByPhoneNumber_diferSnippetting() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         insertPhoneNumber(rawContactId, "505-123-4567");
 
         // The bug happened with the old code only when we use \u0001 as the snippet marker.
@@ -462,7 +465,7 @@
      * there's no visible breakage.)
      */
     public void testSearchByEmail_diferSnippetting() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         insertEmail(rawContactId, "john@doe.com");
 
         assertStoredValue(buildSearchUri("john", "\u0001,\u0001,\u2026,5", true),
@@ -506,10 +509,10 @@
     }
 
     private void createRawContactWithDisplayName(String name) {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, name);
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
     }
 
     // TODO: expectedName must be tested. Many tests in here are quite useless at the moment
diff --git a/tests/src/com/android/providers/contacts/SqlInjectionDetectionTest.java b/tests/src/com/android/providers/contacts/SqlInjectionDetectionTest.java
index 7b3fe95..e7b80a0 100644
--- a/tests/src/com/android/providers/contacts/SqlInjectionDetectionTest.java
+++ b/tests/src/com/android/providers/contacts/SqlInjectionDetectionTest.java
@@ -27,6 +27,8 @@
 import android.provider.ContactsContract.Contacts;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import com.android.providers.contacts.testutil.RawContactUtil;
+
 /**
  * Unit tests for {@link ContactsProvider2}, to make sure the queries don't allow sql injection.
  *
@@ -41,7 +43,7 @@
     private static final String[] PHONE_ID_PROJECTION = new String[] { Phone._ID };
 
     public void testPhoneQueryValid() {
-        long rawContactId = createRawContactWithName("Hot", "Tamale");
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale");
         insertPhoneNumber(rawContactId, "555-123-4567");
 
         assertQueryValid(Phone.CONTENT_URI, PHONE_ID_PROJECTION,
@@ -49,7 +51,7 @@
     }
 
     public void testPhoneQueryBadProjection() {
-        long rawContactId = createRawContactWithName("Hot", "Tamale");
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale");
         insertPhoneNumber(rawContactId, "555-123-4567");
 
         assertQueryThrows(IllegalArgumentException.class, Phone.CONTENT_URI,
@@ -57,7 +59,7 @@
     }
 
     public void testPhoneQueryBadSelection() {
-        long rawContactId = createRawContactWithName("Hot", "Tamale");
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale");
         insertPhoneNumber(rawContactId, "555-123-4567");
 
         assertQueryThrows(SQLiteException.class, Phone.CONTENT_URI, PHONE_ID_PROJECTION,
@@ -65,7 +67,7 @@
     }
 
     public void testPhoneQueryBadSortOrder() {
-        long rawContactId = createRawContactWithName("Hot", "Tamale");
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale");
         insertPhoneNumber(rawContactId, "555-123-4567");
 
         assertQueryThrows(SQLiteException.class, Phone.CONTENT_URI,
@@ -74,7 +76,7 @@
 
     public void testPhoneQueryBadLimit() {
         // Non-numeric query parameters are ignored by the provider
-        long rawContactId = createRawContactWithName("Hot", "Tamale");
+        long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale");
         insertPhoneNumber(rawContactId, "555-123-4567");
 
         Builder builder = Contacts.CONTENT_FILTER_URI.buildUpon();
diff --git a/tests/src/com/android/providers/contacts/TransactionContextTest.java b/tests/src/com/android/providers/contacts/TransactionContextTest.java
new file mode 100644
index 0000000..084a51f
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/TransactionContextTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Unit tests for TransactionContext.
+ */
+@SmallTest
+public class TransactionContextTest extends TestCase {
+
+    public void testClearExceptSearchIndexUpdates_returnsNewSets() {
+        TransactionContext context = new TransactionContext(false);
+        context.markRawContactDirtyAndChanged(1L, false);
+        context.rawContactUpdated(1L);
+        context.rawContactInserted(1L, 1L);
+        context.syncStateUpdated(1L, new Object());
+
+        context.clearExceptSearchIndexUpdates();
+
+        Set<Long> newDirty = context.getDirtyRawContactIds();
+        Set<Long> newChanged = context.getChangedRawContactIds();
+        Set<Long> newInserted = context.getInsertedRawContactIds();
+        Set<Long> newUpdated = context.getUpdatedRawContactIds();
+        Set<Map.Entry<Long, Object>> newSync = context.getUpdatedSyncStates();
+
+        assertTrue(newDirty.isEmpty());
+        assertTrue(newChanged.isEmpty());
+        assertTrue(newInserted.isEmpty());
+        assertTrue(newUpdated.isEmpty());
+        assertTrue(newSync.isEmpty());
+    }
+
+    public void testMarkDirtyAndChanged_onlyUpdatesChanged() {
+        TransactionContext context = new TransactionContext(false);
+
+        context.markRawContactDirtyAndChanged(1L, true /* isSyncAdapter */);
+
+        assertEquals(1, context.getChangedRawContactIds().size());
+        assertEquals(0, context.getDirtyRawContactIds().size());
+    }
+
+    public void testMarkDirtyAndChanged_onlyUpdatesDirtyAndChanged() {
+        TransactionContext context = new TransactionContext(false);
+
+        context.markRawContactDirtyAndChanged(1L, false /* isSyncAdapter */);
+
+        assertEquals(1, context.getChangedRawContactIds().size());
+        assertEquals(1, context.getDirtyRawContactIds().size());
+    }
+
+    public void testRawContactInserted_affectsChangedContacts() {
+        TransactionContext context = new TransactionContext(false);
+        assertTrue(context.getChangedRawContactIds().isEmpty());
+
+        context.rawContactInserted(1L, 2L);
+        assertEquals(1, context.getChangedRawContactIds().size());
+        assertTrue(context.getChangedRawContactIds().contains(1L));
+
+        context.rawContactInserted(5L, 10L);
+        assertEquals(2, context.getChangedRawContactIds().size());
+        assertTrue(context.getChangedRawContactIds().contains(5L));
+    }
+
+    public void testMarkRawContactChangedOrDeletedOrInserted_affectsChangedContacts() {
+        TransactionContext context = new TransactionContext(false);
+        assertTrue(context.getChangedRawContactIds().isEmpty());
+
+        context.markRawContactChangedOrDeletedOrInserted(1L);
+        assertEquals(1, context.getChangedRawContactIds().size());
+        assertTrue(context.getChangedRawContactIds().contains(1L));
+
+        context.rawContactInserted(5L, 10L);
+        assertEquals(2, context.getChangedRawContactIds().size());
+        assertTrue(context.getChangedRawContactIds().contains(5L));
+    }
+}
diff --git a/tests/src/com/android/providers/contacts/VCardTest.java b/tests/src/com/android/providers/contacts/VCardTest.java
index 820c263..e2d205e 100644
--- a/tests/src/com/android/providers/contacts/VCardTest.java
+++ b/tests/src/com/android/providers/contacts/VCardTest.java
@@ -19,6 +19,7 @@
 import android.content.ContentResolver;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import com.android.providers.contacts.testutil.RawContactUtil;
 import com.android.vcard.VCardComposer;
 import com.android.vcard.VCardConfig;
 
@@ -37,7 +38,7 @@
      * a vCard string.
      */
     public void testCompose() {
-        createRawContactWithName("John", "Doe");
+        RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
         final VCardComposer composer = new VCardComposer(
                 getContext(), mResolver, VCardConfig.VCARD_TYPE_DEFAULT, null, true);
         assertTrue(composer.init());
diff --git a/tests/src/com/android/providers/contacts/aggregation/ContactAggregatorTest.java b/tests/src/com/android/providers/contacts/aggregation/ContactAggregatorTest.java
index 16d06c8..acd830f 100644
--- a/tests/src/com/android/providers/contacts/aggregation/ContactAggregatorTest.java
+++ b/tests/src/com/android/providers/contacts/aggregation/ContactAggregatorTest.java
@@ -39,6 +39,9 @@
 import com.android.providers.contacts.BaseContactsProvider2Test;
 import com.android.providers.contacts.TestUtils;
 import com.android.providers.contacts.tests.R;
+import com.android.providers.contacts.testutil.DataUtil;
+import com.android.providers.contacts.testutil.RawContactUtil;
+
 import com.google.android.collect.Lists;
 
 /**
@@ -64,8 +67,8 @@
     };
 
     public void testCrudAggregationExceptions() throws Exception {
-        long rawContactId1 = createRawContactWithName("zz", "top");
-        long rawContactId2 = createRawContactWithName("aa", "bottom");
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "zz", "top");
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "aa", "bottom");
 
         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
                 rawContactId1, rawContactId2);
@@ -112,9 +115,9 @@
     }
 
     public void testAggregationCreatesNewAggregate() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
 
-        Uri resultUri = insertStructuredName(rawContactId, "Johna", "Smitha");
+        Uri resultUri = DataUtil.insertStructuredName(mResolver, rawContactId, "Johna", "Smitha");
 
         // Parse the URI and confirm that it contains an ID
         assertTrue(ContentUris.parseId(resultUri) != 0);
@@ -127,11 +130,11 @@
     }
 
     public void testAggregationOfExactFullNameMatch() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Johnb", "Smithb");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnb", "Smithb");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Johnb", "Smithb");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnb", "Smithb");
 
         assertAggregated(rawContactId1, rawContactId2, "Johnb Smithb");
     }
@@ -140,17 +143,17 @@
         Account account = new Account("accountName", "accountType");
         createAutoAddGroup(account);
 
-        long rawContactId1 = createRawContact(account);
-        insertStructuredName(rawContactId1, "Flynn", "Ryder");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, account);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder");
 
         // Hide by removing from all groups
         removeGroupMemberships(rawContactId1);
 
-        long rawContactId2 = createRawContact(account);
-        insertStructuredName(rawContactId2, "Flynn", "Ryder");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, account);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder");
 
-        long rawContactId3 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId3, "Flynn", "Ryder");
+        long rawContactId3 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder");
 
         assertNotAggregated(rawContactId1, rawContactId2);
         assertNotAggregated(rawContactId1, rawContactId3);
@@ -158,261 +161,262 @@
     }
 
     public void testAggregationOfCaseInsensitiveFullNameMatch() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Johnc", "Smithc");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnc", "Smithc");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Johnc", "smithc");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnc", "smithc");
 
         assertAggregated(rawContactId1, rawContactId2, "Johnc Smithc");
     }
 
     public void testAggregationOfLastNameMatch() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, null, "Johnd");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, null, "Johnd");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, null, "johnd");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, null, "johnd");
 
         assertAggregated(rawContactId1, rawContactId2, "Johnd");
     }
 
     public void testNonAggregationOfFirstNameMatch() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Johne", "Smithe");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Johne", "Smithe");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Johne", null);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Johne", null);
 
         assertNotAggregated(rawContactId1, rawContactId2);
     }
 
     public void testNonAggregationOfLastNameMatch() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Johnf", "Smithf");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnf", "Smithf");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, null, "Smithf");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, null, "Smithf");
 
         assertNotAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationOfConcatenatedFullNameMatch() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Johng", "Smithg");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Johng", "Smithg");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "johngsmithg", null);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "johngsmithg", null);
 
         assertAggregated(rawContactId1, rawContactId2, "Johng Smithg");
     }
 
     public void testAggregationOfNormalizedFullNameMatch() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "H\u00e9l\u00e8ne", "Bj\u00f8rn");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "H\u00e9l\u00e8ne", "Bj\u00f8rn");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "helene bjorn", null);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "helene bjorn", null);
 
         assertAggregated(rawContactId1, rawContactId2, "H\u00e9l\u00e8ne Bj\u00f8rn");
     }
 
     public void testAggregationOfNormalizedFullNameMatchWithReadOnlyAccount() {
-        long rawContactId1 = createRawContact(new Account("acct", READ_ONLY_ACCOUNT_TYPE));
-        insertStructuredName(rawContactId1, "H\u00e9l\u00e8ne", "Bj\u00f8rn");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, new Account("acct",
+                READ_ONLY_ACCOUNT_TYPE));
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "H\u00e9l\u00e8ne", "Bj\u00f8rn");
 
-        long rawContactId2 = createRawContact();
-        insertStructuredName(rawContactId2, "helene bjorn", null);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "helene bjorn", null);
 
         assertAggregated(rawContactId1, rawContactId2, "helene bjorn");
     }
 
     public void testAggregationOfNumericNames() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "123", null);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "123", null);
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "1-2-3", null);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "1-2-3", null);
 
         assertAggregated(rawContactId1, rawContactId2, "1-2-3");
     }
 
     public void testAggregationOfInconsistentlyParsedNames() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
 
         ContentValues values = new ContentValues();
         values.put(StructuredName.DISPLAY_NAME, "604 Arizona Ave");
         values.put(StructuredName.GIVEN_NAME, "604");
         values.put(StructuredName.MIDDLE_NAME, "Arizona");
         values.put(StructuredName.FAMILY_NAME, "Ave");
-        insertStructuredName(rawContactId1, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, values);
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         values.clear();
         values.put(StructuredName.DISPLAY_NAME, "604 Arizona Ave");
         values.put(StructuredName.GIVEN_NAME, "604");
         values.put(StructuredName.FAMILY_NAME, "Arizona Ave");
-        insertStructuredName(rawContactId2, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, values);
 
         assertAggregated(rawContactId1, rawContactId2, "604 Arizona Ave");
     }
 
     public void testAggregationBasedOnMiddleName() {
         ContentValues values = new ContentValues();
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
         values.put(StructuredName.GIVEN_NAME, "John");
         values.put(StructuredName.GIVEN_NAME, "Abigale");
         values.put(StructuredName.FAMILY_NAME, "James");
 
-        insertStructuredName(rawContactId1, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, values);
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         values.clear();
         values.put(StructuredName.GIVEN_NAME, "John");
         values.put(StructuredName.GIVEN_NAME, "Marie");
         values.put(StructuredName.FAMILY_NAME, "James");
-        insertStructuredName(rawContactId2, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, values);
 
         assertNotAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationBasedOnPhoneNumberNoNameData() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
         insertPhoneNumber(rawContactId1, "(888)555-1231");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         insertPhoneNumber(rawContactId2, "1(888)555-1231");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationBasedOnPhoneNumberWhenTargetAggregateHasNoName() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
         insertPhoneNumber(rawContactId1, "(888)555-1232");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Johnl", "Smithl");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnl", "Smithl");
         insertPhoneNumber(rawContactId2, "1(888)555-1232");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationBasedOnPhoneNumberWhenNewContactHasNoName() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Johnm", "Smithm");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnm", "Smithm");
         insertPhoneNumber(rawContactId1, "(888)555-1233");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         insertPhoneNumber(rawContactId2, "1(888)555-1233");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationBasedOnPhoneNumberWithDifferentNames() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Baby", "Bear");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Baby", "Bear");
         insertPhoneNumber(rawContactId1, "(888)555-1235");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Blind", "Mouse");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Blind", "Mouse");
         insertPhoneNumber(rawContactId2, "1(888)555-1235");
 
         assertNotAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationBasedOnPhoneNumberWithJustFirstName() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Chick", "Notnull");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Chick", "Notnull");
         insertPhoneNumber(rawContactId1, "(888)555-1236");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Chick", null);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Chick", null);
         insertPhoneNumber(rawContactId2, "1(888)555-1236");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationBasedOnEmailNoNameData() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
         insertEmail(rawContactId1, "lightning@android.com");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         insertEmail(rawContactId2, "lightning@android.com");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationBasedOnEmailWhenTargetAggregateHasNoName() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
         insertEmail(rawContactId1, "mcqueen@android.com");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Lightning", "McQueen");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Lightning", "McQueen");
         insertEmail(rawContactId2, "mcqueen@android.com");
 
         assertAggregated(rawContactId1, rawContactId2, "Lightning McQueen");
     }
 
     public void testAggregationBasedOnEmailWhenNewContactHasNoName() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Doc", "Hudson");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Doc", "Hudson");
         insertEmail(rawContactId1, "doc@android.com");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         insertEmail(rawContactId2, "doc@android.com");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationBasedOnEmailWithDifferentNames() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Chick", "Hicks");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Chick", "Hicks");
         insertEmail(rawContactId1, "hicky@android.com");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Luigi", "Guido");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Luigi", "Guido");
         insertEmail(rawContactId2, "hicky@android.com");
 
         assertNotAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationByCommonNicknameWithLastName() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Bill", "Gore");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Bill", "Gore");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "William", "Gore");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "William", "Gore");
 
         assertAggregated(rawContactId1, rawContactId2, "William Gore");
     }
 
     public void testAggregationByCommonNicknameOnly() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Lawrence", null);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Lawrence", null);
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Larry", null);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Larry", null);
 
         assertAggregated(rawContactId1, rawContactId2, "Lawrence");
     }
 
     public void testAggregationByNicknameNoStructuredName() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
         insertNickname(rawContactId1, "Frozone");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         insertNickname(rawContactId2, "Frozone");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationByNicknameWithDifferentNames() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Helen", "Parr");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Helen", "Parr");
         insertNickname(rawContactId1, "Elastigirl");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Shawn", "Johnson");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Shawn", "Johnson");
         insertNickname(rawContactId2, "Elastigirl");
 
         assertNotAggregated(rawContactId1, rawContactId2);
@@ -421,11 +425,11 @@
     public void testNonAggregationOnOrganization() {
         ContentValues values = new ContentValues();
         values.put(Organization.TITLE, "Monsters, Inc");
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
         insertOrganization(rawContactId1, values);
         insertNickname(rawContactId1, "Boo");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         insertOrganization(rawContactId2, values);
         insertNickname(rawContactId2, "Rendall");   // To force reaggregation
 
@@ -433,21 +437,21 @@
     }
 
     public void testAggregationByIdentity() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
         insertIdentity(rawContactId1, "iden1", "namespace1");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         insertIdentity(rawContactId2, "iden1", "namespace1");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationExceptionKeepIn() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Johnk", "Smithk");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnk", "Smithk");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Johnkx", "Smithkx");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnkx", "Smithkx");
 
         long contactId1 = queryContactId(rawContactId1);
         long contactId2 = queryContactId(rawContactId2);
@@ -471,11 +475,11 @@
     }
 
     public void testAggregationExceptionKeepOut() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Johnh", "Smithh");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Johnh", "Smithh");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Johnh", "Smithh");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnh", "Smithh");
 
         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
                 rawContactId1, rawContactId2);
@@ -484,14 +488,14 @@
     }
 
     public void testAggregationExceptionKeepOutCheckUpdatesDisplayName() {
-        long rawContactId1 = createRawContact(ACCOUNT_1);
-        insertStructuredName(rawContactId1, "Johni", "Smithi");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Johni", "Smithi");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Johnj", "Smithj");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Johnj", "Smithj");
 
-        long rawContactId3 = createRawContact(ACCOUNT_3);
-        insertStructuredName(rawContactId3, "Johnm", "Smithm");
+        long rawContactId3 = RawContactUtil.createRawContact(mResolver, ACCOUNT_3);
+        DataUtil.insertStructuredName(mResolver, rawContactId3, "Johnm", "Smithm");
 
         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
                 rawContactId1, rawContactId2);
@@ -533,9 +537,9 @@
     }
 
     public void testAggregationExceptionKeepOutCheckResultDisplayNames() {
-        long rawContactId1 = createRawContactWithName("c", "c", ACCOUNT_1);
-        long rawContactId2 = createRawContactWithName("b", "b", ACCOUNT_2);
-        long rawContactId3 = createRawContactWithName("a", "a", ACCOUNT_3);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "c", "c", ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "b", "b", ACCOUNT_2);
+        long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "a", "a", ACCOUNT_3);
 
         // Join all contacts
         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
@@ -569,12 +573,15 @@
     }
 
     public void testNonAggregationWithMultipleAffinities() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         assertNotAggregated(rawContactId1, rawContactId2);
 
         // There are two aggregates this raw contact could join, so it should join neither
-        long rawContactId3 = createRawContactWithName("John", "Doe", ACCOUNT_2);
+        long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_2);
         assertNotAggregated(rawContactId1, rawContactId3);
         assertNotAggregated(rawContactId2, rawContactId3);
 
@@ -583,13 +590,16 @@
     }
 
     public void testSplitBecauseOfMultipleAffinities() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_2);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_2);
         assertAggregated(rawContactId1, rawContactId2);
 
         // The aggregate this raw contact could join has a raw contact from the same account,
         // let's not aggregate and break up the existing aggregate because of the ambiguity
-        long rawContactId3 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         assertNotAggregated(rawContactId1, rawContactId3);
         assertNotAggregated(rawContactId2, rawContactId3);
         assertNotAggregated(rawContactId1, rawContactId2);
@@ -599,14 +609,14 @@
         Account account = new Account("accountName", "accountType");
         createAutoAddGroup(account);
 
-        long rawContactId1 = createRawContact(account);
-        insertStructuredName(rawContactId1, "Flynn", "Ryder");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, account);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Flynn", "Ryder");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder");
 
-        long rawContactId3 = createRawContact(account);
-        insertStructuredName(rawContactId3, "Flynn", "Ryder");
+        long rawContactId3 = RawContactUtil.createRawContact(mResolver, account);
+        DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder");
 
         assertNotAggregated(rawContactId1, rawContactId3);
         assertNotAggregated(rawContactId2, rawContactId3);
@@ -624,15 +634,15 @@
         Account account = new Account("accountName", "accountType");
         createAutoAddGroup(account);
 
-        long rawContactId1 = createRawContact(account);
-        insertStructuredName(rawContactId1, "Flynn", "Ryder");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, account);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder");
         insertPhoneNumber(rawContactId1, "1234567890");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         insertPhoneNumber(rawContactId2, "1234567890");
 
-        long rawContactId3 = createRawContact(account);
-        insertStructuredName(rawContactId3, "Flynn", "Ryder");
+        long rawContactId3 = RawContactUtil.createRawContact(mResolver, account);
+        DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder");
 
         assertNotAggregated(rawContactId1, rawContactId3);
         assertNotAggregated(rawContactId2, rawContactId3);
@@ -650,15 +660,15 @@
         Account account = new Account("accountName", "accountType");
         long groupId = createAutoAddGroup(account);
 
-        long rawContactId1 = createRawContact(account);
-        insertStructuredName(rawContactId1, "Flynn", "Ryder");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, account);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
-        insertStructuredName(rawContactId2, "Flynn", "Ryder");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder");
 
-        long rawContactId3 = createRawContact(account);
+        long rawContactId3 = RawContactUtil.createRawContact(mResolver, account);
         removeGroupMemberships(rawContactId3);
-        insertStructuredName(rawContactId3, "Flynn", "Ryder");
+        DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder");
 
         assertAggregated(rawContactId1, rawContactId2, "Flynn Ryder");
         assertNotAggregated(rawContactId1, rawContactId3);
@@ -672,9 +682,12 @@
     }
 
     public void testNonSplitBecauseOfMultipleAffinitiesWhenOverridden() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_2);
-        long rawContactId3 = createRawContactWithName("John", "Doe", ACCOUNT_3);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_2);
+        long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_3);
         assertAggregated(rawContactId1, rawContactId2);
         assertAggregated(rawContactId1, rawContactId3);
         setAggregationException(
@@ -684,7 +697,8 @@
 
         // The aggregate this raw contact could join has a raw contact from the same account,
         // let's not aggregate and break up the existing aggregate because of the ambiguity
-        long rawContactId4 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId4 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         assertAggregated(rawContactId1, rawContactId2);     // Aggregation exception
         assertNotAggregated(rawContactId1, rawContactId3);
         assertNotAggregated(rawContactId1, rawContactId4);
@@ -692,18 +706,22 @@
     }
 
     public void testNonAggregationFromSameAccount() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         assertNotAggregated(rawContactId1, rawContactId2);
     }
 
     public void testNonAggregationFromSameAccountNoCommonData() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertEmail(rawContactId1, "lightning1@android.com");
         insertPhoneNumber(rawContactId1, "111-222-3333");
         insertIdentity(rawContactId1, "iden1", "namespace");
 
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertEmail(rawContactId2, "lightning2@android.com");
         insertPhoneNumber(rawContactId2, "555-666-7777");
         insertIdentity(rawContactId1, "iden2", "namespace");
@@ -712,20 +730,24 @@
     }
 
     public void testAggregationFromSameAccountEmailSame() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertEmail(rawContactId1, "lightning@android.com");
 
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertEmail(rawContactId2, "lightning@android.com");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testNonAggregationFromSameAccountEmailDifferent() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertEmail(rawContactId1, "lightning1@android.com");
 
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertEmail(rawContactId2, "lightning2@android.com");
         insertEmail(rawContactId2, "lightning3@android.com");
 
@@ -733,21 +755,25 @@
     }
 
     public void testAggregationFromSameAccountIdentitySame() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertIdentity(rawContactId1, "iden", "namespace");
 
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertIdentity(rawContactId2, "iden", "namespace");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testNonAggregationFromSameAccountIdentityDifferent() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertIdentity(rawContactId1, "iden1", "namespace1");
         insertIdentity(rawContactId1, "iden2", "namespace2");
 
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertIdentity(rawContactId2, "iden2", "namespace1");
         insertIdentity(rawContactId2, "iden1", "namespace2");
 
@@ -755,52 +781,58 @@
     }
 
     public void testAggregationFromSameAccountPhoneNumberSame() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertPhoneNumber(rawContactId1, "111-222-3333");
 
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertPhoneNumber(rawContactId2, "111-222-3333");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationFromSameAccountPhoneNumberNormalizedSame() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertPhoneNumber(rawContactId1, "111-222-3333");
 
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertPhoneNumber(rawContactId2, "+1-111-222-3333");
 
         assertAggregated(rawContactId1, rawContactId2);
     }
 
     public void testNonAggregationFromSameAccountPhoneNumberDifferent() {
-        long rawContactId1 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertPhoneNumber(rawContactId1, "111-222-3333");
 
-        long rawContactId2 = createRawContactWithName("John", "Doe", ACCOUNT_1);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe",
+                ACCOUNT_1);
         insertPhoneNumber(rawContactId2, "111-222-3334");
 
         assertNotAggregated(rawContactId1, rawContactId2);
     }
 
     public void testAggregationSuggestionsBasedOnName() {
-        long rawContactId1 = createRawContact();
-        insertStructuredName(rawContactId1, "Duane", null);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Duane", null);
 
         // Exact name match
-        long rawContactId2 = createRawContact();
-        insertStructuredName(rawContactId2, "Duane", null);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Duane", null);
         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
                 rawContactId1, rawContactId2);
 
         // Edit distance == 0.84
-        long rawContactId3 = createRawContact();
-        insertStructuredName(rawContactId3, "Dwayne", null);
+        long rawContactId3 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId3, "Dwayne", null);
 
         // Edit distance == 0.6
-        long rawContactId4 = createRawContact();
-        insertStructuredName(rawContactId4, "Donny", null);
+        long rawContactId4 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId4, "Donny", null);
 
         long contactId1 = queryContactId(rawContactId1);
         long contactId2 = queryContactId(rawContactId2);
@@ -812,12 +844,12 @@
     public void testAggregationSuggestionsBasedOnPhoneNumber() {
 
         // Create two contacts that would not be aggregated because of name mismatch
-        long rawContactId1 = createRawContact();
-        insertStructuredName(rawContactId1, "Lord", "Farquaad");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Lord", "Farquaad");
         insertPhoneNumber(rawContactId1, "(888)555-1236");
 
-        long rawContactId2 = createRawContact();
-        insertStructuredName(rawContactId2, "Talking", "Donkey");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Talking", "Donkey");
         insertPhoneNumber(rawContactId2, "1(888)555-1236");
 
         long contactId1 = queryContactId(rawContactId1);
@@ -830,12 +862,12 @@
     public void testAggregationSuggestionsBasedOnEmailAddress() {
 
         // Create two contacts that would not be aggregated because of name mismatch
-        long rawContactId1 = createRawContact();
-        insertStructuredName(rawContactId1, "Carl", "Fredricksen");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Carl", "Fredricksen");
         insertEmail(rawContactId1, "up@android.com");
 
-        long rawContactId2 = createRawContact();
-        insertStructuredName(rawContactId2, "Charles", "Muntz");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Charles", "Muntz");
         insertEmail(rawContactId2, "up@android.com");
 
         long contactId1 = queryContactId(rawContactId1);
@@ -848,12 +880,12 @@
     public void testAggregationSuggestionsBasedOnEmailAddressApproximateMatch() {
 
         // Create two contacts that would not be aggregated because of name mismatch
-        long rawContactId1 = createRawContact();
-        insertStructuredName(rawContactId1, "Bob", null);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Bob", null);
         insertEmail(rawContactId1, "incredible@android.com");
 
-        long rawContactId2 = createRawContact();
-        insertStructuredName(rawContactId2, "Lucius", "Best");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Lucius", "Best");
         insertEmail(rawContactId2, "incrediball@android.com");
 
         long contactId1 = queryContactId(rawContactId1);
@@ -864,12 +896,12 @@
     }
 
     public void testAggregationSuggestionsBasedOnNickname() {
-        long rawContactId1 = createRawContact();
-        insertStructuredName(rawContactId1, "Peter", "Parker");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Peter", "Parker");
         insertNickname(rawContactId1, "Spider-Man");
 
-        long rawContactId2 = createRawContact();
-        insertStructuredName(rawContactId2, "Manny", "Spider");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Manny", "Spider");
 
         long contactId1 = queryContactId(rawContactId1);
         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
@@ -880,12 +912,12 @@
     }
 
     public void testAggregationSuggestionsBasedOnNicknameMatchingName() {
-        long rawContactId1 = createRawContact();
-        insertStructuredName(rawContactId1, "Clark", "Kent");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Clark", "Kent");
         insertNickname(rawContactId1, "Superman");
 
-        long rawContactId2 = createRawContact();
-        insertStructuredName(rawContactId2, "Roy", "Williams");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Roy", "Williams");
         insertNickname(rawContactId2, "superman");
 
         long contactId1 = queryContactId(rawContactId1);
@@ -897,11 +929,11 @@
     }
 
     public void testAggregationSuggestionsBasedOnCommonNickname() {
-        long rawContactId1 = createRawContact();
-        insertStructuredName(rawContactId1, "Dick", "Cherry");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Dick", "Cherry");
 
-        long rawContactId2 = createRawContact();
-        insertStructuredName(rawContactId2, "Richard", "Cherry");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Richard", "Cherry");
 
         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
                 rawContactId1, rawContactId2);
@@ -914,12 +946,12 @@
     public void testAggregationSuggestionsBasedOnPhoneNumberWithFilter() {
 
         // Create two contacts that would not be aggregated because of name mismatch
-        long rawContactId1 = createRawContact();
-        insertStructuredName(rawContactId1, "Lord", "Farquaad");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId1, "Lord", "Farquaad");
         insertPhoneNumber(rawContactId1, "(888)555-1236");
 
-        long rawContactId2 = createRawContact();
-        insertStructuredName(rawContactId2, "Talking", "Donkey");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "Talking", "Donkey");
         insertPhoneNumber(rawContactId2, "1(888)555-1236");
 
         long contactId1 = queryContactId(rawContactId1);
@@ -933,13 +965,15 @@
     }
 
     public void testAggregationSuggestionsDontSuggestInvisible() {
-        long rawContactId1 = createRawContactWithName("first", "last", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "first", "last",
+                ACCOUNT_1);
         insertPhoneNumber(rawContactId1, "111-222-3333");
         insertNickname(rawContactId1, "Superman");
         insertEmail(rawContactId1, "incredible@android.com");
 
         // Create another with the exact same name, phone number, nickname and email.
-        long rawContactId2 = createRawContactWithName("first", "last", ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "first", "last",
+                ACCOUNT_2);
         insertPhoneNumber(rawContactId2, "111-222-3333");
         insertNickname(rawContactId2, "Superman");
         insertEmail(rawContactId2, "incredible@android.com");
@@ -965,15 +999,15 @@
     }
 
     public void testChoosePhotoSetBeforeAggregation() {
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId1, "donut", "donut_act");
         insertPhoto(rawContactId1);
 
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
         long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2));
 
-        long rawContactId3 = createRawContact();
+        long rawContactId3 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId3, "froyo", "froyo_act");
         insertPhoto(rawContactId3);
 
@@ -985,17 +1019,17 @@
     }
 
     public void testChoosePhotoSetAfterAggregation() {
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId1, "donut", "donut_act");
         insertPhoto(rawContactId1);
 
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
                 rawContactId1, rawContactId2);
         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
         long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2));
 
-        long rawContactId3 = createRawContact();
+        long rawContactId3 = RawContactUtil.createRawContact(mResolver);
         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
                 rawContactId1, rawContactId3);
         setContactAccount(rawContactId3, "froyo", "froyo_act");
@@ -1015,7 +1049,7 @@
 
     public void testChooseLargerPhotoByDimensions() {
         // Donut photo is 256x256.
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId1, "donut", "donut_act");
         long normalEarthDataId = ContentUris.parseId(
                 insertPhoto(rawContactId1, R.drawable.earth_normal));
@@ -1024,7 +1058,7 @@
                 Photo.PHOTO_FILE_ID);
 
         // Cupcake would normally have priority, but its photo is 200x200.
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
         insertPhoto(rawContactId2, R.drawable.earth_200);
 
@@ -1037,7 +1071,7 @@
 
     public void testChooseLargerPhotoByFileSize() {
         // Donut photo is a 256x256 photo of a nebula.
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId1, "donut", "donut_act");
         long nebulaDataId = ContentUris.parseId(
                 insertPhoto(rawContactId1, R.drawable.nebula));
@@ -1047,7 +1081,7 @@
 
         // Cupcake would normally have priority, but its photo (of a galaxy) has the same dimensions
         // as Donut's, but a smaller filesize.
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
         insertPhoto(rawContactId2, R.drawable.galaxy);
 
@@ -1060,7 +1094,7 @@
 
     public void testChooseFilePhotoOverThumbnail() {
         // Donut photo is a 256x256 photo of Earth.
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId1, "donut", "donut_act");
         long normalEarthDataId = ContentUris.parseId(
                 insertPhoto(rawContactId1, R.drawable.earth_normal));
@@ -1069,7 +1103,7 @@
                 Photo.PHOTO_FILE_ID);
 
         // Cupcake would normally have priority, but its photo of Earth is thumbnail-sized.
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
         insertPhoto(rawContactId2, R.drawable.earth_small);
 
@@ -1082,12 +1116,12 @@
 
     public void testFallbackToAccountPriorityForSamePhoto() {
         // Donut photo is a 256x256 photo of Earth.
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId1, "donut", "donut_act");
         insertPhoto(rawContactId1, R.drawable.earth_normal);
 
         // Cupcake has the same 256x256 photo of Earth.
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
         long cupcakeEarthDataId = ContentUris.parseId(
                 insertPhoto(rawContactId2, R.drawable.earth_normal));
@@ -1104,13 +1138,13 @@
 
     public void testFallbackToAccountPriorityForDifferingThumbnails() {
         // Donut photo is a 96x96 thumbnail of Earth.
-        long rawContactId1 = createRawContact();
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId1, "donut", "donut_act");
         insertPhoto(rawContactId1, R.drawable.earth_small);
 
         // Cupcake photo is the 96x96 "no contact" placeholder (smaller filesize than the Earth
         // picture, but thumbnail filesizes are ignored in the aggregator).
-        long rawContactId2 = createRawContact();
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
         setContactAccount(rawContactId2, "cupcake", "cupcake_act");
         long cupcakeDataId = ContentUris.parseId(
                 insertPhoto(rawContactId2, R.drawable.ic_contact_picture));
@@ -1123,7 +1157,7 @@
     }
 
     public void testDisplayNameSources() {
-        long rawContactId = createRawContact();
+        long rawContactId = RawContactUtil.createRawContact(mResolver);
         long contactId = queryContactId(rawContactId);
 
         assertNull(queryDisplayName(contactId));
@@ -1145,15 +1179,18 @@
         values.clear();
         values.put(StructuredName.GIVEN_NAME, "Eclair");
         values.put(StructuredName.FAMILY_NAME, "Android");
-        insertStructuredName(rawContactId, values);
+        DataUtil.insertStructuredName(mResolver, rawContactId, values);
         assertEquals("Eclair Android", queryDisplayName(contactId));
     }
 
     public void testVerifiedName() {
-        long rawContactId1 = createRawContactWithName("test1", "TEST1", ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "test1", "TEST1",
+                ACCOUNT_1);
         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, "1");
-        long rawContactId2 = createRawContactWithName("test2", "TEST2", ACCOUNT_2);
-        long rawContactId3 = createRawContactWithName("test3", "TEST3 LONG", ACCOUNT_3);
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "test2", "TEST2",
+                ACCOUNT_2);
+        long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "test3",
+                "TEST3 LONG", ACCOUNT_3);
 
         setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1,
                 rawContactId2);
@@ -1179,15 +1216,15 @@
     public void testAggregationModeSuspendedSeparateTransactions() {
 
         // Setting aggregation mode to SUSPENDED should prevent aggregation from happening
-        long rawContactId1 = createRawContact(ACCOUNT_1);
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1);
         storeValue(RawContacts.CONTENT_URI, rawContactId1,
                 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
-        Uri name1 = insertStructuredName(rawContactId1, "THE", "SAME");
+        Uri name1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "THE", "SAME");
 
-        long rawContactId2 = createRawContact(ACCOUNT_2);
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2);
         storeValue(RawContacts.CONTENT_URI, rawContactId2,
                 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
-        insertStructuredName(rawContactId2, "THE", "SAME");
+        DataUtil.insertStructuredName(mResolver, rawContactId2, "THE", "SAME");
 
         assertNotAggregated(rawContactId1, rawContactId2);
 
@@ -1365,12 +1402,12 @@
     }
 
     public void testAggregatedStatusUpdate() {
-        long rawContactId1 = createRawContact();
-        Uri dataUri1 = insertStructuredName(rawContactId1, "john", "doe");
+        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
+        Uri dataUri1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "john", "doe");
         insertStatusUpdate(ContentUris.parseId(dataUri1), StatusUpdates.AWAY, "Green", 100,
                 StatusUpdates.CAPABILITY_HAS_CAMERA);
-        long rawContactId2 = createRawContact();
-        Uri dataUri2 = insertStructuredName(rawContactId2, "john", "doe");
+        long rawContactId2 = RawContactUtil.createRawContact(mResolver);
+        Uri dataUri2 = DataUtil.insertStructuredName(mResolver, rawContactId2, "john", "doe");
         insertStatusUpdate(ContentUris.parseId(dataUri2), StatusUpdates.AVAILABLE, "Red", 50,
                 StatusUpdates.CAPABILITY_HAS_CAMERA);
         setAggregationException(
@@ -1391,8 +1428,8 @@
     }
 
     public void testAggregationSuggestionsByName() throws Exception {
-        long rawContactId1 = createRawContactWithName("first1", "last1");
-        long rawContactId2 = createRawContactWithName("first2", "last2");
+        long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "first1", "last1");
+        long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "first2", "last2");
 
         Uri uri = AggregationSuggestions.builder()
                 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "last1 first1")
diff --git a/tests/src/com/android/providers/contacts/database/MoreDatabaseUtilTest.java b/tests/src/com/android/providers/contacts/database/MoreDatabaseUtilTest.java
new file mode 100644
index 0000000..6eb8b55
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/database/MoreDatabaseUtilTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.database;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for MoreDatabaseutil.
+ */
+@SmallTest
+public class MoreDatabaseUtilTest extends TestCase {
+
+    public void testBuildBindArgString() {
+        assertEquals("?", MoreDatabaseUtils.buildBindArgString(1));
+        assertEquals("?,?", MoreDatabaseUtils.buildBindArgString(2));
+        assertEquals("?,?,?", MoreDatabaseUtils.buildBindArgString(3));
+        assertEquals("?,?,?,?", MoreDatabaseUtils.buildBindArgString(4));
+    }
+
+    public void testBuildIndex() {
+        String expected = "create index testtable_testfield_index on testtable(testfield)";
+        String actual = MoreDatabaseUtils.buildCreateIndexSql("testtable", "testfield")
+                .toLowerCase();
+        assertEquals(expected, actual);
+
+        expected = "create index test_table_test_field_index on test_table(test_field)";
+        actual = MoreDatabaseUtils.buildCreateIndexSql("test_table", "test_field").toLowerCase();
+        assertEquals(expected, actual);
+    }
+
+    public void testDropIndex() {
+        String expected = "drop index if exists testtable_testfield_index";
+        String actual = MoreDatabaseUtils.buildDropIndexSql("testtable", "testfield").toLowerCase();
+        assertEquals(expected, actual);
+    }
+
+    public void testBuildIndexName() {
+        assertEquals("testtable_testfield_index",
+                MoreDatabaseUtils.buildIndexName("testtable", "testfield"));
+    }
+}
diff --git a/tests/src/com/android/providers/contacts/testutil/CommonDatabaseUtils.java b/tests/src/com/android/providers/contacts/testutil/CommonDatabaseUtils.java
new file mode 100644
index 0000000..bba5978
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/testutil/CommonDatabaseUtils.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.testutil;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Common database methods.
+ */
+public class CommonDatabaseUtils {
+
+    // primitive value used when record is not found.
+    public static final long NOT_FOUND = -1;
+
+    public static String[] singleRecordToArray(Cursor cursor) {
+        String[] result = null;
+        try {
+            if (cursor.moveToNext()) {
+                result = new String[cursor.getColumnCount()];
+                fillArray(cursor, result);
+            }
+        } finally {
+            closeQuietly(cursor);
+        }
+        return result;
+    }
+
+    public static List<String[]> multiRecordToArray(Cursor cursor) {
+        ArrayList<String[]> result = new ArrayList<String[]>();
+        try {
+            while (cursor.moveToNext()) {
+                String[] record = new String[cursor.getColumnCount()];
+                fillArray(cursor, record);
+                result.add(record);
+            }
+        } finally {
+            closeQuietly(cursor);
+        }
+        return result;
+    }
+
+    private static void fillArray(Cursor cursor, String[] array) {
+        for (int i = 0; i < array.length; i++) {
+            array[i] = cursor.getString(i);
+        }
+    }
+
+    public static void closeQuietly(Cursor cursor) {
+        if (cursor != null) {
+            cursor.close();
+        }
+    }
+
+    public static void extrasVarArgsToValues(ContentValues values, String... extras) {
+        for (int i = 0; i < extras.length; ) {
+            values.put(extras[i], extras[i + 1]);
+            i += 2;
+        }
+    }
+}
diff --git a/tests/src/com/android/providers/contacts/testutil/ContactUtil.java b/tests/src/com/android/providers/contacts/testutil/ContactUtil.java
new file mode 100644
index 0000000..442c5e7
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/testutil/ContactUtil.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.testutil;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+
+/**
+ * Convenience methods for operating on the Contacts table.
+ */
+public class ContactUtil {
+
+    private static final Uri URI = ContactsContract.Contacts.CONTENT_URI;
+
+    public static void update(ContentResolver resolver, long contactId,
+            ContentValues values) {
+        Uri uri = ContentUris.withAppendedId(URI, contactId);
+        resolver.update(uri, values, null, null);
+    }
+
+    public static void delete(ContentResolver resolver, long contactId) {
+        Uri uri = ContentUris.withAppendedId(URI, contactId);
+        resolver.delete(uri, null, null);
+    }
+
+    public static boolean recordExistsForContactId(ContentResolver resolver, long contactId) {
+        String[] projection = new String[]{
+                ContactsContract.Contacts._ID
+        };
+        Uri uri = ContentUris.withAppendedId(URI, contactId);
+        Cursor cursor = resolver.query(uri, projection, null, null, null);
+        if (cursor.moveToNext()) {
+            return true;
+        }
+        return false;
+    }
+
+    public static long queryContactLastUpdatedTimestamp(ContentResolver resolver, long contactId) {
+        String[] projection = new String[]{
+                ContactsContract.Contacts.CONTACT_LAST_UPDATED_TIMESTAMP
+        };
+
+        Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
+        Cursor cursor = resolver.query(uri, projection, null, null, null);
+        try {
+            if (cursor.moveToNext()) {
+                return cursor.getLong(0);
+            }
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+        return CommonDatabaseUtils.NOT_FOUND;
+    }
+}
diff --git a/tests/src/com/android/providers/contacts/testutil/DataUtil.java b/tests/src/com/android/providers/contacts/testutil/DataUtil.java
new file mode 100644
index 0000000..874aacf
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/testutil/DataUtil.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.testutil;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.test.mock.MockContentResolver;
+
+/**
+ * Convenience methods for operating on the Data table.
+ */
+public class DataUtil {
+
+    private static final Uri URI = ContactsContract.Data.CONTENT_URI;
+
+    public static void delete(ContentResolver resolver, long dataId) {
+        Uri uri = ContentUris.withAppendedId(URI, dataId);
+        resolver.delete(uri, null, null);
+    }
+
+    public static void update(ContentResolver resolver, long dataId, ContentValues values) {
+        Uri uri = ContentUris.withAppendedId(URI, dataId);
+        resolver.update(uri, values, null, null);
+    }
+
+    public static Uri insertStructuredName(ContentResolver resolver, long rawContactId,
+            ContentValues values) {
+        values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
+        values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
+        Uri resultUri = resolver.insert(ContactsContract.Data.CONTENT_URI, values);
+        return resultUri;
+    }
+
+    public static Uri insertStructuredName(ContentResolver resolver, long rawContactId,
+            String givenName, String familyName) {
+        ContentValues values = new ContentValues();
+        StringBuilder sb = new StringBuilder();
+        if (givenName != null) {
+            sb.append(givenName);
+        }
+        if (givenName != null && familyName != null) {
+            sb.append(" ");
+        }
+        if (familyName != null) {
+            sb.append(familyName);
+        }
+        values.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, sb.toString());
+        values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, givenName);
+        values.put(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, familyName);
+
+        return insertStructuredName(resolver, rawContactId, values);
+    }
+}
diff --git a/tests/src/com/android/providers/contacts/testutil/DatabaseAsserts.java b/tests/src/com/android/providers/contacts/testutil/DatabaseAsserts.java
new file mode 100644
index 0000000..ac4df17
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/testutil/DatabaseAsserts.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.testutil;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.net.Uri;
+import android.test.MoreAsserts;
+
+import junit.framework.Assert;
+
+/**
+ * Common methods for asserting database related operations.
+ */
+public class DatabaseAsserts {
+
+    public static void assertDeleteIsUnsupported(ContentResolver resolver, Uri uri) {
+        try {
+            resolver.delete(uri, null, null);
+            Assert.fail("delete operation should have failed with UnsupportedOperationException on"
+                    + uri);
+        } catch (UnsupportedOperationException e) {
+            // pass
+        }
+    }
+
+    public static void assertInsertIsUnsupported(ContentResolver resolver, Uri  uri) {
+        try {
+            ContentValues values = new ContentValues();
+            resolver.insert(uri, values);
+            Assert.fail("insert operation should have failed with UnsupportedOperationException on"
+                    + uri);
+        } catch (UnsupportedOperationException e) {
+            // pass
+        }
+    }
+
+    /**
+     * Create a contact and assert that the record exists.
+     *
+     * @return The created contact id pair.
+     */
+    public static ContactIdPair assertAndCreateContact(ContentResolver resolver) {
+        long rawContactId = RawContactUtil.createRawContactWithName(resolver);
+
+        long contactId = RawContactUtil.queryContactIdByRawContactId(resolver, rawContactId);
+        MoreAsserts.assertNotEqual(CommonDatabaseUtils.NOT_FOUND, contactId);
+
+        return new ContactIdPair(contactId, rawContactId);
+    }
+
+    /**
+     * Asserts that a contact id was deleted, has a delete log, and that log has a timestamp greater
+     * than the given timestamp.
+     *
+     * @param contactId The contact id to check.
+     * @param start The timestamp that the delete log should be greater than.
+     */
+    public static void assertHasDeleteLogGreaterThan(ContentResolver resolver, long contactId,
+            long start) {
+        Assert.assertFalse(ContactUtil.recordExistsForContactId(resolver, contactId));
+
+        long deletedTimestamp = DeletedContactUtil.queryDeletedTimestampForContactId(resolver,
+                contactId);
+        MoreAsserts.assertNotEqual(CommonDatabaseUtils.NOT_FOUND, deletedTimestamp);
+        Assert.assertTrue(deletedTimestamp > start);
+    }
+
+    /**
+     * Holds a single contact id and raw contact id relationship.
+     */
+    public static class ContactIdPair {
+        public long mContactId;
+        public long mRawContactId;
+
+        public ContactIdPair(long contactId, long rawContactId) {
+            this.mContactId = contactId;
+            this.mRawContactId = rawContactId;
+        }
+    }
+}
diff --git a/tests/src/com/android/providers/contacts/testutil/DeletedContactUtil.java b/tests/src/com/android/providers/contacts/testutil/DeletedContactUtil.java
new file mode 100644
index 0000000..2dab7f9
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/testutil/DeletedContactUtil.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.testutil;
+
+import static android.provider.ContactsContract.DeletedContacts;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.database.Cursor;
+import android.net.Uri;
+
+import java.util.List;
+
+/**
+ * Convenience methods for operating on the DeletedContacts table.
+ */
+public class DeletedContactUtil {
+
+    private static final Uri URI = DeletedContacts.CONTENT_URI;
+
+    public static long queryDeletedTimestampForContactId(ContentResolver resolver, long contactId) {
+        String[] projection = new String[]{
+                DeletedContacts.CONTACT_DELETED_TIMESTAMP
+        };
+        Uri uri = ContentUris.withAppendedId(URI, contactId);
+        Cursor cursor = resolver.query(uri, projection, null, null, null);
+        if (cursor.moveToNext()) {
+            return cursor.getLong(0);
+        }
+        return CommonDatabaseUtils.NOT_FOUND;
+    }
+
+    public static long getCount(ContentResolver resolver) {
+        String[] projection = new String[] {
+                DeletedContacts.CONTACT_ID
+        };
+        Cursor cursor = resolver.query(URI, projection, null, null, null);
+        try {
+            return cursor.getCount();
+        } finally {
+            CommonDatabaseUtils.closeQuietly(cursor);
+        }
+    }
+
+    /**
+     * Queries all records.
+     *
+     * @return A list of records.  Where each record is represented as an array of strings.
+     */
+    public static List<String[]> query(ContentResolver resolver, String[] projection) {
+        Cursor cursor = resolver.query(URI, projection, null, null, null);
+        return CommonDatabaseUtils.multiRecordToArray(cursor);
+    }
+
+    /**
+     * Queries all records after a given timestamp.
+     *
+     * @return A list of records.  Where each record is represented as an array of strings.
+     */
+    public static List<String[]> querySinceTimestamp(ContentResolver resolver, String[] projection,
+            long timestamp) {
+        String selection = DeletedContacts.CONTACT_DELETED_TIMESTAMP + ">?";
+        String[] args = new String[] {timestamp + ""};
+        Cursor cursor = resolver.query(URI, projection, selection, args, null);
+        return CommonDatabaseUtils.multiRecordToArray(cursor);
+    }
+}
diff --git a/tests/src/com/android/providers/contacts/testutil/RawContactUtil.java b/tests/src/com/android/providers/contacts/testutil/RawContactUtil.java
new file mode 100644
index 0000000..e9cd3b5
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/testutil/RawContactUtil.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.testutil;
+
+import android.accounts.Account;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.test.mock.MockContentResolver;
+
+import java.util.List;
+
+/**
+ * Convenience methods for operating on the RawContacts table.
+ */
+public class RawContactUtil {
+
+    private static final Uri URI = ContactsContract.RawContacts.CONTENT_URI;
+
+    public static void update(ContentResolver resolver, long rawContactId,
+            ContentValues values) {
+        Uri uri = ContentUris.withAppendedId(URI, rawContactId);
+        resolver.update(uri, values, null, null);
+    }
+
+    public static String[] queryByRawContactId(ContentResolver resolver,
+            long rawContactId, String[] projection) {
+        Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
+                rawContactId);
+        Cursor cursor = resolver.query(uri, projection, null, null, null);
+        return CommonDatabaseUtils.singleRecordToArray(cursor);
+    }
+
+    /**
+     * Returns a list of raw contact records.
+     *
+     * @return A list of records.  Where each record is represented as an array of strings.
+     */
+    public static List<String[]> queryByContactId(ContentResolver resolver, long contactId,
+            String[] projection) {
+        Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, contactId);
+        Cursor cursor = resolver.query(uri, projection, null, null, null);
+        return CommonDatabaseUtils.multiRecordToArray(cursor);
+    }
+
+    public static void delete(ContentResolver resolver, long rawContactId,
+            boolean isSyncAdapter) {
+        Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId)
+                .buildUpon()
+                .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, isSyncAdapter + "")
+                .build();
+        resolver.delete(uri, null, null);
+    }
+
+    public static long queryContactIdByRawContactId(ContentResolver resolver, long rawContactid) {
+        String[] projection = new String[]{
+                ContactsContract.RawContacts.CONTACT_ID
+        };
+        String[] result = RawContactUtil.queryByRawContactId(resolver, rawContactid,
+                projection);
+        if (result == null) {
+            return CommonDatabaseUtils.NOT_FOUND;
+        }
+        return Long.parseLong(result[0]);
+    }
+
+    public static boolean rawContactExistsById(ContentResolver resolver, long rawContactid) {
+        long contactId = queryContactIdByRawContactId(resolver, rawContactid);
+        return contactId != CommonDatabaseUtils.NOT_FOUND;
+    }
+
+    public static long createRawContact(ContentResolver resolver, Account account,
+            String... extras) {
+        ContentValues values = new ContentValues();
+        CommonDatabaseUtils.extrasVarArgsToValues(values, extras);
+        final Uri uri = TestUtil.maybeAddAccountQueryParameters(ContactsContract.RawContacts.CONTENT_URI, account);
+        Uri contactUri = resolver.insert(uri, values);
+        return ContentUris.parseId(contactUri);
+    }
+
+    public static long createRawContactWithName(ContentResolver resolver) {
+        return createRawContactWithName(resolver, null);
+    }
+
+    public static long createRawContactWithName(ContentResolver resolver, Account account) {
+        return createRawContactWithName(resolver, "John", "Doe", account);
+    }
+
+    public static long createRawContactWithName(ContentResolver resolver, String firstName,
+            String lastName) {
+        return createRawContactWithName(resolver, firstName, lastName, null);
+    }
+
+    public static long createRawContactWithName(ContentResolver resolver, String firstName,
+            String lastName, Account account) {
+        long rawContactId = createRawContact(resolver, account);
+        DataUtil.insertStructuredName(resolver, rawContactId, firstName, lastName);
+        return rawContactId;
+    }
+
+    public static long createRawContact(ContentResolver resolver) {
+        return createRawContact(resolver, null);
+    }
+}
diff --git a/tests/src/com/android/providers/contacts/testutil/TestUtil.java b/tests/src/com/android/providers/contacts/testutil/TestUtil.java
new file mode 100644
index 0000000..2020f6d
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/testutil/TestUtil.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts.testutil;
+
+import android.accounts.Account;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.util.Log;
+
+/**
+ * Common methods used for testing.
+ */
+public class TestUtil {
+    private static String TAG = TestUtil.class.getSimpleName();
+
+    public static final Account ACCOUNT_1 = new Account("account_name_1", "account_type_1");
+    public static final Account ACCOUNT_2 = new Account("account_name_2", "account_type_2");
+
+    /**
+     * Sleep for 1ms.
+     */
+    public static void sleep() {
+        try {
+            Thread.sleep(1);
+        } catch (InterruptedException e) {
+            Log.w(TAG, "Sleep interrupted.");
+        }
+    }
+
+    public static Uri maybeAddAccountQueryParameters(Uri uri, Account account) {
+        if (account == null) {
+            return uri;
+        }
+        return uri.buildUpon()
+                .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, account.name)
+                .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type)
+                .build();
+    }
+}