Refactor RawContact to be parcelable.

- Re-work of RawContact to be a real data container and removed un-necessary
  dependencies.
- Removed un-necessary circular dependency between RawContact and DataItem.
- Cleaned up and made DataItem more compartmentalized by removing un-related
  account methods.
- Implemented Parcelable for RawContact and NamedDataItem.

Bug: 6406182
Change-Id: Icd84f34d85e1349a86e473708cc7f8fece12349f
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index 4333aa4..c756752 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -47,9 +47,9 @@
 import android.widget.Toast;
 
 import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.RawContactModifier;
 import com.android.contacts.model.RawContactDelta;
 import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.model.RawContactModifier;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.util.CallerInfoCacheUtils;
 import com.google.common.collect.Lists;
diff --git a/src/com/android/contacts/activities/AttachPhotoActivity.java b/src/com/android/contacts/activities/AttachPhotoActivity.java
index 2f7651f..b6d7c2d 100644
--- a/src/com/android/contacts/activities/AttachPhotoActivity.java
+++ b/src/com/android/contacts/activities/AttachPhotoActivity.java
@@ -35,9 +35,9 @@
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.model.Contact;
 import com.android.contacts.model.ContactLoader;
-import com.android.contacts.model.RawContactModifier;
 import com.android.contacts.model.RawContactDelta;
 import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.model.RawContactModifier;
 import com.android.contacts.model.account.AccountType;
 import com.android.contacts.util.ContactPhotoUtils;
 
diff --git a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
index c8adf95..84206f8 100644
--- a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
+++ b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
@@ -630,7 +630,7 @@
                 editableAccount.type, editableAccount.dataSet);
 
         // Create a new RawContactDelta for the new raw_contact.
