Remove all List forms of KindSectionData

Pick and render one raw contact delta at a time in editor.
Have the account selector always visible.
  - When viewing a read only contact, header will say "Viewing"
  - Otherwise it says "Saving to"
Swap between raw contact deltas when an account is selected in the
drop down
Keep menu options available even when viewing just one raw contact.
Remove some code related to photo picker.

Test:
Tested the following editor scenarios:
  1) new contact
  2) edit other contact
  3) edit writable raw contact
  4) edit read-only raw contact (joins a new writable raw contact to it)
  5) edit aggregate w/ 1 writable and 1 read-only raw contact
  6) edit aggregate w/ 2 writable raw contacts
  7) edit local me raw contact
  8) edit local me raw contact joined with a read-only raw contact
  9) editing photo of a raw contact that is part of an aggregate
     updates the aggregate photo
  10) same with editing the name

Change-Id: Id797619e656d3a9974cc9454a3d26fee471569d5
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index caacc36..7a52a37 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -16,17 +16,14 @@
 
 package com.android.contacts.editor;
 
-import android.content.ContentUris;
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.Cursor;
-import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Event;
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
@@ -44,7 +41,6 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -127,7 +123,7 @@
         /**
          * Invoked when a rawcontact from linked contacts is selected in editor.
          */
