Fix showing all phone nums and emails for joined contacts

We must delete the entire KindSectionView for emails and
phone numbers for all but the last raw contact that is being
edited.

Also, icons must be updated whenever an editor housed in
a kindview is deleted since we only want to show the icon
once for all the kindviews added to the compact layout
for all the raw contacts in the delta list.

Bug 22203548

Change-Id: If12c4fc10a9c9c09cbcfb86c5bf1472d89f6b890
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index e2ecbd6..2ec80e6 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -298,8 +298,8 @@
         addPhotoView(rawContactDeltas, viewIdGenerator, photoId, readOnlyDisplayName);
         addStructuredNameView(rawContactDeltas, nameId, readOnlyDisplayName);
         addEditorViews(rawContactDeltas);
-        removeExtraEmptyTextFields(mPhoneNumbers);
-        removeExtraEmptyTextFields(mEmails);
+        updateKindEditorEmptyFieldsAndIcons(mPhoneNumbers);
+        updateKindEditorEmptyFieldsAndIcons(mEmails);
     }
 
     private void addAccountInfo(RawContactDeltaList rawContactDeltas, boolean hasNewContact,
@@ -657,10 +657,25 @@
                                 rawContactDelta));
                     }
                 } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
-                    mPhoneNumbers.addView(inflateKindSectionView(mPhoneNumbers, dataKind,
-                            rawContactDelta));
+                    final KindSectionView kindSectionView =
+                            inflateKindSectionView(mPhoneNumbers, dataKind, rawContactDelta);
+                    kindSectionView.setListener(new KindSectionView.Listener() {
+                        @Override
+                        public void onDeleteRequested() {
+                            updateKindEditorEmptyFieldsAndIcons(mPhoneNumbers);
+                        }
+                    });
+                    mPhoneNumbers.addView(kindSectionView);
                 } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
-                    mEmails.addView(inflateKindSectionView(mEmails, dataKind, rawContactDelta));
+                    final KindSectionView kindSectionView =
+                            inflateKindSectionView(mEmails, dataKind, rawContactDelta);
+                    kindSectionView.setListener(new KindSectionView.Listener() {
+                        @Override
+                        public void onDeleteRequested() {
+                            updateKindEditorEmptyFieldsAndIcons(mEmails);
+                        }
+                    });
+                    mEmails.addView(kindSectionView);
                 } else if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
                     mOther.addView(inflateKindSectionView(mOther, dataKind, rawContactDelta));
                 }
@@ -668,47 +683,39 @@
         }
     }
 