-        final RawContact rawContact = new RawContact(context);
+        final RawContact rawContact = new RawContact();
         rawContact.setAccount(editableAccount);
 
         final RawContactDelta entityDelta = new RawContactDelta(ValuesDelta.fromAfter(
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 3dfaf8d..9e13ed4 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -543,6 +543,7 @@
         ArrayList<String> groups = new ArrayList<String>();
         for (RawContact rawContact: mContactData.getRawContacts()) {
             final long rawContactId = rawContact.getId();
+            final AccountType accountType = rawContact.getAccountType(mContext);
             for (DataItem dataItem : rawContact.getDataItems()) {
                 dataItem.setRawContactId(rawContactId);
 
@@ -558,11 +559,12 @@
                     continue;
                 }
 
-                final DataKind kind = dataItem.getDataKind();
+                final DataKind kind = AccountTypeManager.getInstance(mContext)
+                        .getKindOrFallback(accountType, dataItem.getMimeType());
                 if (kind == null) continue;
 
                 final DetailViewEntry entry = DetailViewEntry.fromValues(mContext, dataItem,
-                        mContactData.isDirectoryEntry(), mContactData.getDirectoryId());
+                        mContactData.isDirectoryEntry(), mContactData.getDirectoryId(), kind);
                 entry.maxLines = kind.maxLinesForDisplay;
 
                 final boolean hasData = !TextUtils.isEmpty(entry.data);
@@ -625,7 +627,8 @@
                         ImDataItem im = ImDataItem.createFromEmail(email);
 
                         final DetailViewEntry imEntry = DetailViewEntry.fromValues(mContext, im,
-                                mContactData.isDirectoryEntry(), mContactData.getDirectoryId());
+                                mContactData.isDirectoryEntry(), mContactData.getDirectoryId(),
+                                kind);
                         buildImActions(mContext, imEntry, im);
                         imEntry.setPresence(status.getPresence());
                         imEntry.maxLines = kind.maxLinesForDisplay;
@@ -706,20 +709,19 @@
                     entry.intent = new Intent(Intent.ACTION_VIEW);
                     entry.intent.setDataAndType(entry.uri, entry.mimetype);
 
-                    entry.data = dataItem.buildDataString();
+                    entry.data = dataItem.buildDataString(getContext(), kind);
 
                     if (!TextUtils.isEmpty(entry.data)) {
                         // If the account type exists in the hash map, add it as another entry for
                         // that account type
-                        AccountType type = dataItem.getAccountType();
-                        if (mOtherEntriesMap.containsKey(type)) {
-                            List<DetailViewEntry> listEntries = mOtherEntriesMap.get(type);
+                        if (mOtherEntriesMap.containsKey(accountType)) {
+                            List<DetailViewEntry> listEntries = mOtherEntriesMap.get(accountType);
                             listEntries.add(entry);
                         } else {
                             // Otherwise create a new list with the entry and add it to the hash map
                             List<DetailViewEntry> listEntries = new ArrayList<DetailViewEntry>();
                             listEntries.add(entry);
-                            mOtherEntriesMap.put(type, listEntries);
+                            mOtherEntriesMap.put(accountType, listEntries);
                         }
                     }
                 }
@@ -1244,7 +1246,7 @@
          * Build new {@link DetailViewEntry} and populate from the given values.
          */
         public static DetailViewEntry fromValues(Context context, DataItem item,
-                boolean isDirectoryEntry, long directoryId) {
+                boolean isDirectoryEntry, long directoryId, DataKind dataKind) {
             final DetailViewEntry entry = new DetailViewEntry();
             entry.id = item.getId();
             entry.context = context;
@@ -1254,15 +1256,15 @@
                         ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
             }
             entry.mimetype = item.getMimeType();
-            entry.kind = item.getKindString();
-            entry.data = item.buildDataString();
+            entry.kind = dataKind.getKindString(context);
+            entry.data = item.buildDataString(context, dataKind);
 
-            if (item.hasKindTypeColumn()) {
-                entry.type = item.getKindTypeColumn();
+            if (item.hasKindTypeColumn(dataKind)) {
+                entry.type = item.getKindTypeColumn(dataKind);
 
                 // get type string
                 entry.typeString = "";
-                for (EditType type : item.getDataKind().typeList) {
+                for (EditType type : dataKind.typeList) {
                     if (type.rawValue == entry.type) {
                         if (type.customColumn == null) {
                             // Non-custom type. Get its description from the resource
@@ -1998,7 +2000,7 @@
             if (defaultGroupId == -1) return false;
 
             final RawContact rawContact = (RawContact) mContactData.getRawContacts().get(0);
-            final AccountType type = rawContact.getAccountType();
+            final AccountType type = rawContact.getAccountType(getContext());
             // Offline or non-writeable account? Nothing to fix
             if (type == null || !type.areContactsWritable()) return false;
 
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 19bb646..cd9b4ec 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -479,7 +479,7 @@
             RawContact rawContact = rawContacts.get(0);
             String type = rawContact.getAccountTypeString();
             String dataSet = rawContact.getDataSet();
-            AccountType accountType = rawContact.getAccountType();
+            AccountType accountType = rawContact.getAccountType(mContext);
             if (accountType.getEditContactActivityClassName() != null &&
                     !accountType.areContactsWritable()) {
                 if (mListener != null) {
@@ -524,7 +524,7 @@
             }
             // Editor should always present a local profile for editing
             if (!localProfileExists) {
-                final RawContact rawContact = new RawContact(mContext);
+                final RawContact rawContact = new RawContact();
                 rawContact.setAccountToLocal();
 
                 RawContactDelta insert = new RawContactDelta(ValuesDelta.fromAfter(
@@ -659,7 +659,7 @@
             AccountType oldAccountType) {
         mStatus = Status.EDITING;
 
-        final RawContact rawContact = new RawContact(mContext);
+        final RawContact rawContact = new RawContact();
         if (newAccount != null) {
             rawContact.setAccount(newAccount);
         } else {
diff --git a/src/com/android/contacts/editor/StructuredNameEditorView.java b/src/com/android/contacts/editor/StructuredNameEditorView.java
index 3c4476d..bac3b79 100644
--- a/src/com/android/contacts/editor/StructuredNameEditorView.java
+++ b/src/com/android/contacts/editor/StructuredNameEditorView.java
@@ -67,7 +67,7 @@
             ViewIdGenerator vig) {
         super.setValues(kind, entry, state, readOnly, vig);
         if (mSnapshot == null) {
-            mSnapshot = (StructuredNameDataItem) DataItem.createFrom(null,
+            mSnapshot = (StructuredNameDataItem) DataItem.createFrom(
                     new ContentValues(getValues().getCompleteValues()));
             mChanged = entry.isInsert();
         } else {
@@ -214,7 +214,7 @@
         super.onRestoreInstanceState(ss.mSuperState);
 
         mChanged = ss.mChanged;
-        mSnapshot = (StructuredNameDataItem) DataItem.createFrom(null, ss.mSnapshot);
+        mSnapshot = (StructuredNameDataItem) DataItem.createFrom(ss.mSnapshot);
     }
 
     private static class SavedState implements Parcelable {
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index 64f3a91..29cffa2 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -140,8 +140,7 @@
      * {@link AccountType#accountType}, {@link AccountType#dataSet}, and {@link DataKind#mimeType}.
      * If no direct match found, we try searching {@link FallbackAccountType}.
      */
-    public DataKind getKindOrFallback(String accountType, String dataSet, String mimeType) {
-        final AccountType type = getAccountType(accountType, dataSet);
+    public DataKind getKindOrFallback(AccountType type, String mimeType) {
         return type == null ? null : type.getKindForMimetype(mimeType);
     }
 
@@ -588,13 +587,11 @@
      * If no direct match found, we try searching {@link FallbackAccountType}.
      */
     @Override
-    public DataKind getKindOrFallback(String accountType, String dataSet, String mimeType) {
+    public DataKind getKindOrFallback(AccountType type, String mimeType) {
         ensureAccountsLoaded();
         DataKind kind = null;
 
         // Try finding account type and kind matching request
-        final AccountType type = mAccountTypesWithDataSets.get(
-                AccountTypeWithDataSet.get(accountType, dataSet));
         if (type != null) {
             kind = type.getKindForMimetype(mimeType);
         }
@@ -605,7 +602,7 @@
         }
 
         if (kind == null) {
-            Log.w(TAG, "Unknown type=" + accountType + ", mime=" + mimeType);
+            Log.w(TAG, "Unknown type=" + type + ", mime=" + mimeType);
         }
 
         return kind;
diff --git a/src/com/android/contacts/model/Contact.java b/src/com/android/contacts/model/Contact.java
index ede2101..a097a25 100644
--- a/src/com/android/contacts/model/Contact.java
+++ b/src/com/android/contacts/model/Contact.java
@@ -26,7 +26,6 @@
 
 import com.android.contacts.GroupMetaData;
 import com.android.contacts.model.account.AccountType;
-import com.android.contacts.model.dataitem.DataItem;
 import com.android.contacts.util.DataStatus;
 import com.android.contacts.util.StreamItemEntry;
 import com.google.common.annotations.VisibleForTesting;
@@ -389,7 +388,7 @@
 
         // Iterate through raw-contacts; if we find a writable on, return its ID.
         for (RawContact rawContact : getRawContacts()) {
-            AccountType accountType = rawContact.getAccountType();
+            AccountType accountType = rawContact.getAccountType(context);
             if (accountType != null && accountType.areContactsWritable()) {
                 return rawContact.getId();
             }
@@ -429,10 +428,7 @@
         }
 
         RawContact rawContact = mRawContacts.get(0);
-        ArrayList<ContentValues> result = new ArrayList<ContentValues>();
-        for (DataItem dataItem : rawContact.getDataItems()) {
-            result.add(dataItem.getContentValues());
-        }
+        ArrayList<ContentValues> result = rawContact.getContentValues();
 
         // If the photo was loaded using the URI, create an entry for the photo
         // binary data.
diff --git a/src/com/android/contacts/model/ContactLoader.java b/src/com/android/contacts/model/ContactLoader.java
index f9f630d..364f5bc 100644
--- a/src/com/android/contacts/model/ContactLoader.java
+++ b/src/com/android/contacts/model/ContactLoader.java
@@ -382,12 +382,12 @@
                     // First time to see this raw contact id, so create a new entity, and
                     // add it to the result's entities.
                     currentRawContactId = rawContactId;
-                    rawContact = new RawContact(getContext(), loadRawContactValues(cursor));
+                    rawContact = new RawContact(loadRawContactValues(cursor));
                     rawContactsBuilder.add(rawContact);
                 }
                 if (!cursor.isNull(ContactQuery.DATA_ID)) {
                     ContentValues data = loadDataValues(cursor);
-                    final DataItem item = rawContact.addDataItemValues(data);
+                    rawContact.addDataItemValues(data);
 
                     if (!cursor.isNull(ContactQuery.PRESENCE)
                             || !cursor.isNull(ContactQuery.STATUS)) {
@@ -865,7 +865,7 @@
                 continue; // Already notified for this raw contact.
             }
             mNotifiedRawContactIds.add(rawContactId);
-            final AccountType accountType = rawContact.getAccountType();
+            final AccountType accountType = rawContact.getAccountType(context);
             final String serviceName = accountType.getViewContactNotifyServiceClassName();
             final String servicePackageName = accountType.getViewContactNotifyServicePackageName();
             if (!TextUtils.isEmpty(serviceName) && !TextUtils.isEmpty(servicePackageName)) {
diff --git a/src/com/android/contacts/model/RawContact.java b/src/com/android/contacts/model/RawContact.java
index 6d4a881..823a853 100644
--- a/src/com/android/contacts/model/RawContact.java
+++ b/src/com/android/contacts/model/RawContact.java
@@ -20,6 +20,8 @@
 import android.content.Context;
 import android.content.Entity;
 import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.RawContacts;
@@ -27,6 +29,8 @@
 import com.android.contacts.model.account.AccountType;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.model.dataitem.DataItem;
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -42,20 +46,76 @@
  * DataItem objects that represent contact information elements (like phone
  * numbers, email, address, etc.).
  */
-public class RawContact {
+final public class RawContact implements Parcelable {
 
-    private final Context mContext;
     private AccountTypeManager mAccountTypeManager;
     private final ContentValues mValues;
     private final ArrayList<NamedDataItem> mDataItems;
 
-    public static class NamedDataItem {
-        public final Uri uri;
-        public final DataItem dataItem;
+    final public static class NamedDataItem implements Parcelable {
+        public final Uri mUri;
 
-        public NamedDataItem(Uri uri, DataItem dataItem) {
-            this.uri = uri;
-            this.dataItem = dataItem;
+        // This use to be a DataItem. DataItem creation is now delayed until the point of request
+        // since there is no benefit to storing them here due to the multiple inheritance.
+        // Eventually instanceof still has to be used anyways to determine which sub-class of
+        // DataItem it is. And having parent DataItem's here makes it very difficult to serialize or
+        // parcelable.
+        //
+        // Instead of having a common DataItem super class, we should refactor this to be a generic
+        // Object where the object is a concrete class that no longer relies on ContentValues.
+        // (this will also make the classes easier to use).
+        // Since instanceof is used later anyways, having a list of Objects won't hurt and is no
+        // worse than having a DataItem.
+        public final ContentValues mContentValues;
+
+        public NamedDataItem(Uri uri, ContentValues values) {
+            this.mUri = uri;
+            this.mContentValues = values;
+        }
+
+        public NamedDataItem(Parcel parcel) {
+            this.mUri = parcel.readParcelable(Uri.class.getClassLoader());
+            this.mContentValues = parcel.readParcelable(ContentValues.class.getClassLoader());
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel parcel, int i) {
+            parcel.writeParcelable(mUri, i);
+            parcel.writeParcelable(mContentValues, i);
+        }
+
+        public static final Parcelable.Creator<NamedDataItem> CREATOR
+                = new Parcelable.Creator<NamedDataItem>() {
+
+            @Override
+            public NamedDataItem createFromParcel(Parcel parcel) {
+                return new NamedDataItem(parcel);
+            }
+
+            @Override
+            public NamedDataItem[] newArray(int i) {
+                return new NamedDataItem[i];
+            }
+        };
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(mUri, mContentValues);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) return false;
+            if (getClass() != obj.getClass()) return false;
+
+            final NamedDataItem other = (NamedDataItem) obj;
+            return Objects.equal(mUri, other.mUri) &&
+                    Objects.equal(mContentValues, other.mContentValues);
         }
     }
 
@@ -63,7 +123,7 @@
         final ContentValues values = entity.getEntityValues();
         final ArrayList<Entity.NamedContentValues> subValues = entity.getSubValues();
 
-        RawContact rawContact = new RawContact(null, values);
+        RawContact rawContact = new RawContact(values);
         for (Entity.NamedContentValues subValue : subValues) {
             rawContact.addNamedDataItemValues(subValue.uri, subValue.values);
         }
@@ -72,31 +132,60 @@
 
     /**
      * A RawContact object can be created with or without a context.
-     *
-     * The context is used for the buildString() member function in DataItem objects,
-     * specifically for retrieving an instance of AccountTypeManager.  It is okay to
-     * pass in null for the context in which case, you will not be able to call buildString(),
-     * getDataKind(), or getAccountType() from a DataItem object.
      */
-    public RawContact(Context context) {
-        this(context, new ContentValues());
+    public RawContact() {
+        this(new ContentValues());
     }
 
-    public RawContact(Context context, ContentValues values) {
-        mContext = context;
+    public RawContact(ContentValues values) {
         mValues = values;
         mDataItems = new ArrayList<NamedDataItem>();
     }
 
-    public AccountTypeManager getAccountTypeManager() {
-        if (mAccountTypeManager == null) {
-            mAccountTypeManager = AccountTypeManager.getInstance(mContext);
-        }
-        return mAccountTypeManager;
+    /**
+     * Constructor for the parcelable.
+     *
+     * @param parcel The parcel to de-serialize from.
+     */
+    private RawContact(Parcel parcel) {
+        mValues = parcel.readParcelable(ContentValues.class.getClassLoader());
+        mDataItems = Lists.newArrayList();
+        parcel.readTypedList(mDataItems, NamedDataItem.CREATOR);
     }
 
-    public Context getContext() {
-        return mContext;
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int i) {
+        parcel.writeParcelable(mValues, i);
+        parcel.writeTypedList(mDataItems);
+    }
+
+    /**
+     * Create for building the parcelable.
+     */
+    public static final Parcelable.Creator<RawContact> CREATOR
+            = new Parcelable.Creator<RawContact>() {
+
+        @Override
+        public RawContact createFromParcel(Parcel parcel) {
+            return new RawContact(parcel);
+        }
+
+        @Override
+        public RawContact[] newArray(int i) {
+            return new RawContact[i];
+        }
+    };
+
+    public AccountTypeManager getAccountTypeManager(Context context) {
+        if (mAccountTypeManager == null) {
+            mAccountTypeManager = AccountTypeManager.getInstance(context);
+        }
+        return mAccountTypeManager;
     }
 
     public ContentValues getValues() {
@@ -182,8 +271,8 @@
         return getValues().getAsBoolean(Contacts.STARRED);
     }
 
-    public AccountType getAccountType() {
-        return getAccountTypeManager().getAccountType(getAccountTypeString(), getDataSet());
+    public AccountType getAccountType(Context context) {
+        return getAccountTypeManager(context).getAccountType(getAccountTypeString(), getDataSet());
     }
 
     /**
@@ -231,38 +320,58 @@
     /**
      * Creates and inserts a DataItem object that wraps the content values, and returns it.
      */
-    public DataItem addDataItemValues(ContentValues values) {
-        final NamedDataItem namedItem = addNamedDataItemValues(Data.CONTENT_URI, values);
-        return namedItem.dataItem;
+    public void addDataItemValues(ContentValues values) {
+        addNamedDataItemValues(Data.CONTENT_URI, values);
     }
 
     public NamedDataItem addNamedDataItemValues(Uri uri, ContentValues values) {
-        final NamedDataItem namedItem = new NamedDataItem(uri, DataItem.createFrom(this, values));
+        final NamedDataItem namedItem = new NamedDataItem(uri, values);
         mDataItems.add(namedItem);
         return namedItem;
     }
 
-    public List<DataItem> getDataItems() {
-        final ArrayList<DataItem> list = new ArrayList<DataItem>();
+    public ArrayList<ContentValues> getContentValues() {
+        final ArrayList<ContentValues> list = Lists.newArrayListWithCapacity(mDataItems.size());
         for (NamedDataItem dataItem : mDataItems) {
-            if (Data.CONTENT_URI.equals(dataItem.uri)) {
-                list.add(dataItem.dataItem);
+            if (Data.CONTENT_URI.equals(dataItem.mUri)) {
+                list.add(dataItem.mContentValues);
             }
         }
         return list;
     }
 
-    public List<NamedDataItem> getNamedDataItems() {
-        return mDataItems;
+    public List<DataItem> getDataItems() {
+        final ArrayList<DataItem> list = Lists.newArrayListWithCapacity(mDataItems.size());
+        for (NamedDataItem dataItem : mDataItems) {
+            if (Data.CONTENT_URI.equals(dataItem.mUri)) {
+                list.add(DataItem.createFrom(dataItem.mContentValues));
+            }
+        }
+        return list;
     }
 
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         sb.append("RawContact: ").append(mValues);
         for (RawContact.NamedDataItem namedDataItem : mDataItems) {
-            sb.append("\n  ").append(namedDataItem.uri);
-            sb.append("\n  -> ").append(namedDataItem.dataItem.getContentValues());
+            sb.append("\n  ").append(namedDataItem.mUri);
+            sb.append("\n  -> ").append(namedDataItem.mContentValues);
         }
         return sb.toString();
     }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(mValues, mDataItems);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+
+        RawContact other = (RawContact) obj;
+        return Objects.equal(mValues, other.mValues) &&
+                Objects.equal(mDataItems, other.mDataItems);
+    }
 }
diff --git a/src/com/android/contacts/model/RawContactDelta.java b/src/com/android/contacts/model/RawContactDelta.java
index 2ee9d5c..b381174 100644
--- a/src/com/android/contacts/model/RawContactDelta.java
+++ b/src/com/android/contacts/model/RawContactDelta.java
@@ -35,7 +35,6 @@
 import android.util.Log;
 
 import com.android.contacts.model.account.AccountType;
-import com.android.contacts.model.dataitem.DataItem;
 import com.android.contacts.test.NeededForTesting;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -97,8 +96,8 @@
         final RawContactDelta rawContactDelta = new RawContactDelta();
         rawContactDelta.mValues = ValuesDelta.fromBefore(before.getValues());
         rawContactDelta.mValues.setIdColumn(RawContacts._ID);
-        for (DataItem dataItem : before.getDataItems()) {
-            rawContactDelta.addEntry(ValuesDelta.fromBefore(dataItem.getContentValues()));
+        for (final ContentValues values : before.getContentValues()) {
+            rawContactDelta.addEntry(ValuesDelta.fromBefore(values));
         }
         return rawContactDelta;
     }
diff --git a/src/com/android/contacts/model/account/AccountType.java b/src/com/android/contacts/model/account/AccountType.java
index edd17a0..ca3dc68 100644
--- a/src/com/android/contacts/model/account/AccountType.java
+++ b/src/com/android/contacts/model/account/AccountType.java
@@ -28,7 +28,6 @@
 import android.widget.EditText;
 
 import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.dataitem.DataKind;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.Lists;
@@ -325,8 +324,7 @@
 
     /**
      * Find the {@link DataKind} for a specific MIME-type, if it's handled by
-     * this data source. If you may need a fallback {@link DataKind}, use
-     * {@link AccountTypeManager#getKindOrFallback(String, String, String)}.
+     * this data source.
      */
     public DataKind getKindForMimetype(String mimeType) {
         return this.mMimeKinds.get(mimeType);
diff --git a/src/com/android/contacts/model/dataitem/DataItem.java b/src/com/android/contacts/model/dataitem/DataItem.java
index 25c44cb..9c618de 100644
--- a/src/com/android/contacts/model/dataitem/DataItem.java
+++ b/src/com/android/contacts/model/dataitem/DataItem.java
@@ -17,6 +17,7 @@
 package com.android.contacts.model.dataitem;
 
 import android.content.ContentValues;
+import android.content.Context;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Event;
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
@@ -34,10 +35,6 @@
 import android.provider.ContactsContract.CommonDataKinds.Website;
 import android.provider.ContactsContract.Contacts.Data;
 
-import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.RawContact;
-import com.android.contacts.model.account.AccountType;
-
 /**
  * This is the base class for data items, which represents a row from the Data table.
  */
@@ -45,67 +42,56 @@
 
     private final ContentValues mContentValues;
 
-    /**
-     * The raw contact that this data item is associated with.  This can be null.
-     */
-    private final RawContact mRawContact;
-    private DataKind mDataKind;
-
-    protected DataItem(RawContact rawContact, ContentValues values) {
+    protected DataItem(ContentValues values) {
         mContentValues = values;
-        mRawContact = rawContact;
     }
 
     /**
      * Factory for creating subclasses of DataItem objects based on the mimetype in the
      * content values.  Raw contact is the raw contact that this data item is associated with.
      */
-    public static DataItem createFrom(RawContact rawContact, ContentValues values) {
+    public static DataItem createFrom(ContentValues values) {
         final String mimeType = values.getAsString(Data.MIMETYPE);
         if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new GroupMembershipDataItem(rawContact, values);
+            return new GroupMembershipDataItem(values);
         } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new StructuredNameDataItem(rawContact, values);
+            return new StructuredNameDataItem(values);
         } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new PhoneDataItem(rawContact, values);
+            return new PhoneDataItem(values);
         } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new EmailDataItem(rawContact, values);
+            return new EmailDataItem(values);
         } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new StructuredPostalDataItem(rawContact, values);
+            return new StructuredPostalDataItem(values);
         } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new ImDataItem(rawContact, values);
+            return new ImDataItem(values);
         } else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new OrganizationDataItem(rawContact, values);
+            return new OrganizationDataItem(values);
         } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new NicknameDataItem(rawContact, values);
+            return new NicknameDataItem(values);
         } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new NoteDataItem(rawContact, values);
+            return new NoteDataItem(values);
         } else if (Website.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new WebsiteDataItem(rawContact, values);
+            return new WebsiteDataItem(values);
         } else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new SipAddressDataItem(rawContact, values);
+            return new SipAddressDataItem(values);
         } else if (Event.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new EventDataItem(rawContact, values);
+            return new EventDataItem(values);
         } else if (Relation.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new RelationDataItem(rawContact, values);
+            return new RelationDataItem(values);
         } else if (Identity.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new IdentityDataItem(rawContact, values);
+            return new IdentityDataItem(values);
         } else if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
-            return new PhotoDataItem(rawContact, values);
+            return new PhotoDataItem(values);
         }
 
         // generic
-        return new DataItem(rawContact, values);
+        return new DataItem(values);
     }
 
     public ContentValues getContentValues() {
         return mContentValues;
     }
 
-    protected RawContact getRawContact() {
-        return mRawContact;
-    }
-
     public void setRawContactId(long rawContactId) {
         mContentValues.put(Data.RAW_CONTACT_ID, rawContactId);
     }
@@ -145,70 +131,25 @@
         return mContentValues.getAsInteger(Data.DATA_VERSION);
     }
 
-    public AccountTypeManager getAccountTypeManager() {
-        if (mRawContact == null) {
-            return null;
-        } else {
-            return mRawContact.getAccountTypeManager();
-        }
-    }
-
-    public AccountType getAccountType() {
-        if (mRawContact == null) {
-            return null;
-        } else {
-            return mRawContact.getAccountType();
-        }
-    }
-
-    /**
-     * This method can only be invoked if the raw contact is non-null.
-     */
-    public DataKind getDataKind() {
-        if (mRawContact == null) {
-            throw new IllegalStateException("mRawContact must be non-null to call getDataKind()");
-        }
-
-        if (mDataKind == null) {
-            mDataKind = getAccountTypeManager().getKindOrFallback(
-                    mRawContact.getAccountTypeString(), mRawContact.getDataSet(), getMimeType());
-        }
-
-        return mDataKind;
-    }
-
-    public boolean hasKindTypeColumn() {
-        final String key = getDataKind().typeColumn;
+    public boolean hasKindTypeColumn(DataKind kind) {
+        final String key = kind.typeColumn;
         return key != null && mContentValues.containsKey(key);
     }
 
-    public int getKindTypeColumn() {
-        final String key = getDataKind().typeColumn;
+    public int getKindTypeColumn(DataKind kind) {
+        final String key = kind.typeColumn;
         return mContentValues.getAsInteger(key);
     }
 
     /**
      * This builds the data string depending on the type of data item by using the generic
-     * DataKind object underneath.  This DataItem object must be associated with a raw contact
-     * for this function to work.
+     * DataKind object underneath.
      */
-    public String buildDataString() {
-        if (mRawContact == null) {
-            throw new IllegalStateException("mRawContact must be non-null to call getDataKind()");
-        }
-        final DataKind kind = getDataKind();
-
+    public String buildDataString(Context context, DataKind kind) {
         if (kind.actionBody == null) {
             return null;
         }
-        CharSequence actionBody = kind.actionBody.inflateUsing(mRawContact.getContext(),
-                mContentValues);
+        CharSequence actionBody = kind.actionBody.inflateUsing(context, mContentValues);
         return actionBody == null ? null : actionBody.toString();
     }
-
-    public String getKindString() {
-        final DataKind kind = getDataKind();
-        return (kind.titleRes == -1 || kind.titleRes == 0) ? ""
-                : mRawContact.getContext().getString(kind.titleRes);
-    }
 }
diff --git a/src/com/android/contacts/model/dataitem/DataKind.java b/src/com/android/contacts/model/dataitem/DataKind.java
index 8707012..204b784 100644
--- a/src/com/android/contacts/model/dataitem/DataKind.java
+++ b/src/com/android/contacts/model/dataitem/DataKind.java
@@ -17,6 +17,7 @@
 package com.android.contacts.model.dataitem;
 
 import android.content.ContentValues;
+import android.content.Context;
 import android.provider.ContactsContract.Data;
 
 import com.android.contacts.R;
@@ -106,6 +107,10 @@
         maxLinesForDisplay = 1;
     }
 
+    public String getKindString(Context context) {
+        return (titleRes == -1 || titleRes == 0) ? "" : context.getString(titleRes);
+    }
+
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
diff --git a/src/com/android/contacts/model/dataitem/EmailDataItem.java b/src/com/android/contacts/model/dataitem/EmailDataItem.java
index a535c73..cb93395 100644
--- a/src/com/android/contacts/model/dataitem/EmailDataItem.java
+++ b/src/com/android/contacts/model/dataitem/EmailDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents an email data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.Email}.
  */
 public class EmailDataItem extends DataItem {
 
-    /* package */ EmailDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ EmailDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getAddress() {
diff --git a/src/com/android/contacts/model/dataitem/EventDataItem.java b/src/com/android/contacts/model/dataitem/EventDataItem.java
index 2114279..1b34a17 100644
--- a/src/com/android/contacts/model/dataitem/EventDataItem.java
+++ b/src/com/android/contacts/model/dataitem/EventDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Event;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents an event data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.Event}.
  */
 public class EventDataItem extends DataItem {
 
-    /* package */ EventDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ EventDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getStartDate() {
diff --git a/src/com/android/contacts/model/dataitem/GroupMembershipDataItem.java b/src/com/android/contacts/model/dataitem/GroupMembershipDataItem.java
index aea9bca..a3db7f9 100644
--- a/src/com/android/contacts/model/dataitem/GroupMembershipDataItem.java
+++ b/src/com/android/contacts/model/dataitem/GroupMembershipDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents a group memebership data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.GroupMembership}.
  */
 public class GroupMembershipDataItem extends DataItem {
 
-    /* package */ GroupMembershipDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ GroupMembershipDataItem(ContentValues values) {
+        super(values);
     }
 
     public long getGroupRowId() {
diff --git a/src/com/android/contacts/model/dataitem/IdentityDataItem.java b/src/com/android/contacts/model/dataitem/IdentityDataItem.java
index fd4b836..045867a 100644
--- a/src/com/android/contacts/model/dataitem/IdentityDataItem.java
+++ b/src/com/android/contacts/model/dataitem/IdentityDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Identity;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents an identity data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.Identity}.
  */
 public class IdentityDataItem extends DataItem {
 
-    /* package */ IdentityDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ IdentityDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getIdentity() {
diff --git a/src/com/android/contacts/model/dataitem/ImDataItem.java b/src/com/android/contacts/model/dataitem/ImDataItem.java
index 3a08325..00473e5 100644
--- a/src/com/android/contacts/model/dataitem/ImDataItem.java
+++ b/src/com/android/contacts/model/dataitem/ImDataItem.java
@@ -21,8 +21,6 @@
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Im;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents an IM data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.Im}.
@@ -31,20 +29,18 @@
 
     private final boolean mCreatedFromEmail;
 
-    /* package */ ImDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ ImDataItem(ContentValues values) {
+        super(values);
         mCreatedFromEmail = false;
     }
 
-    private ImDataItem(RawContact rawContact, ContentValues values,
-            boolean createdFromEmail) {
-        super(rawContact, values);
+    private ImDataItem(ContentValues values, boolean createdFromEmail) {
+        super(values);
         mCreatedFromEmail = createdFromEmail;
     }
 
     public static ImDataItem createFromEmail(EmailDataItem item) {
-        ImDataItem im = new ImDataItem(item.getRawContact(),
-                new ContentValues(item.getContentValues()), true);
+        ImDataItem im = new ImDataItem(new ContentValues(item.getContentValues()), true);
         im.setMimeType(Im.CONTENT_ITEM_TYPE);
         return im;
     }
diff --git a/src/com/android/contacts/model/dataitem/NicknameDataItem.java b/src/com/android/contacts/model/dataitem/NicknameDataItem.java
index 7b52510..79c2c50 100644
--- a/src/com/android/contacts/model/dataitem/NicknameDataItem.java
+++ b/src/com/android/contacts/model/dataitem/NicknameDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Nickname;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents a nickname data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.Nickname}.
  */
 public class NicknameDataItem extends DataItem {
 
-    public NicknameDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    public NicknameDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getName() {
diff --git a/src/com/android/contacts/model/dataitem/NoteDataItem.java b/src/com/android/contacts/model/dataitem/NoteDataItem.java
index 0d0fa24..9a572cb 100644
--- a/src/com/android/contacts/model/dataitem/NoteDataItem.java
+++ b/src/com/android/contacts/model/dataitem/NoteDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Note;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents a note data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.Note}.
  */
 public class NoteDataItem extends DataItem {
 
-    /* package */ NoteDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ NoteDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getNote() {
diff --git a/src/com/android/contacts/model/dataitem/OrganizationDataItem.java b/src/com/android/contacts/model/dataitem/OrganizationDataItem.java
index 1326bdb..0fbcd01 100644
--- a/src/com/android/contacts/model/dataitem/OrganizationDataItem.java
+++ b/src/com/android/contacts/model/dataitem/OrganizationDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Organization;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents an organization data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.Organization}.
  */
 public class OrganizationDataItem extends DataItem {
 
-    /* package */ OrganizationDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ OrganizationDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getCompany() {
diff --git a/src/com/android/contacts/model/dataitem/PhoneDataItem.java b/src/com/android/contacts/model/dataitem/PhoneDataItem.java
index 61d62c1..66b9018 100644
--- a/src/com/android/contacts/model/dataitem/PhoneDataItem.java
+++ b/src/com/android/contacts/model/dataitem/PhoneDataItem.java
@@ -21,8 +21,6 @@
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.telephony.PhoneNumberUtils;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents a phone data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.Phone}.
@@ -31,8 +29,8 @@
 
     public static final String KEY_FORMATTED_PHONE_NUMBER = "formattedPhoneNumber";
 
-    /* package */ PhoneDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ PhoneDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getNumber() {
diff --git a/src/com/android/contacts/model/dataitem/PhotoDataItem.java b/src/com/android/contacts/model/dataitem/PhotoDataItem.java
index 5e355fa..62eab8f 100644
--- a/src/com/android/contacts/model/dataitem/PhotoDataItem.java
+++ b/src/com/android/contacts/model/dataitem/PhotoDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts.Photo;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents a photo data item, wrapping the columns in
  * {@link ContactsContract.Contacts.Photo}.
  */
 public class PhotoDataItem extends DataItem {
 
-    /* package */ PhotoDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ PhotoDataItem(ContentValues values) {
+        super(values);
     }
 
     public long getPhotoFileId() {
diff --git a/src/com/android/contacts/model/dataitem/RelationDataItem.java b/src/com/android/contacts/model/dataitem/RelationDataItem.java
index 7c22cf5..86967f5 100644
--- a/src/com/android/contacts/model/dataitem/RelationDataItem.java
+++ b/src/com/android/contacts/model/dataitem/RelationDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Relation;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents a relation data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.Relation}.
  */
 public class RelationDataItem extends DataItem {
 
-    /* package */ RelationDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ RelationDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getName() {
diff --git a/src/com/android/contacts/model/dataitem/SipAddressDataItem.java b/src/com/android/contacts/model/dataitem/SipAddressDataItem.java
index 6b8e93d..3457fb2 100644
--- a/src/com/android/contacts/model/dataitem/SipAddressDataItem.java
+++ b/src/com/android/contacts/model/dataitem/SipAddressDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.SipAddress;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents a sip address data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.SipAddress}.
  */
 public class SipAddressDataItem extends DataItem {
 
-    /* package */ SipAddressDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ SipAddressDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getSipAddress() {
diff --git a/src/com/android/contacts/model/dataitem/StructuredNameDataItem.java b/src/com/android/contacts/model/dataitem/StructuredNameDataItem.java
index 4654a6f..7d1a44d 100644
--- a/src/com/android/contacts/model/dataitem/StructuredNameDataItem.java
+++ b/src/com/android/contacts/model/dataitem/StructuredNameDataItem.java
@@ -21,8 +21,6 @@
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.Contacts.Data;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents a structured name data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.StructuredName}.
@@ -30,12 +28,12 @@
 public class StructuredNameDataItem extends DataItem {
 
     public StructuredNameDataItem() {
-        super(null, new ContentValues());
+        super(new ContentValues());
         getContentValues().put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
     }
 
-    /* package */ StructuredNameDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ StructuredNameDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getDisplayName() {
diff --git a/src/com/android/contacts/model/dataitem/StructuredPostalDataItem.java b/src/com/android/contacts/model/dataitem/StructuredPostalDataItem.java
index cc2cf56..b571bd3 100644
--- a/src/com/android/contacts/model/dataitem/StructuredPostalDataItem.java
+++ b/src/com/android/contacts/model/dataitem/StructuredPostalDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents a structured postal data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.StructuredPostal}.
  */
 public class StructuredPostalDataItem extends DataItem {
 
-    /* package */ StructuredPostalDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ StructuredPostalDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getFormattedAddress() {
diff --git a/src/com/android/contacts/model/dataitem/WebsiteDataItem.java b/src/com/android/contacts/model/dataitem/WebsiteDataItem.java
index c3aadf3..33935fb 100644
--- a/src/com/android/contacts/model/dataitem/WebsiteDataItem.java
+++ b/src/com/android/contacts/model/dataitem/WebsiteDataItem.java
@@ -20,16 +20,14 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Website;
 
-import com.android.contacts.model.RawContact;
-
 /**
  * Represents a website data item, wrapping the columns in
  * {@link ContactsContract.CommonDataKinds.Website}.
  */
 public class WebsiteDataItem extends DataItem {
 
-    /* package */ WebsiteDataItem(RawContact rawContact, ContentValues values) {
-        super(rawContact, values);
+    /* package */ WebsiteDataItem(ContentValues values) {
+        super(values);
     }
 
     public String getUrl() {
diff --git a/src/com/android/contacts/quickcontact/DataAction.java b/src/com/android/contacts/quickcontact/DataAction.java
index c10c338..1366b46 100644
--- a/src/com/android/contacts/quickcontact/DataAction.java
+++ b/src/com/android/contacts/quickcontact/DataAction.java
@@ -69,18 +69,18 @@
     /**
      * Create an action from common {@link Data} elements.
      */
-    public DataAction(Context context, DataItem item) {
+    public DataAction(Context context, DataItem item, DataKind kind) {
         mContext = context;
-        mKind = item.getDataKind();
+        mKind = kind;
         mMimeType = item.getMimeType();
 
         // Determine type for subtitle
         mSubtitle = "";
-        if (item.hasKindTypeColumn()) {
-            final int typeValue = item.getKindTypeColumn();
+        if (item.hasKindTypeColumn(kind)) {
+            final int typeValue = item.getKindTypeColumn(kind);
 
             // get type string
-            for (EditType type : item.getDataKind().typeList) {
+            for (EditType type : kind.typeList) {
                 if (type.rawValue == typeValue) {
                     if (type.customColumn == null) {
                         // Non-custom type. Get its description from the resource
@@ -95,7 +95,7 @@
         }
 
         mIsPrimary = item.isSuperPrimary();
-        mBody = item.buildDataString();
+        mBody = item.buildDataString(context, kind);
 
         mDataId = item.getId();
         mDataUri = ContentUris.withAppendedId(Data.CONTENT_URI, mDataId);
@@ -119,8 +119,8 @@
                     if (hasPhone && hasSms) {
                         mIntent = phoneIntent;
                         mAlternateIntent = smsIntent;
-                        mAlternateIconRes = phone.getDataKind().iconAltRes;
-                        mAlternateIconDescriptionRes = phone.getDataKind().iconAltDescriptionRes;
+                        mAlternateIconRes = kind.iconAltRes;
+                        mAlternateIconDescriptionRes = kind.iconAltDescriptionRes;
                     } else if (hasPhone) {
                         mIntent = phoneIntent;
                     } else if (hasSms) {
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 25fb3f4..72d8521 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -58,9 +58,11 @@
 
 import com.android.contacts.Collapser;
 import com.android.contacts.R;
+import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.Contact;
 import com.android.contacts.model.ContactLoader;
 import com.android.contacts.model.RawContact;
+import com.android.contacts.model.account.AccountType;
 import com.android.contacts.model.dataitem.DataItem;
 import com.android.contacts.model.dataitem.DataKind;
 import com.android.contacts.model.dataitem.EmailDataItem;
@@ -348,6 +350,9 @@
         for (RawContact rawContact : data.getRawContacts()) {
             for (DataItem dataItem : rawContact.getDataItems()) {
                 final String mimeType = dataItem.getMimeType();
+                final AccountType accountType = rawContact.getAccountType(this);
+                final DataKind dataKind = AccountTypeManager.getInstance(this)
+                        .getKindOrFallback(accountType, mimeType);
 
                 // Skip this data item if MIME-type excluded
                 if (isMimeExcluded(mimeType)) continue;
@@ -356,11 +361,11 @@
                 final boolean isPrimary = dataItem.isPrimary();
                 final boolean isSuperPrimary = dataItem.isSuperPrimary();
 
-                if (dataItem.getDataKind() != null) {
+                if (dataKind != null) {
                     // Build an action for this data entry, find a mapping to a UI
                     // element, build its summary from the cursor, and collect it
                     // along with all others of this MIME-type.
-                    final Action action = new DataAction(context, dataItem);
+                    final Action action = new DataAction(context, dataItem, dataKind);
                     final boolean wasAdded = considerAdd(action, cache, isSuperPrimary);
                     if (wasAdded) {
                         // Remember the default
@@ -375,8 +380,8 @@
                 if (status != null && dataItem instanceof EmailDataItem) {
                     final EmailDataItem email = (EmailDataItem) dataItem;
                     final ImDataItem im = ImDataItem.createFromEmail(email);
-                    if (im.getDataKind() != null) {
-                        final DataAction action = new DataAction(context, im);
+                    if (dataKind != null) {
+                        final DataAction action = new DataAction(context, im, dataKind);
                         action.setPresence(status.getPresence());
                         considerAdd(action, cache, isSuperPrimary);
                     }