-        public void onRawContactSelected(Uri uri, long rawContactId, boolean isReadOnly);
+        void onRawContactSelected(long rawContactId, boolean isReadOnly);
 
         /**
          * Returns the map of raw contact IDs to newly taken or selected photos that have not
@@ -286,10 +282,10 @@
     private boolean mIsUserProfile;
     private AccountWithDataSet mPrimaryAccount;
     private RawContactDeltaList mRawContactDeltas;
+    private RawContactDelta mCurrentRawContactDelta;
     private long mRawContactIdToDisplayAlone = -1;
     private boolean mRawContactDisplayAloneIsReadOnly;
     private boolean mIsEditingReadOnlyRawContactWithNewContact;
-    private KindSectionDataList mPhotoKindSectionDataList = new KindSectionDataList();
     private Map<String, KindSectionData> mKindSectionDataMap = new HashMap<>();
     private Set<String> mSortedMimetypes = new TreeSet<>(new MimeTypeComparator());
 
@@ -441,11 +437,18 @@
     }
 
     private void unsetSuperPrimaryFromAllPhotos() {
-        for (int i = 0; i < mPhotoKindSectionDataList.size(); i++) {
-            final KindSectionData kindSectionData = mPhotoKindSectionDataList.get(0);
-            final List<ValuesDelta> valuesDeltas = kindSectionData.getNonEmptyValuesDeltas();
-            for (int j = 0; j < valuesDeltas.size(); j++) {
-                valuesDeltas.get(j).setSuperPrimary(false);
+        for (int i = 0; i < mRawContactDeltas.size(); i++) {
+            final RawContactDelta rawContactDelta = mRawContactDeltas.get(i);
+            if (!rawContactDelta.hasMimeEntries(Photo.CONTENT_ITEM_TYPE)) {
+                continue;
+            }
+            final List<ValuesDelta> photosDeltas =
+                    mRawContactDeltas.get(i).getMimeEntries(Photo.CONTENT_ITEM_TYPE);
+            if (photosDeltas == null) {
+                continue;
+            }
+            for (int j = 0; j < photosDeltas.size(); j++) {
+                photosDeltas.get(j).setSuperPrimary(false);
             }
         }
     }
@@ -470,74 +473,16 @@
                 ? null : primaryNameKindSectionView.getPrimaryNameEditorView();
     }
 
-    /**
-     * Returns a data holder for every non-default/non-empty photo from each raw contact, whether
-     * the raw contact is writable or not.
-     */
-    public ArrayList<CompactPhotoSelectionFragment.Photo> getPhotos() {
-        final ArrayList<CompactPhotoSelectionFragment.Photo> photos = new ArrayList<>();
-
-        final Bundle updatedPhotos = mListener == null ? null : mListener.getUpdatedPhotos();
-
-        for (int i = 0; i < mPhotoKindSectionDataList.size(); i++) {
-            final KindSectionData kindSectionData = mPhotoKindSectionDataList.get(i);
-            final AccountType accountType = kindSectionData.getAccountType();
-            final List<ValuesDelta> valuesDeltas = kindSectionData.getNonEmptyValuesDeltas();
-            if (valuesDeltas.isEmpty()) continue;
-            for (int j = 0; j < valuesDeltas.size(); j++) {
-                final ValuesDelta valuesDelta = valuesDeltas.get(j);
-                final Bitmap bitmap = EditorUiUtils.getPhotoBitmap(valuesDelta);
-                if (bitmap == null) continue;
-
-                final CompactPhotoSelectionFragment.Photo photo =
-                        new CompactPhotoSelectionFragment.Photo();
-                photo.titleRes = accountType.titleRes;
-                photo.iconRes = accountType.iconRes;
-                photo.syncAdapterPackageName = accountType.syncAdapterPackageName;
-                photo.valuesDelta = valuesDelta;
-                photo.primary = valuesDelta.isSuperPrimary();
-                photo.kindSectionDataListIndex = i;
-                photo.valuesDeltaListIndex = j;
-                photo.photoId = valuesDelta.getId();
-
-                if (updatedPhotos != null) {
-                    photo.updatedPhotoUri = (Uri) updatedPhotos.get(String.valueOf(
-                            kindSectionData.getRawContactDelta().getRawContactId()));
-                }
-
-                final CharSequence accountTypeLabel = accountType.getDisplayLabel(getContext());
-                photo.accountType = accountTypeLabel == null ? "" : accountTypeLabel.toString();
-                final String accountName = kindSectionData.getRawContactDelta().getAccountName();
-                photo.accountName = accountName == null ? "" : accountName;
-
-                photos.add(photo);
-            }
-        }
-
-        return photos;
-    }
 
     /**
      * Marks the raw contact photo given as primary for the aggregate contact and updates the
      * UI.
      */
     public void setPrimaryPhoto(CompactPhotoSelectionFragment.Photo photo) {
-        // Find the values delta to mark as primary
-        if (photo.kindSectionDataListIndex < 0
-                || photo.kindSectionDataListIndex >= mPhotoKindSectionDataList.size()) {
-            wlog("Invalid kind section data list index");
-            return;
-        }
-        final KindSectionData kindSectionData =
-                mPhotoKindSectionDataList.get(photo.kindSectionDataListIndex);
-        final List<ValuesDelta> valuesDeltaList = kindSectionData.getNonEmptyValuesDeltas();
-        if (photo.valuesDeltaListIndex >= valuesDeltaList.size()) {
-            wlog("Invalid values delta list index");
-            return;
-        }
 
         // Update values delta
-        final ValuesDelta valuesDelta = valuesDeltaList.get(photo.valuesDeltaListIndex);
+        final ValuesDelta valuesDelta = mCurrentRawContactDelta
+                .getSuperPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
         valuesDelta.setFromTemplate(false);
         unsetSuperPrimaryFromAllPhotos();
         valuesDelta.setSuperPrimary(true);
@@ -576,9 +521,7 @@
         mRawContactDisplayAloneIsReadOnly = rawContactDisplayAloneIsReadOnly;
         mIsEditingReadOnlyRawContactWithNewContact = isEditingReadOnlyRawContactWithNewContact;
 
-        mKindSectionDataMap.clear();
         mKindSectionViewMap.clear();
-        mSortedMimetypes.clear();
         mKindSectionViews.removeAllViews();
         mMoreFields.setVisibility(View.VISIBLE);
 
@@ -600,7 +543,8 @@
             if (mListener != null) mListener.onBindEditorsFailed();
             return;
         }
