Merge "Hide extra empty kind editor on compact contact editor"
diff --git a/res/layout/compact_contact_editor_fragment.xml b/res/layout/compact_contact_editor_fragment.xml
index ae3eb59..a61b290 100644
--- a/res/layout/compact_contact_editor_fragment.xml
+++ b/res/layout/compact_contact_editor_fragment.xml
@@ -32,8 +32,8 @@
         <!-- TODO: remove hard coded dimensions when we have a split screen layout in landscape -->
         <com.android.contacts.editor.CompactHeaderView
                 android:id="@+id/header"
-                android:layout_width="@dimen/detail_contact_photo_expanded_size"
-                android:layout_height="@dimen/detail_contact_photo_expanded_size"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
                 android:layout_gravity="center_horizontal"
                 android:orientation="vertical">
 
@@ -96,12 +96,11 @@
             <TextView
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:paddingEnd="@dimen/expanding_entry_card_item_image_spacing"
+                    android:paddingStart="@dimen/expanding_entry_card_item_image_spacing"
                     android:gravity="center_vertical"
                     android:paddingBottom="@dimen/expanding_entry_card_button_padding_vertical"
                     android:paddingTop="@dimen/expanding_entry_card_button_padding_vertical"
                     android:text="@string/compact_editor_more_fields"
-                    android:textAlignment="textEnd"
                     android:textColor="@color/expanding_entry_card_button_text_color"
                     android:textSize="@dimen/expanding_entry_card_title_text_size" />
 
diff --git a/src/com/android/contacts/editor/CompactHeaderView.java b/src/com/android/contacts/editor/CompactHeaderView.java
index f1b37cf..d150902 100644
--- a/src/com/android/contacts/editor/CompactHeaderView.java
+++ b/src/com/android/contacts/editor/CompactHeaderView.java
@@ -26,6 +26,7 @@
 import com.android.contacts.common.model.dataitem.DataKind;
 import com.android.contacts.editor.CompactContactEditorFragment.PhotoHandler;
 import com.android.contacts.util.ContactPhotoUtils;
+import com.android.contacts.util.SchedulingUtils;
 
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -36,7 +37,9 @@
 import android.provider.ContactsContract.DisplayPhoto;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -50,6 +53,9 @@
     private ContactPhotoManager mContactPhotoManager;
     private PhotoHandler mPhotoHandler;
 
+    private final float mLandscapePhotoRatio;
+    private final boolean mIsTwoPanel;
+
     private ValuesDelta mValuesDelta;
     private boolean mReadOnly;
     private boolean mIsPhotoSet;
@@ -57,11 +63,17 @@
     private ImageView mPhotoImageView;
 
     public CompactHeaderView(Context context) {
-        super(context);
+        this(context, null);
     }
 
     public CompactHeaderView(Context context, AttributeSet attrs) {
         super(context, attrs);
+
+        final TypedValue landscapePhotoRatio = new TypedValue();
+        getResources().getValue(R.dimen.quickcontact_landscape_photo_ratio, landscapePhotoRatio,
+                /* resolveRefs =*/ true);
+        mLandscapePhotoRatio = landscapePhotoRatio.getFloat();
+        mIsTwoPanel = getResources().getBoolean(R.bool.quickcontact_two_panel);
     }
 
     @Override
