Try to show the "right" name on the compact contact editor

* If a super primary is set use it on the compact editor
* If a super primary is not set and the compact editor
  name value is changed, set it as super primary.  But
  don't make an unchanged name super primary when expanding
  to the full editor.  Also unset super primary if
  the name field becomes blank.
* On the full editor, set the last changed name to super
  primary.  Also unset super primary if
  the name field becomes blank.

Bug 19124091

Change-Id: I1352f25f4decf31c5aeda20dbef133ce48d5d248
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index 1287d47..cb605c6 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -64,6 +64,54 @@
          * Invoked when the compact editor should be expanded to show all fields.
          */
         public void onExpandEditor();
+
+        /**
+         * Invoked when the structured name editor field has changed.
+         *
+         * @param rawContactId The raw contact ID from the underlying {@link RawContactDelta}.
+         * @param valuesDelta The values from the underlying {@link RawContactDelta}.
+         */
+        public void onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta);
+    }
+
+    /**
+     * Marks a name as super primary when it is changed.
+     *
+     * This is for the case when two or more raw contacts with names are joined where neither is
+     * marked as super primary.  If the user hits back (which causes a save) after changing the
+     * name that was arbitrarily displayed, we want that to be the name that is used.
+     *
+     * Should only be set when a super primary name does not already exist since we only show
+     * one name field.
+     */
+    static final class NameEditorListener implements Editor.EditorListener {
+
+        private final ValuesDelta mValuesDelta;
+        private final long mRawContactId;
+        private final Listener mListener;
+
+        public NameEditorListener(ValuesDelta valuesDelta, long rawContactId,
+                Listener listener) {
+            mValuesDelta = valuesDelta;
+            mRawContactId = rawContactId;
+            mListener = listener;
+        }
+
+        @Override
+        public void onRequest(int request) {
+            if (request == Editor.EditorListener.FIELD_CHANGED) {
+                mValuesDelta.setSuperPrimary(true);
+                if (mListener != null) {
+                    mListener.onNameFieldChanged(mRawContactId, mValuesDelta);
+                }
+            } else if (request == Editor.EditorListener.FIELD_TURNED_EMPTY) {
+                mValuesDelta.setSuperPrimary(false);
+            }
+        }
+
+        @Override
+        public void onDeleteRequested(Editor editor) {
+        }
     }
 
     private Listener mListener;
@@ -83,6 +131,9 @@
     private ViewGroup mOther;
     private View mMoreFields;
 
+    // The ValuesDelta for the non super primary name that was displayed to the user.
+    private ValuesDelta mNameValuesDelta;
+
     private long mPhotoRawContactId;
 
     public CompactRawContactsEditorView(Context context) {
@@ -122,6 +173,13 @@
     @Override
     public void onClick(View view) {
         if (view.getId() == R.id.more_fields && mListener != null ) {
+            // We mark the name that was displayed as super primary before expanding
+            // so that a save on the expanded editor (without a name change) does not
+            // cause the displayed name to change.
+            if (mNameValuesDelta != null) {
+                mNameValuesDelta.setSuperPrimary(true);
+            }
+
             mListener.onExpandEditor();
         }
     }
@@ -208,14 +266,14 @@
                 /* valuesDelta =*/ null, ViewIdGenerator.NO_VIEW_INDEX));
         mMaterialPalette = materialPalette;
 
-        addHeaderView(rawContactDeltas, viewIdGenerator);
+        addPhotoView(rawContactDeltas, viewIdGenerator);
         addStructuredNameView(rawContactDeltas);
         addEditorViews(rawContactDeltas);
         removeExtraEmptyTextFields(mPhoneNumbers);
         removeExtraEmptyTextFields(mEmails);
     }
 