-    // TODO: avoid inflating extra views and deleting them
-    private void removeExtraEmptyTextFields(ViewGroup viewGroup) {
-        // If there is one (or less) editors, leave it whether it is empty or not
-        if (viewGroup.getChildCount() <= 1) {
-            return;
-        }
-        // Determine if there are any non-empty editors
-        boolean hasAtLeastOneNonEmptyEditorView = false;
-        for (int i = 0; i < viewGroup.getChildCount(); i++) {
-            if (!isEmptyEditorView(viewGroup.getChildAt(i))) {
-                hasAtLeastOneNonEmptyEditorView = true;
-                break;
-            }
-        }
-        if (hasAtLeastOneNonEmptyEditorView) {
-            // There is at least one non-empty editor, remove all the empty ones
-            for (int i = 0; i < viewGroup.getChildCount(); i++) {
-                if (isEmptyEditorView(viewGroup.getChildAt(i))) {
-                    viewGroup.getChildAt(i).setVisibility(View.GONE);
+    private void updateKindEditorEmptyFieldsAndIcons(ViewGroup viewGroup) {
+        if (viewGroup.getChildCount() > 0) {
+            // Only the last editor should show an empty editor
+            final KindSectionView lastKindSectionView = (KindSectionView) viewGroup.getChildAt(
+                    viewGroup.getChildCount() - 1);
+            lastKindSectionView.setShowOneEmptyEditor(true);
+            lastKindSectionView.updateEmptyEditors(/* shouldAnimate =*/ false);
+
+            // For all the other editors, if there is nothing to show, hide the section entirely
+            for (int i = 0; i < viewGroup.getChildCount() - 1; i++) {
+                final KindSectionView kindSectionView = (KindSectionView) viewGroup.getChildAt(i);
+                if (kindSectionView.getEditorCount() == 0) {
+                    kindSectionView.setVisibility(View.GONE);
                 }
             }
-        } else {
-            // There is no non-empty editor, keep the first empty view and remove the rest
-            for (int i = 1; i < viewGroup.getChildCount(); i++) {
-                viewGroup.getChildAt(i).setVisibility(View.GONE);
+        }
+
+        // Show the icon on the first visible kind editor
+        boolean iconVisible = false;
+        for (int i = 0; i < viewGroup.getChildCount(); i++) {
+            final KindSectionView kindSectionView = (KindSectionView) viewGroup.getChildAt(i);
+            if (kindSectionView.getVisibility() != View.VISIBLE) {
+                continue;
+            }
+            if (!iconVisible) {
+                kindSectionView.setIconVisibility(true);
+                iconVisible = true;
+            } else {
+                kindSectionView.setIconVisibility(false);
             }
         }
     }
 
-    private static boolean isEmptyEditorView(View view) {
-        if (view instanceof TextFieldsEditorView) {
-            final TextFieldsEditorView textFieldsEditorView = (TextFieldsEditorView) view;
-            return textFieldsEditorView.isEmpty();
-        }
-        if (view instanceof KindSectionView) {
-            final KindSectionView kindSectionView = (KindSectionView) view;
-            return kindSectionView.hasEmptyEditor();
-        }
-        return false;
-    }
-
     private static boolean hasNonEmptyValuesDelta(RawContactDelta rawContactDelta,
             String mimeType, DataKind dataKind) {
         return !getNonEmptyValuesDeltas(rawContactDelta, mimeType, dataKind).isEmpty();
diff --git a/src/com/android/contacts/editor/KindSectionView.java b/src/com/android/contacts/editor/KindSectionView.java
index a0df1c3..1bd0a23 100644
--- a/src/com/android/contacts/editor/KindSectionView.java
+++ b/src/com/android/contacts/editor/KindSectionView.java
@@ -40,11 +40,11 @@
 import android.widget.LinearLayout;
 
 import com.android.contacts.R;
-import com.android.contacts.editor.Editor.EditorListener;
-import com.android.contacts.common.model.RawContactModifier;
 import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactModifier;
 import com.android.contacts.common.model.ValuesDelta;
 import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.editor.Editor.EditorListener;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -56,17 +56,28 @@
  */
 public class KindSectionView extends LinearLayout implements EditorListener {
 
+    public interface Listener {
+
+        /**
+         * Invoked when any editor that is displayed in this section view is deleted by the user.
+         */
+        public void onDeleteRequested();
+    }
+
     private ViewGroup mEditors;
     private ImageView mIcon;
 
     private DataKind mKind;
     private RawContactDelta mState;
     private boolean mReadOnly;
+    private boolean mShowOneEmptyEditor;
 
     private ViewIdGenerator mViewIdGenerator;
 
     private LayoutInflater mInflater;
 
+    private Listener mListener;
+
     public KindSectionView(Context context) {
         this(context, null);
     }
@@ -106,14 +117,20 @@
 
     @Override
     public void onDeleteRequested(Editor editor) {
-        // If there is only 1 editor in the section, then don't allow the user to delete it.
-        // Just clear the fields in the editor.
-        if (getEditorCount() == 1) {
+        // If there is only 1 editor in the section, or it is the last editor in a list of editors,
+        // then don't allow the user to delete it.  Just clear the fields in the editor.
+        if (getEditorCount() == 1 && mShowOneEmptyEditor) {
             editor.clearAllFields();
         } else {
             // Otherwise it's okay to delete this {@link Editor}
+            if (!mShowOneEmptyEditor) {
+                setVisibility(View.GONE);
+            }
             editor.deleteEditor();
         }
+        if (mListener != null) {
+            mListener.onDeleteRequested();
+        }
     }
 
     @Override
@@ -125,6 +142,22 @@
         }
     }
 
+    /**
+     * @param showOneEmptyEditor If true, one empty input will always be displayed,
+     *         otherwise an empty input will only be displayed if there is no non-empty value.
+     */
+    public void setShowOneEmptyEditor(boolean showOneEmptyEditor) {
+        mShowOneEmptyEditor = showOneEmptyEditor;
+    }
+
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    public void setIconVisibility(boolean visible) {
+        mIcon.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+    }
+
     public void setState(DataKind kind, RawContactDelta state, boolean readOnly,
             ViewIdGenerator vig) {
         mKind = kind;
@@ -222,7 +255,7 @@
      * Updates the editors being displayed to the user removing extra empty
      * {@link Editor}s, so there is only max 1 empty {@link Editor} view at a time.
      */
-    private void updateEmptyEditors(boolean shouldAnimate) {
+    public void updateEmptyEditors(boolean shouldAnimate) {
 
         final List<View> emptyEditors = getEmptyEditors();
 
@@ -254,7 +287,7 @@
         } else if (emptyEditors.size() == 1) {
             // We have already reached the maximum number of empty editors. Lets not add any more.
             return;
-        } else {
+        } else if (mShowOneEmptyEditor) {
             final ValuesDelta values = RawContactModifier.insertChild(mState, mKind);
             final View newField = createEditorView(values);
             if (shouldAnimate) {
@@ -265,13 +298,6 @@
     }
 
     /**
-     * Whether this section has any empty editors.
-     */
-    public boolean hasEmptyEditor() {
-        return !getEmptyEditors().isEmpty();
-    }
-
-    /**
      * Returns a list of empty editor views in this section.
      */
     private List<View> getEmptyEditors() {
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index 6c55854..eeba401 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -287,6 +287,7 @@
                 if (kind.fieldList == null) continue;
                 final KindSectionView section = (KindSectionView)mInflater.inflate(
                         R.layout.item_kind_section, mFields, false);
+                section.setShowOneEmptyEditor(true);
                 section.setEnabled(isEnabled());
                 section.setState(kind, state, /* readOnly =*/ false, vig);
                 mFields.addView(section);