-        parseRawContactDeltas(rawContactDeltas);
+        pickRawContactDelta();
+        parseRawContactDelta();
         if (mKindSectionDataMap.isEmpty()) {
             elog("No kind section data parsed from RawContactDelta(s)");
             if (mListener != null) mListener.onBindEditorsFailed();
@@ -625,29 +569,9 @@
 
         // Setup the view
         addPhotoView();
-        if (isSingleReadOnlyRawContact()) {
+        if (isReadOnlyRawContact()) {
             // We're want to display the inputs fields for a single read only raw contact
             addReadOnlyRawContactEditorViews();
-            // Hide the "More fields" link
-            mMoreFields.setVisibility(View.GONE);
-        } else if (mIsEditingReadOnlyRawContactWithNewContact) {
-            // A new writable raw contact was created and joined with the read only contact
-            // that the user is trying to edit.
-            setupCompactEditorNormally();
-
-            // TODO: Hide the raw contact selector since it will just contain the read-only raw
-            // contact and clicking that will just open the exact same editor.  When we clean up
-            // the whole account header, selector, and raw contact selector mess, we can prevent
-            // the selector from being displayed in a less hacky way.
-            mRawContactContainer.setVisibility(View.GONE);
-        } else if (mRawContactDeltas.size() > 1) {
-            // We're editing an aggregate composed of more than one writable raw contacts
-
-            // TODO: Don't render any input fields. Eventually we will show a list of account
-            // types and names but for now just show the account selector and hide the "More fields"
-            // link.
-            addAccountInfo();
-            mMoreFields.setVisibility(View.GONE);
         } else {
             setupCompactEditorNormally();
         }
@@ -663,135 +587,104 @@
         if (mIsExpanded) showAllFields();
     }
 
-    private boolean isSingleReadOnlyRawContact() {
-        return mRawContactDeltas.size() == 1
-                && mRawContactDeltas.get(0).getRawContactId() == mRawContactIdToDisplayAlone
-                && mRawContactDisplayAloneIsReadOnly;
+    private boolean isReadOnlyRawContact() {
+        return !mCurrentRawContactDelta.getAccountType(mAccountTypeManager).areContactsWritable();
     }
 
-    private void parseRawContactDeltas(RawContactDeltaList rawContactDeltas) {
+    private void pickRawContactDelta() {
         // Build the kind section data list map
-        vlog("parse: " + rawContactDeltas.size() + " rawContactDelta(s)");
-        for (int j = 0; j < rawContactDeltas.size(); j++) {
-            final RawContactDelta rawContactDelta = rawContactDeltas.get(j);
+        vlog("parse: " + mRawContactDeltas.size() + " rawContactDelta(s)");
+        for (int j = 0; j < mRawContactDeltas.size(); j++) {
+            final RawContactDelta rawContactDelta = mRawContactDeltas.get(j);
             vlog("parse: " + j + " rawContactDelta" + rawContactDelta);
             if (rawContactDelta == null || !rawContactDelta.isVisible()) continue;
             final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
             if (accountType == null) continue;
-            final List<DataKind> dataKinds = accountType.getSortedDataKinds();
-            final int dataKindSize = dataKinds == null ? 0 : dataKinds.size();
-            vlog("parse: " + dataKindSize + " dataKinds(s)");
-            for (int i = 0; i < dataKindSize; i++) {
-                final DataKind dataKind = dataKinds.get(i);
-                if (dataKind == null) {
-                    vlog("parse: " + i + " " + dataKind.mimeType + " dropped null data kind");
-                    continue;
+
+            if (mRawContactIdToDisplayAlone > 0) {
+                // Look for the raw contact if specified.
+                if (rawContactDelta.getRawContactId().equals(mRawContactIdToDisplayAlone)) {
+                    mCurrentRawContactDelta = rawContactDelta;
+                    return;
                 }
-                final String mimeType = dataKind.mimeType;
-
-                // Skip psuedo mime types
-                if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)
-                        || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
-                    vlog("parse: " + i + " " + dataKind.mimeType + " dropped pseudo type");
-                    continue;
-                }
-
-                // Skip custom fields
-                // TODO: Handle them when we implement editing custom fields.
-                if (CustomDataItem.MIMETYPE_CUSTOM_FIELD.equals(mimeType)) {
-                    vlog("parse: " + i + " " + dataKind.mimeType + " dropped custom field");
-                    continue;
-                }
-
-                // Add all photo data.
-                if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
-                    final KindSectionData photoKindSectionData =
-                            new KindSectionData(accountType, dataKind, rawContactDelta);
-                    mPhotoKindSectionDataList.add(photoKindSectionData);
-                    vlog("parse: " + i + " " + dataKind.mimeType + " " +
-                            photoKindSectionData.getValuesDeltas().size() + " value(s) " +
-                            photoKindSectionData.getNonEmptyValuesDeltas().size() +
-                            " non-empty value(s) " +
-                            photoKindSectionData.getVisibleValuesDeltas().size() +
-                            " visible value(s)");
-                    continue;
-                }
-
-                // Skip the non-writable names when we're auto creating a new writable contact.
-                if (mIsEditingReadOnlyRawContactWithNewContact
-                        && !accountType.areContactsWritable()
-                        && StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
-                    vlog("parse: " + i + " " + dataKind.mimeType + " dropped non-writable name");
-                    continue;
-                }
-
-                // Skip non-photo data that doesn't belong to the single raw contact we're editing.
-                if (mRawContactIdToDisplayAlone > 0 &&
-                        !rawContactDelta.getRawContactId().equals(mRawContactIdToDisplayAlone)) {
-                    continue;
-                }
-
-                final KindSectionData kindSectionData =
-                        new KindSectionData(accountType, dataKind, rawContactDelta);
-                mKindSectionDataMap.put(mimeType, kindSectionData);
-                mSortedMimetypes.add(mimeType);
-
-                vlog("parse: " + i + " " + dataKind.mimeType + " " +
-                        kindSectionData.getValuesDeltas().size() + " value(s) " +
-                        kindSectionData.getNonEmptyValuesDeltas().size() + " non-empty value(s) " +
-                        kindSectionData.getVisibleValuesDeltas().size() +
-                        " visible value(s)");
+            } else if (mPrimaryAccount != null
+                    && mPrimaryAccount.equals(rawContactDelta.getAccountWithDataSet())) {
+                // Otherwise try to find the one that matches the default.
+                mCurrentRawContactDelta = rawContactDelta;
+                return;
+            } else if (accountType.areContactsWritable()){
+                // TODO: Find better raw contact delta
+                // Just select an arbitrary writable contact.
+                mCurrentRawContactDelta = rawContactDelta;
             }
         }
+
+    }
+
+    private void parseRawContactDelta() {
+        mKindSectionDataMap.clear();
+        mSortedMimetypes.clear();
+
+        final AccountType accountType = mCurrentRawContactDelta.getAccountType(mAccountTypeManager);
+        final List<DataKind> dataKinds = accountType.getSortedDataKinds();
+        final int dataKindSize = dataKinds == null ? 0 : dataKinds.size();
+        vlog("parse: " + dataKindSize + " dataKinds(s)");
+
+        for (int i = 0; i < dataKindSize; i++) {
+            final DataKind dataKind = dataKinds.get(i);
+            if (dataKind == null) {
+                vlog("parse: " + i + " " + dataKind.mimeType + " dropped null data kind");
+                continue;
+            }
+            final String mimeType = dataKind.mimeType;
+
+            // Skip psuedo mime types
+            if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)
+                    || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
+                vlog("parse: " + i + " " + dataKind.mimeType + " dropped pseudo type");
+                continue;
+            }
+
+            // Skip custom fields
+            // TODO: Handle them when we implement editing custom fields.
+            if (CustomDataItem.MIMETYPE_CUSTOM_FIELD.equals(mimeType)) {
+                vlog("parse: " + i + " " + dataKind.mimeType + " dropped custom field");
+                continue;
+            }
+
+            final KindSectionData kindSectionData =
+                    new KindSectionData(accountType, dataKind, mCurrentRawContactDelta);
+            mKindSectionDataMap.put(mimeType, kindSectionData);
+            mSortedMimetypes.add(mimeType);
+
+            vlog("parse: " + i + " " + dataKind.mimeType + " " +
+                    kindSectionData.getValuesDeltas().size() + " value(s) " +
+                    kindSectionData.getNonEmptyValuesDeltas().size() + " non-empty value(s) " +
+                    kindSectionData.getVisibleValuesDeltas().size() +
+                    " visible value(s)");
+        }
     }
 
     private void addReadOnlyRawContactEditorViews() {
         mKindSectionViews.removeAllViews();
+        addAccountInfo();
         final AccountTypeManager accountTypes = AccountTypeManager.getInstance(
                 getContext());
-        final RawContactDelta state = mRawContactDeltas
-                .getByRawContactId(mRawContactIdToDisplayAlone);
-        final AccountType type = state.getAccountType(accountTypes);
+        final AccountType type = mCurrentRawContactDelta.getAccountType(accountTypes);
 
         // Bail if invalid state or source
-        if (state == null || type == null) return;
+        if (type == null) return;
 
         // Make sure we have StructuredName
-        RawContactModifier.ensureKindExists(state, type, StructuredName.CONTENT_ITEM_TYPE);
-
-        final AccountDisplayInfo account = mAccountDisplayInfoFactory
-                .getAccountDisplayInfoFor(state);
-
-        final String accountTypeLabel;
-        final String accountNameLabel;
-        if (mIsUserProfile) {
-            accountTypeLabel = EditorUiUtils.getAccountHeaderLabelForMyProfile(
-                    getContext(), account);
-            accountNameLabel = account.getNameLabel().toString();
-        } else {
-            accountTypeLabel = account.getTypeLabel().toString();
-            accountNameLabel = account.getNameLabel().toString();
-        }
-
-        if (!account.hasDistinctName()) {
-            // Hide this view so the other view will be centered vertically
-            mAccountHeaderName.setVisibility(View.GONE);
-        } else {
-            mAccountHeaderName.setVisibility(View.VISIBLE);
-            mAccountHeaderName.setText(accountNameLabel);
-        }
-        mAccountHeaderType.setText(accountTypeLabel);
-        updateAccountHeaderContentDescription();
-
-        mAccountHeaderIcon.setImageDrawable(state.getRawContactAccountType(getContext())
-                .getDisplayIcon(getContext()));
+        RawContactModifier.ensureKindExists(
+                mCurrentRawContactDelta, type, StructuredName.CONTENT_ITEM_TYPE);
 
         ValuesDelta primary;
 
         // Name
         final Context context = getContext();
         final Resources res = context.getResources();
-        primary = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
+        primary = mCurrentRawContactDelta.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
         final String name = primary != null ? primary.getAsString(StructuredName.DISPLAY_NAME) :
             getContext().getString(R.string.missing_name);
         final Drawable nameDrawable = context.getDrawable(R.drawable.ic_person_24dp);
@@ -800,7 +693,8 @@
                 /* isFirstEntry */ true);
 
         // Phones
-        final ArrayList<ValuesDelta> phones = state.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
+        final ArrayList<ValuesDelta> phones = mCurrentRawContactDelta
+                .getMimeEntries(Phone.CONTENT_ITEM_TYPE);
         final Drawable phoneDrawable = context.getDrawable(R.drawable.ic_phone_24dp);
         final String phoneContentDescription = res.getString(R.string.header_phone_entry);
         if (phones != null) {
@@ -825,7 +719,8 @@
         }
 
         // Emails
-        final ArrayList<ValuesDelta> emails = state.getMimeEntries(Email.CONTENT_ITEM_TYPE);
+        final ArrayList<ValuesDelta> emails = mCurrentRawContactDelta
+                .getMimeEntries(Email.CONTENT_ITEM_TYPE);
         final Drawable emailDrawable = context.getDrawable(R.drawable.ic_email_24dp);
         final String emailContentDescription = res.getString(R.string.header_email_entry);
         if (emails != null) {
@@ -851,13 +746,6 @@
         mMoreFields.setVisibility(GONE);
     }
 
-    protected void updateAccountHeaderContentDescription() {
-        final StringBuilder builder = new StringBuilder();
-        builder.append(EditorUiUtils.getAccountInfoContentDescription(
-                mAccountHeaderName.getText(), mAccountHeaderType.getText()));
-        mAccountHeaderContainer.setContentDescription(builder);
-    }
-
     private void bindData(Drawable icon, String iconContentDescription, CharSequence data,
             CharSequence type, boolean isFirstEntry) {
         bindData(icon, iconContentDescription, data, type, isFirstEntry, false);
@@ -895,14 +783,9 @@
     private void addAccountInfo() {
         mAccountHeaderContainer.setVisibility(View.GONE);
         mRawContactContainer.setVisibility(View.GONE);
-        final KindSectionData nameSectionData =
-                mKindSectionDataMap.get(StructuredName.CONTENT_ITEM_TYPE);
-        if (nameSectionData == null) return;
-        final RawContactDelta rawContactDelta =
-                nameSectionData.getRawContactDelta();
 
         final AccountDisplayInfo account =
-                mAccountDisplayInfoFactory.getAccountDisplayInfoFor(rawContactDelta);
+                mAccountDisplayInfoFactory.getAccountDisplayInfoFor(mCurrentRawContactDelta);
 
         // Get the account information for the primary raw contact delta
         final String accountLabel = mIsUserProfile
@@ -912,9 +795,10 @@
         // Either the account header or selector should be shown, not both.
         final List<AccountWithDataSet> accounts =
                 AccountTypeManager.getInstance(getContext()).getAccounts(true);
+
         if (mHasNewContact && !mIsUserProfile) {
             if (accounts.size() > 1) {
-                addAccountSelector(rawContactDelta, accountLabel);
+                addAccountSelector(mCurrentRawContactDelta, accountLabel);
             } else {
                 addAccountHeader(accountLabel);
             }
@@ -926,11 +810,8 @@
         // the full editor (i.e. they are not newly created raw contacts)
         final RawContactAccountListAdapter adapter =  new RawContactAccountListAdapter(getContext(),
                 getRawContactDeltaListForSelector(mRawContactDeltas));
-        if (adapter.getCount() > 0) {
-            final String accountsSummary = getResources().getQuantityString(
-                    R.plurals.compact_editor_linked_contacts_selector_title,
-                    adapter.getCount(), adapter.getCount());
-            addRawContactAccountSelector(accountsSummary, adapter);
+        if (adapter.getCount() > 0 && !mIsEditingReadOnlyRawContactWithNewContact) {
+            addRawContactAccountSelector(accountLabel, adapter);
         }
     }
 
@@ -982,22 +863,15 @@
         mAccountHeaderName.setText(accountLabel);
 
         // Set the account type
-        final String selectorTitle = getResources().getString(
+        final String selectorTitle = getResources().getString(isReadOnlyRawContact() ?
+                R.string.compact_editor_account_selector_read_only_title :
                 R.string.compact_editor_account_selector_title);
         mAccountHeaderType.setText(selectorTitle);
 
         // Set the icon
-        final KindSectionData nameSectionData =
-                mKindSectionDataMap.get(StructuredName.CONTENT_ITEM_TYPE);
-        if (nameSectionData != null) {
-            final RawContactDelta rawContactDelta =
-                    nameSectionData.getRawContactDelta();
-            if (rawContactDelta != null) {
-                final AccountType accountType =
-                        rawContactDelta.getRawContactAccountType(getContext());
-                mAccountHeaderIcon.setImageDrawable(accountType.getDisplayIcon(getContext()));
-            }
-        }
+        final AccountType accountType =
+                mCurrentRawContactDelta.getRawContactAccountType(getContext());
+        mAccountHeaderIcon.setImageDrawable(accountType.getDisplayIcon(getContext()));
 
         // Set the content description
         mAccountHeaderContainer.setContentDescription(
@@ -1006,11 +880,7 @@
     }
 
     private void addAccountSelector(final RawContactDelta rawContactDelta, CharSequence nameLabel) {
-        // Show save to default account.
-        addAccountHeader(nameLabel.toString());
-        // Add handlers for choosing another account to save to.
-        mAccountHeaderExpanderIcon.setVisibility(View.VISIBLE);
-        mAccountHeaderContainer.setOnClickListener(new View.OnClickListener() {
+        final View.OnClickListener onClickListener = new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 final ListPopupWindow popup = new ListPopupWindow(getContext(), null);
@@ -1030,6 +900,7 @@
                         UiClosables.closeQuietly(popup);
                         final AccountWithDataSet newAccount = adapter.getItem(position);
                         if (mListener != null && !mPrimaryAccount.equals(newAccount)) {
+                            mIsExpanded = false;
                             mListener.onRebindEditorsForNewContact(
                                     rawContactDelta,
                                     mPrimaryAccount,
@@ -1039,21 +910,18 @@
                 });
                 popup.show();
             }
-        });
+        };
+        setUpAccountSelector(nameLabel.toString(), onClickListener);
     }
 
-    private void addRawContactAccountSelector(String accountsSummary,
+    private void addRawContactAccountSelector(String nameLabel,
             final RawContactAccountListAdapter adapter) {
-        mRawContactContainer.setVisibility(View.VISIBLE);
-
-        mRawContactSummary.setText(accountsSummary);
-
-        mRawContactContainer.setOnClickListener(new View.OnClickListener() {
+        final View.OnClickListener onClickListener = new OnClickListener() {
             @Override
             public void onClick(View v) {
                 final ListPopupWindow popup = new ListPopupWindow(getContext(), null);
-                popup.setWidth(mRawContactContainer.getWidth());
-                popup.setAnchorView(mRawContactContainer);
+                popup.setWidth(mAccountHeaderContainer.getWidth());
+                popup.setAnchorView(mAccountHeaderContainer);
                 popup.setAdapter(adapter);
                 popup.setModal(true);
                 popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
@@ -1062,54 +930,56 @@
                     public void onItemClick(AdapterView<?> parent, View view, int position,
                                             long id) {
                         UiClosables.closeQuietly(popup);
-
-                        if (mListener != null) {
-                            final long rawContactId = adapter.getItemId(position);
-                            final Uri rawContactUri = ContentUris.withAppendedId(
-                                    ContactsContract.RawContacts.CONTENT_URI, rawContactId);
+                        final long rawContactId = adapter.getItemId(position);
+                        // Only switch if it's actually a different raw contact.
+                        if (rawContactId != mCurrentRawContactDelta.getRawContactId()
+                                && mListener != null) {
                             final RawContactDelta rawContactDelta = adapter.getItem(position);
                             final AccountTypeManager accountTypes = AccountTypeManager.getInstance(
                                     getContext());
                             final AccountType accountType = rawContactDelta.getAccountType(
                                     accountTypes);
                             final boolean isReadOnly = !accountType.areContactsWritable();
-
-                            mListener.onRawContactSelected(rawContactUri, rawContactId, isReadOnly);
+                            // Reset state.
+                            mIsExpanded = false;
+                            mListener.onRawContactSelected(rawContactId, isReadOnly);
                         }
                     }
                 });
                 popup.show();
             }
-        });
+        };
+        setUpAccountSelector(nameLabel, onClickListener);
+    }
+
+    private void setUpAccountSelector(String nameLabel, OnClickListener listener) {
+        addAccountHeader(nameLabel);
+        // Add handlers for choosing another account to save to.
+        mAccountHeaderExpanderIcon.setVisibility(View.VISIBLE);
+        mAccountHeaderContainer.setOnClickListener(listener);
     }
 
     private void addPhotoView() {
-        // Get the kind section data and values delta that we will display in the photo view. Either
-        // the aggregate photo or the photo from the raw contact that is being edited.
-        final Pair<KindSectionData, ValuesDelta> photo =
-                mPhotoKindSectionDataList.getEntryToDisplay(
-                        mRawContactIdToDisplayAlone > 0
-                                ? mRawContactIdToDisplayAlone
-                                : mAggregatePhotoId);
-        if (photo == null) {
-            wlog("photo: no kind section data parsed");
+        if (!mCurrentRawContactDelta.hasMimeEntries(Photo.CONTENT_ITEM_TYPE)) {
+            wlog("No photo mimetype for this raw contact.");
             mPhotoView.setVisibility(View.GONE);
             return;
         } else {
             mPhotoView.setVisibility(View.VISIBLE);
         }
 
+        final ValuesDelta superPrimaryDelta = mCurrentRawContactDelta
+                .getSuperPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
         // Set the photo view
-        mPhotoView.setPhoto(photo.second, mMaterialPalette);
+        mPhotoView.setPhoto(superPrimaryDelta, mMaterialPalette);
 
-        // If we're showing an aggregate photo, set it to read only.
-        if (mRawContactIdToDisplayAlone < 1) {
+        if (isReadOnlyRawContact()) {
             mPhotoView.setReadOnly(true);
             return;
         }
         mPhotoView.setReadOnly(false);
-        mPhotoRawContactId = photo.first.getRawContactDelta().getRawContactId();
-        mPhotoValuesDelta = photo.second;
+        mPhotoRawContactId = mCurrentRawContactDelta.getRawContactId();
+        mPhotoValuesDelta = superPrimaryDelta;
     }
 
     private void addKindSectionViews() {
@@ -1117,31 +987,16 @@
 
         for (String mimeType : mSortedMimetypes) {
             i++;
-            final CompactKindSectionView kindSectionView;
-            // TODO: Since we don't have a primary name kind anymore, refactor and collapse
-            // these two branches and the following code paths.
-            if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
-                final KindSectionData nameSectionData = mKindSectionDataMap.get(mimeType);
-                if (nameSectionData == null) {
-                    vlog("kind: " + i + " " + mimeType + " dropped");
-                    continue;
-                }
-                vlog("kind: " + i + " " + mimeType + " using first entry only");
-                kindSectionView = inflateKindSectionView(
-                        mKindSectionViews, nameSectionData, mimeType,
-                        nameSectionData.getValuesDeltas().get(0));
-            } else {
-                final KindSectionData kindSectionData = mKindSectionDataMap.get(mimeType);
-
-                // Ignore mime types that we've already handled
-                if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
-                    vlog("kind: " + i + " " + mimeType + " dropped");
-                    continue;
-                }
-                kindSectionView = inflateKindSectionView(
-                        mKindSectionViews, kindSectionData, mimeType,
-                        /* primaryValueDelta =*/ null);
+            // Ignore mime types that we've already handled
+            if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                vlog("kind: " + i + " " + mimeType + " dropped");
+                continue;
             }
+            final CompactKindSectionView kindSectionView;
+            final KindSectionData kindSectionData = mKindSectionDataMap.get(mimeType);
+            final ValuesDelta primaryDelta = mCurrentRawContactDelta.getPrimaryEntry(mimeType);
+            kindSectionView = inflateKindSectionView(mKindSectionViews, kindSectionData, mimeType,
+                    primaryDelta);
             mKindSectionViews.addView(kindSectionView);
 
             // Keep a pointer to the KindSectionView for each mimeType