-    private void addHeaderView(RawContactDeltaList rawContactDeltas,
+    private void addPhotoView(RawContactDeltaList rawContactDeltas,
             ViewIdGenerator viewIdGenerator) {
         for (RawContactDelta rawContactDelta : rawContactDeltas) {
             if (!rawContactDelta.isVisible()) {
@@ -243,24 +301,68 @@
 
     private void addStructuredNameView(RawContactDeltaList rawContactDeltas) {
         for (RawContactDelta rawContactDelta : rawContactDeltas) {
-            if (!rawContactDelta.isVisible()) {
-                continue;
-            }
+            if (!rawContactDelta.isVisible()) continue;
             final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
 
             // Make sure we have a structured name
             RawContactModifier.ensureKindExists(
                     rawContactDelta, accountType, StructuredName.CONTENT_ITEM_TYPE);
 
+            // Note use of pseudo mime type to get the DataKind and StructuredName to get value
             final DataKind dataKind = accountType.getKindForMimetype(
+                    DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME);
+            if (dataKind == null || !dataKind.editable) continue;
+
+            final ValuesDelta superPrimaryValuesDelta = getNonEmptySuperPrimaryValuesDeltas(
+                    rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind);
+            if (superPrimaryValuesDelta != null) {
+                // Our first preference is for a non-empty super primary name
+                mNames.addView(inflateStructuredNameEditorView(mNames, accountType,
+                        superPrimaryValuesDelta, rawContactDelta, /* nameEditorListener =*/ null));
+                return;
+            }
+        }
+        // We didn't find a super primary name
+        for (RawContactDelta rawContactDelta : rawContactDeltas) {
+            if (!rawContactDelta.isVisible()) continue;
+            final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
+
+            final DataKind dataKind = accountType.getKindForMimetype(
+                    DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME);
+            if (dataKind == null || !dataKind.editable) continue;
+
+            final List<ValuesDelta> nonEmptyValuesDeltas = getNonEmptyValuesDeltas(
+                    rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind);
+            if (nonEmptyValuesDeltas != null && !nonEmptyValuesDeltas.isEmpty()) {
+                // Take the first non-empty name, also make it super primary before expanding to the
+                // full editor (see #onCLick) so that name does not change if the user saves from
+                // the fully expanded editor.
+                mNameValuesDelta = nonEmptyValuesDeltas.get(0);
+                final NameEditorListener nameEditorListener = new NameEditorListener(
+                        mNameValuesDelta, rawContactDelta.getRawContactId(), mListener);
+                mNames.addView(inflateStructuredNameEditorView(mNames, accountType,
+                        mNameValuesDelta, rawContactDelta, nameEditorListener));
+                return;
+            }
+        }
+        for (RawContactDelta rawContactDelta : rawContactDeltas) {
+            if (!rawContactDelta.isVisible()) continue;
+            final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
+
+            final DataKind dataKind = accountType.getKindForMimetype(
+                    DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME);
+            if (dataKind == null || !dataKind.editable) continue;
+
+            // Fall back to the first entry
+            final ArrayList<ValuesDelta> valuesDeltas = rawContactDelta.getMimeEntries(
                     StructuredName.CONTENT_ITEM_TYPE);
-            if (dataKind != null) {
-                final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(dataKind.mimeType);
-                if (valuesDelta != null) {
-                    mNames.addView(inflateStructuredNameEditorView(
-                            mNames, accountType, valuesDelta, rawContactDelta));
-                    return;
-                }
+            if (valuesDeltas != null && !valuesDeltas.isEmpty()) {
+                mNameValuesDelta = valuesDeltas.get(0);
+                final NameEditorListener nameEditorListener = new NameEditorListener(
+                        mNameValuesDelta, rawContactDelta.getRawContactId(), mListener);
+                mNames.addView(inflateStructuredNameEditorView(mNames, accountType,
+                        mNameValuesDelta, rawContactDelta, nameEditorListener));
+                return;
             }
         }
     }
@@ -281,20 +383,24 @@
                 if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)
                         || StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)
                         || GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
-                    // Photos and name are handled separately; group membership is not supported
+                    // Photos and structured names are handled separately and
+                    // group membership is not supported
                     continue;
                 } else if (DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
-                    // Use the StructuredName mime type to get values
-                    if (hasNonEmptyPrimaryValuesDelta(
+                    // Only add phonetic names if there is a non-empty one. Note the use of
+                    // StructuredName mimeType below, even though we matched a pseudo mime type.
+                    if (hasNonEmptyValuesDelta(
                             rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind)) {
-                        final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(
-                                StructuredName.CONTENT_ITEM_TYPE);
-                        mPhoneticNames.addView(inflatePhoneticNameEditorView(
-                                mPhoneticNames, accountType, valuesDelta, rawContactDelta));
+                        for (ValuesDelta valuesDelta : getNonEmptyValuesDeltas(
+                                rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind)) {
+                            mPhoneticNames.addView(inflatePhoneticNameEditorView(
+                                    mPhoneticNames, accountType, valuesDelta, rawContactDelta));
+                        }
                     }
                 } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                    // Only add nicknames if there is a non-empty one
                     if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
-                        mNicknames.addView(inflateNicknameEditorView(
+                        mNicknames.addView(inflateKindSectionView(
                                 mNicknames, dataKind, rawContactDelta));
                     }
                 } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
@@ -357,7 +463,18 @@
         return !getNonEmptyValuesDeltas(rawContactDelta, mimeType, dataKind).isEmpty();
     }
 
-    private static List<ValuesDelta> getNonEmptyValuesDeltas(RawContactDelta rawContactDelta,
+    private static ValuesDelta getNonEmptySuperPrimaryValuesDeltas(RawContactDelta rawContactDelta,
+            String mimeType, DataKind dataKind) {
+        for (ValuesDelta valuesDelta : getNonEmptyValuesDeltas(
+                rawContactDelta, mimeType, dataKind)) {
+            if (valuesDelta.isSuperPrimary()) {
+                return valuesDelta;
+            }
+        }
+        return null;
+    }
+
+    static List<ValuesDelta> getNonEmptyValuesDeltas(RawContactDelta rawContactDelta,
             String mimeType, DataKind dataKind) {
         final List<ValuesDelta> result = new ArrayList<>();
         if (rawContactDelta == null) {
@@ -385,28 +502,14 @@
         return result;
     }
 
-    private static boolean hasNonEmptyPrimaryValuesDelta(RawContactDelta rawContactDelta,
-            String mimeType, DataKind dataKind) {
-        final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(mimeType);
-        if (valuesDelta == null) {
-            return false;
-        }
-        for (EditField editField : dataKind.fieldList) {
-            final String column = editField.column;
-            final String value = valuesDelta == null ? null : valuesDelta.getAsString(column);
-            log(Log.VERBOSE, "Field (primary) " + column + " empty=" + TextUtils.isEmpty(value) +
-                    " value=" + value);
-            if (!TextUtils.isEmpty(value)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private StructuredNameEditorView inflateStructuredNameEditorView(ViewGroup viewGroup,
-            AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
+            AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta,
+            NameEditorListener nameEditorListener) {
         final StructuredNameEditorView result = (StructuredNameEditorView) mLayoutInflater.inflate(
                 R.layout.structured_name_editor_view, viewGroup, /* attachToRoot =*/ false);
+        if (nameEditorListener != null) {
+            result.setEditorListener(nameEditorListener);
+        }
         result.setValues(
                 accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME),
                 valuesDelta,
@@ -429,19 +532,6 @@
         return result;
     }
 
-    private KindSectionView inflateNicknameEditorView(ViewGroup viewGroup, DataKind dataKind,
-            RawContactDelta rawContactDelta) {
-        final KindSectionView result = (KindSectionView) mLayoutInflater.inflate(
-                R.layout.item_kind_section, viewGroup, /* attachToRoot =*/ false);
-        result.setState(
-                dataKind,
-                rawContactDelta,
-                /* readOnly =*/ false,
-                /* showOneEmptyEditor =*/ false,
-                mViewIdGenerator);
-        return result;
-    }
-
     private KindSectionView inflateKindSectionView(ViewGroup viewGroup, DataKind dataKind,
             RawContactDelta rawContactDelta) {
         final KindSectionView result = (KindSectionView) mLayoutInflater.inflate(