@@ -82,31 +94,46 @@
 
         if (valuesDelta == null) {
             setDefaultPhoto();
-            return;
-        }
-        final byte[] bytes = valuesDelta.getAsByteArray(Photo.PHOTO);
-        if (bytes == null) {
-            setDefaultPhoto();
-            return;
-        }
-        final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, /* offset =*/ 0, bytes.length);
-        mPhotoImageView.setImageBitmap(bitmap);
-        mIsPhotoSet = true;
-        mValuesDelta.setFromTemplate(false);
+        } else {
+            final byte[] bytes = valuesDelta.getAsByteArray(Photo.PHOTO);
+            if (bytes == null) {
+                setDefaultPhoto();
+            } else {
+                final Bitmap bitmap = BitmapFactory.decodeByteArray(
+                        bytes, /* offset =*/ 0, bytes.length);
+                mPhotoImageView.setImageBitmap(bitmap);
+                mIsPhotoSet = true;
+                mValuesDelta.setFromTemplate(false);
 
-        // Check if we can update to the full size photo immediately
-        if (valuesDelta.getAfter() == null || valuesDelta.getAfter().get(Photo.PHOTO) == null) {
-            // If the user hasn't updated the PHOTO value, then PHOTO_FILE_ID may contain
-            // a reference to a larger version of PHOTO that we can bind to the UI.
-            // Otherwise, we need to wait for a call to #setFullSizedPhoto() to update
-            // our full sized image.
-            final Integer fileId = valuesDelta.getAsInteger(Photo.PHOTO_FILE_ID);
-            if (fileId != null) {
-                final Uri photoUri = DisplayPhoto.CONTENT_URI.buildUpon()
-                        .appendPath(fileId.toString()).build();
-                setFullSizedPhoto(photoUri);
+                // Check if we can update to the full size photo immediately
+                if (valuesDelta.getAfter() == null
+                        || valuesDelta.getAfter().get(Photo.PHOTO) == null) {
+                    // If the user hasn't updated the PHOTO value, then PHOTO_FILE_ID may contain
+                    // a reference to a larger version of PHOTO that we can bind to the UI.
+                    // Otherwise, we need to wait for a call to #setFullSizedPhoto() to update
+                    // our full sized image.
+                    final Integer fileId = valuesDelta.getAsInteger(Photo.PHOTO_FILE_ID);
+                    if (fileId != null) {
+                        final Uri photoUri = DisplayPhoto.CONTENT_URI.buildUpon()
+                                .appendPath(fileId.toString()).build();
+                        setFullSizedPhoto(photoUri);
+                    }
+                }
             }
         }
+
+        // Make the photo a square
+        SchedulingUtils.doOnPreDraw(this, /* drawNextFrame =*/ false, new Runnable() {
+            @Override
+            public void run() {
+                final int photoHeight = mIsTwoPanel
+                        ? (int) (getWidth() * mLandscapePhotoRatio) : getWidth();
+                final ViewGroup.LayoutParams layoutParams = getLayoutParams();
+                layoutParams.height = photoHeight;
+                layoutParams.width = photoHeight;
+                setLayoutParams(layoutParams);
+            }
+        });
     }
 
     /**
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index 72cf650..7506f5a 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -199,8 +199,8 @@
                 /* valuesDelta =*/ null, ViewIdGenerator.NO_VIEW_INDEX));
 
         addHeaderView(rawContactDeltas, viewIdGenerator);
+        addStructuredNameView(rawContactDeltas);
         addEditorViews(rawContactDeltas);
-        removeExtraEmptyTextFields(mNames);
         removeExtraEmptyTextFields(mPhoneNumbers);
         removeExtraEmptyTextFields(mEmails);
     }
@@ -219,11 +219,10 @@
 
             final DataKind dataKind = accountType.getKindForMimetype(Photo.CONTENT_ITEM_TYPE);
             if (dataKind != null) {
-                final String mimeType = dataKind.mimeType;
-                if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                if (Photo.CONTENT_ITEM_TYPE.equals(dataKind.mimeType)) {
                     mPhotoRawContactId = rawContactDelta.getRawContactId();
                     final ValuesDelta valuesDelta = rawContactDelta.getSuperPrimaryEntry(
-                            mimeType, /* forceSelection =*/ true);
+                            dataKind.mimeType, /* forceSelection =*/ true);
                     mHeader.setValues(dataKind, valuesDelta, rawContactDelta,
                             /* readOnly =*/ !dataKind.editable, viewIdGenerator);
                     return;
@@ -232,6 +231,30 @@
         }
     }
 
+    private void addStructuredNameView(RawContactDeltaList rawContactDeltas) {
+        for (RawContactDelta rawContactDelta : rawContactDeltas) {
+            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);
+
+            final DataKind dataKind = accountType.getKindForMimetype(
+                    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;
+                }
+            }
+        }
+    }
+
     private void addEditorViews(RawContactDeltaList rawContactDeltas) {
         for (RawContactDelta rawContactDelta : rawContactDeltas) {
             if (!rawContactDelta.isVisible()) {
@@ -239,10 +262,6 @@
             }
             final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
 
-            // Make sure we have a structured name
-            RawContactModifier.ensureKindExists(
-                    rawContactDelta, accountType, StructuredName.CONTENT_ITEM_TYPE);
-
             for (DataKind dataKind : accountType.getSortedDataKinds()) {
                 if (!dataKind.editable) {
                     continue;
@@ -250,15 +269,10 @@
                 final String mimeType = dataKind.mimeType;
                 log(Log.VERBOSE, mimeType + " " + dataKind.fieldList.size() + " field(s)");
                 if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)
+                        || StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)
                         || GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
-                    // Photos are handled separately and group membership is not supported
+                    // Photos and name are handled separately; group membership is not supported
                     continue;
-                } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
-                    final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(mimeType);
-                    if (valuesDelta != null) {
-                        mNames.addView(inflateStructuredNameEditorView(
-                                mNames, accountType, valuesDelta, rawContactDelta));
-                    }
                 } else if (DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
                     // Use the StructuredName mime type to get values
                     if (hasNonEmptyPrimaryValuesDelta(
@@ -414,6 +428,7 @@
                 dataKind,
                 rawContactDelta,
                 /* readOnly =*/ false,
+                /* showOneEmptyEditor =*/ false,
                 mViewIdGenerator);
         return result;
     }
@@ -426,6 +441,7 @@
                 dataKind,
                 rawContactDelta,
                 /* readOnly =*/ false,
+                /* showOneEmptyEditor =*/ false,
                 mViewIdGenerator);
         return result;
     }
diff --git a/src/com/android/contacts/editor/KindSectionView.java b/src/com/android/contacts/editor/KindSectionView.java
index 5a5a51d..081efaa 100644
--- a/src/com/android/contacts/editor/KindSectionView.java
+++ b/src/com/android/contacts/editor/KindSectionView.java
@@ -63,6 +63,7 @@
     private DataKind mKind;
     private RawContactDelta mState;
     private boolean mReadOnly;
+    private boolean mShowOneEmptyEditor;
 
     private ViewIdGenerator mViewIdGenerator;
 
@@ -126,10 +127,16 @@
         }
     }
 
-    public void setState(DataKind kind, RawContactDelta state, boolean readOnly, ViewIdGenerator vig) {
+    /**
+     * @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 setState(DataKind kind, RawContactDelta state, boolean readOnly,
+            boolean showOneEmptyEditor, ViewIdGenerator vig) {
         mKind = kind;
         mState = state;
         mReadOnly = readOnly;
+        mShowOneEmptyEditor = showOneEmptyEditor;
         mViewIdGenerator = vig;
 
         setId(mViewIdGenerator.getId(state, kind, null, ViewIdGenerator.NO_VIEW_INDEX));
@@ -250,7 +257,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 || !hasNonEmptyEditor()) {
             final ValuesDelta values = RawContactModifier.insertChild(mState, mKind);
             final View newField = createEditorView(values);
             if (shouldAnimate) {
@@ -261,6 +268,19 @@
     }
 
     /**
+     * Whether there is at least one non-empty editor.
+     */
+    private boolean hasNonEmptyEditor() {
+        for (int i = 0; i < mEditors.getChildCount(); i++) {
+            View view = mEditors.getChildAt(i);
+            if (!((Editor) view).isEmpty()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Whether this section has any empty editors.
      */
     public boolean hasEmptyEditor() {
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index 06b4d62..ee61857 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -302,7 +302,8 @@
                 final KindSectionView section = (KindSectionView)mInflater.inflate(
                         R.layout.item_kind_section, mFields, false);
                 section.setEnabled(isEnabled());
-                section.setState(kind, state, false, vig);
+                section.setState(kind, state, /* readOnly =*/ false,
+                        /* showOneEmptyEditor =*/ true, vig);
                 mFields.addView(section);
             }
         }