Merge "Moves section header in contacts list to the left side."
diff --git a/src/com/android/contacts/common/list/ContactEntryListAdapter.java b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
index 57b93b7..900cffc 100644
--- a/src/com/android/contacts/common/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
@@ -36,7 +36,6 @@
 import com.android.contacts.common.ContactPhotoManager;
 import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
 import com.android.contacts.common.R;
-import com.android.contacts.common.list.ContactListAdapter.ContactQuery;
 import com.android.contacts.common.util.SearchUtil;
 
 import java.util.HashSet;
@@ -101,13 +100,21 @@
     }
 
     @Override
+    protected ContactListItemView newView(
+            Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
+        final ContactListItemView view = new ContactListItemView(context, null);
+        view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
+        return view;
+    }
+
+    @Override
     protected View createPinnedSectionHeaderView(Context context, ViewGroup parent) {
         return new ContactListPinnedHeaderView(context, null);
     }
 
     @Override
     protected void setPinnedSectionTitle(View pinnedHeaderView, String title) {
-        ((ContactListPinnedHeaderView)pinnedHeaderView).setSectionHeader(title);
+        ((ContactListPinnedHeaderView) pinnedHeaderView).setSectionHeaderTitle(title);
     }
 
     protected void addPartitions() {
diff --git a/src/com/android/contacts/common/list/ContactListAdapter.java b/src/com/android/contacts/common/list/ContactListAdapter.java
index 739b30e..4bfbdcf 100644
--- a/src/com/android/contacts/common/list/ContactListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactListAdapter.java
@@ -194,9 +194,9 @@
     }
 
     @Override
-    protected View newView(Context context, int partition, Cursor cursor, int position,
-            ViewGroup parent) {
-        ContactListItemView view = new ContactListItemView(context, null);
+    protected ContactListItemView newView(
+            Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
+        ContactListItemView view = super.newView(context, partition, cursor, position, parent);
         view.setUnknownNameText(mUnknownNameText);
         view.setQuickContactEnabled(isQuickContactEnabled());
         view.setActivatedStateSupported(isSelectionVisible());
diff --git a/src/com/android/contacts/common/list/ContactListItemView.java b/src/com/android/contacts/common/list/ContactListItemView.java
index 84e74e5..8ae26fd 100644
--- a/src/com/android/contacts/common/list/ContactListItemView.java
+++ b/src/com/android/contacts/common/list/ContactListItemView.java
@@ -86,12 +86,8 @@
     private int mGapBetweenLabelAndData = 0;
     private int mPresenceIconMargin = 4;
     private int mPresenceIconSize = 16;
-    private int mHeaderTextColor = Color.BLACK;
-    private int mHeaderTextIndent = 0;
-    private int mHeaderTextSize = 12;
-    private int mHeaderUnderlineHeight = 1;
-    private int mHeaderUnderlineColor = 0;
     private int mTextIndent = 0;
+    private int mHeaderWidth;
     private Drawable mActivatedBackgroundDrawable;
 
     /**
@@ -148,10 +144,9 @@
     private PhotoPosition mPhotoPosition = getDefaultPhotoPosition(false /* normal/non opposite */);
 
     // Header layout data
-    private boolean mHeaderVisible;
-    private View mHeaderDivider;
-    private int mHeaderBackgroundHeight = 30;
+    private int mHeaderBackgroundHeight;
     private TextView mHeaderTextView;
+    private boolean mIsSectionHeaderEnabled;
 
     // The views inside the contact view
     private boolean mQuickContactEnabled = true;
@@ -256,20 +251,6 @@
                 R.styleable.ContactListItemView_list_item_presence_icon_size, mPresenceIconSize);
         mDefaultPhotoViewSize = a.getDimensionPixelOffset(
                 R.styleable.ContactListItemView_list_item_photo_size, mDefaultPhotoViewSize);
-        mHeaderTextIndent = a.getDimensionPixelOffset(
-                R.styleable.ContactListItemView_list_item_header_text_indent, mHeaderTextIndent);
-        mHeaderTextColor = a.getColor(
-                R.styleable.ContactListItemView_list_item_header_text_color, mHeaderTextColor);
-        mHeaderTextSize = a.getDimensionPixelSize(
-                R.styleable.ContactListItemView_list_item_header_text_size, mHeaderTextSize);
-        mHeaderBackgroundHeight = a.getDimensionPixelSize(
-                R.styleable.ContactListItemView_list_item_header_height, mHeaderBackgroundHeight);
-        mHeaderUnderlineHeight = a.getDimensionPixelSize(
-                R.styleable.ContactListItemView_list_item_header_underline_height,
-                mHeaderUnderlineHeight);
-        mHeaderUnderlineColor = a.getColor(
-                R.styleable.ContactListItemView_list_item_header_underline_color,
-                mHeaderUnderlineColor);
         mTextIndent = a.getDimensionPixelOffset(
                 R.styleable.ContactListItemView_list_item_text_indent, mTextIndent);
         mDataViewWidthWeight = a.getInteger(
@@ -296,6 +277,9 @@
         mSecondaryTextColor = a.getColorStateList(R.styleable.Theme_android_textColorSecondary);
         a.recycle();
 
+        mHeaderWidth =
+                getResources().getDimensionPixelSize(R.dimen.contact_list_section_header_width);
+
         if (mActivatedBackgroundDrawable != null) {
             mActivatedBackgroundDrawable.setCallback(this);
         }
@@ -443,16 +427,12 @@
         // Make sure height is at least the preferred height
         height = Math.max(height, preferredHeight);
 
-        // Add the height of the header if visible
-        if (mHeaderVisible) {
-            final int headerWidth = specWidth -
-                    getPaddingLeft() - getPaddingRight() - mHeaderTextIndent;
+        // Measure the header if it is visible.
+        if (mHeaderTextView != null && mHeaderTextView.getVisibility() == VISIBLE) {
             mHeaderTextView.measure(
-                    MeasureSpec.makeMeasureSpec(headerWidth, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(mHeaderBackgroundHeight, MeasureSpec.EXACTLY));
-            mHeaderBackgroundHeight = Math.max(mHeaderBackgroundHeight,
-                    mHeaderTextView.getMeasuredHeight());
-            height += (mHeaderBackgroundHeight + mHeaderUnderlineHeight);
+                    MeasureSpec.makeMeasureSpec(mHeaderWidth, MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+            mHeaderBackgroundHeight = Math.min(height, mHeaderTextView.getMeasuredHeight());
         }
 
         setMeasuredDimension(specWidth, height);
@@ -471,20 +451,23 @@
 
         final boolean isLayoutRtl = ViewUtil.isViewLayoutRtl(this);
 
-        // Put the header in the top of the contact view (Text + underline view)
-        if (mHeaderVisible) {
-            mHeaderTextView.layout(isLayoutRtl ? leftBound : leftBound + mHeaderTextIndent,
-                    0,
-                    isLayoutRtl ? rightBound - mHeaderTextIndent : rightBound,
-                    mHeaderBackgroundHeight);
-            mHeaderDivider.layout(leftBound,
-                    mHeaderBackgroundHeight,
-                    rightBound,
-                    mHeaderBackgroundHeight + mHeaderUnderlineHeight);
-            topBound += (mHeaderBackgroundHeight + mHeaderUnderlineHeight);
+        // Put the section header on the left side of the contact view.
+        if (mIsSectionHeaderEnabled) {
+            if (mHeaderTextView != null) {
+                mHeaderTextView.layout(
+                        isLayoutRtl ? rightBound - mHeaderWidth : leftBound,
+                        topBound,
+                        isLayoutRtl ? rightBound : leftBound + mHeaderWidth,
+                        mHeaderBackgroundHeight);
+            }
+            if (isLayoutRtl) {
+                rightBound -= mHeaderWidth;
+            } else {
+                leftBound += mHeaderWidth;
+            }
         }
 
-        mBoundsWithoutHeader.set(0, topBound, width, bottomBound);
+        mBoundsWithoutHeader.set(leftBound, topBound, width, bottomBound);
 
         if (mActivatedStateSupported && isActivated()) {
             mActivatedBackgroundDrawable.setBounds(mBoundsWithoutHeader);
@@ -663,10 +646,6 @@
         }
     }
 
-    protected void setDefaultPhotoViewSize(int pixels) {
-        mDefaultPhotoViewSize = pixels;
-    }
-
     protected int getDefaultPhotoViewSize() {
         return mDefaultPhotoViewSize;
     }
@@ -720,34 +699,22 @@
         if (!TextUtils.isEmpty(title)) {
             if (mHeaderTextView == null) {
                 mHeaderTextView = new TextView(getContext());
-                mHeaderTextView.setTextColor(mHeaderTextColor);
-                mHeaderTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mHeaderTextSize);
                 mHeaderTextView.setTextAppearance(getContext(), R.style.SectionHeaderStyle);
-                mHeaderTextView.setGravity(Gravity.CENTER_VERTICAL);
-                mHeaderTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
+                mHeaderTextView.setGravity(Gravity.CENTER);
                 addView(mHeaderTextView);
             }
-            if (mHeaderDivider == null) {
-                mHeaderDivider = new View(getContext());
-                mHeaderDivider.setBackgroundColor(mHeaderUnderlineColor);
-                addView(mHeaderDivider);
-            }
             setMarqueeText(mHeaderTextView, title);
             mHeaderTextView.setVisibility(View.VISIBLE);
-            mHeaderDivider.setVisibility(View.VISIBLE);
             mHeaderTextView.setAllCaps(true);
-            mHeaderVisible = true;
-        } else {
-            if (mHeaderTextView != null) {
-                mHeaderTextView.setVisibility(View.GONE);
-            }
-            if (mHeaderDivider != null) {
-                mHeaderDivider.setVisibility(View.GONE);
-            }
-            mHeaderVisible = false;
+        } else if (mHeaderTextView != null) {
+            mHeaderTextView.setVisibility(View.GONE);
         }
     }
 
+    public void setIsSectionHeaderEnabled(boolean isSectionHeaderEnabled) {
+        mIsSectionHeaderEnabled = isSectionHeaderEnabled;
+    }
+
     /**
      * Returns the quick contact badge, creating it if necessary.
      */
diff --git a/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java b/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
index 83892b4..6f6e551 100644
--- a/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
+++ b/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
@@ -19,146 +19,45 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Color;
-import android.graphics.Typeface;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.View;
-import android.view.ViewGroup;
+import android.widget.LinearLayout.LayoutParams;
 import android.widget.TextView;
 
 import com.android.contacts.common.R;
-import com.android.contacts.common.util.ViewUtil;
 
 /**
  * A custom view for the pinned section header shown at the top of the contact list.
  */
-public class ContactListPinnedHeaderView extends ViewGroup {
-
-    protected final Context mContext;
-
-    private final int mHeaderTextColor;
-    private final int mHeaderTextIndent;
-    private final int mHeaderTextSize;
-    private final int mHeaderUnderlineHeight;
-    private final int mHeaderUnderlineColor;
-    private final int mPaddingRight;
-    private final int mPaddingLeft;
-
-    private int mHeaderBackgroundHeight;
-    private TextView mHeaderTextView;
-    private TextView mCountTextView = null;
-    private View mHeaderDivider;
+public class ContactListPinnedHeaderView extends TextView {
 
     public ContactListPinnedHeaderView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mContext = context;
 
         TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ContactListItemView);
-
-        mHeaderTextIndent = a.getDimensionPixelOffset(
-                R.styleable.ContactListItemView_list_item_header_text_indent, 0);
-        mHeaderTextColor = a.getColor(
-                R.styleable.ContactListItemView_list_item_header_text_color, Color.BLACK);
-        mHeaderTextSize = a.getDimensionPixelSize(
-                R.styleable.ContactListItemView_list_item_header_text_size, 12);
-        mHeaderUnderlineHeight = a.getDimensionPixelSize(
-                R.styleable.ContactListItemView_list_item_header_underline_height, 1);
-        mHeaderUnderlineColor = a.getColor(
-                R.styleable.ContactListItemView_list_item_header_underline_color, 0);
-        mHeaderBackgroundHeight = a.getDimensionPixelSize(
-                R.styleable.ContactListItemView_list_item_header_height, 30);
-        mPaddingLeft = a.getDimensionPixelOffset(
-                R.styleable.ContactListItemView_list_item_padding_left, 0);
-        mPaddingRight = a.getDimensionPixelOffset(
-                R.styleable.ContactListItemView_list_item_padding_right, 0);
-
+        int backgroundColor = a.getColor(
+                R.styleable.ContactListItemView_list_item_background_color, Color.WHITE);
         a.recycle();
 
-        mHeaderTextView = new TextView(mContext);
-        mHeaderTextView.setTextColor(mHeaderTextColor);
-        mHeaderTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mHeaderTextSize);
-        mHeaderTextView.setGravity(Gravity.CENTER_VERTICAL);
-        mHeaderTextView.setTextAppearance(mContext, R.style.DirectoryHeaderStyle);
-        mHeaderTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
-        addView(mHeaderTextView);
-        mHeaderDivider = new View(mContext);
-        mHeaderDivider.setBackgroundColor(mHeaderUnderlineColor);
-        addView(mHeaderDivider);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
-        // We will match parent's width and wrap content vertically.
-        int width = resolveSize(0, widthMeasureSpec);
-
-        mHeaderTextView.measure(
-                MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
-                MeasureSpec.makeMeasureSpec(mHeaderBackgroundHeight, MeasureSpec.EXACTLY));
-        if (isViewMeasurable(mCountTextView)) {
-            mCountTextView.measure(
-                    MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
-                    MeasureSpec.makeMeasureSpec(mHeaderBackgroundHeight, MeasureSpec.EXACTLY));
-        }
-
-        setMeasuredDimension(width, mHeaderBackgroundHeight + mHeaderUnderlineHeight);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        int width = right - left;
-
-        final int leftHeaderTextView;
-        final int rightHeaderTextView;
-        final int topTextView = 0;
-        final int bottomTextView = mHeaderBackgroundHeight;
-
-
-        if (ViewUtil.isViewLayoutRtl(this)) {
-            rightHeaderTextView = width - mPaddingRight - mHeaderTextIndent;
-            leftHeaderTextView = rightHeaderTextView - mHeaderTextView.getMeasuredWidth();
-        } else {
-            leftHeaderTextView = mHeaderTextIndent + mPaddingLeft;
-            rightHeaderTextView = mHeaderTextView.getMeasuredWidth() + leftHeaderTextView;
-        }
-
-        // Take into account left and right padding when laying out the below views.
-        mHeaderTextView.layout(leftHeaderTextView,
-                topTextView,
-                rightHeaderTextView,
-                bottomTextView);
-
-        mHeaderDivider.layout(mPaddingLeft,
-                mHeaderBackgroundHeight,
-                width - mPaddingRight,
-                mHeaderBackgroundHeight + mHeaderUnderlineHeight);
+        setBackgroundColor(backgroundColor);
+        setTextAppearance(getContext(), R.style.DirectoryHeaderStyle);
+        setLayoutParams(new LayoutParams(
+                getResources().getDimensionPixelSize(R.dimen.contact_list_section_header_width),
+                LayoutParams.WRAP_CONTENT));
+        setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER);
     }
 
     /**
      * Sets section header or makes it invisible if the title is null.
      */
-    public void setSectionHeader(String title) {
+    public void setSectionHeaderTitle(String title) {
         if (!TextUtils.isEmpty(title)) {
-            mHeaderTextView.setText(title);
-            mHeaderTextView.setVisibility(View.VISIBLE);
-            mHeaderDivider.setVisibility(View.VISIBLE);
+            setText(title);
+            setVisibility(View.VISIBLE);
         } else {
-            mHeaderTextView.setVisibility(View.GONE);
-            mHeaderDivider.setVisibility(View.GONE);
+            setVisibility(View.GONE);
         }
     }
-
-    @Override
-    public void requestLayout() {
-        // We will assume that once measured this will not need to resize
-        // itself, so there is no need to pass the layout request to the parent
-        // view (ListView).
-        forceLayout();
-    }
-
-    private boolean isViewMeasurable(View view) {
-        return (view != null && view.getVisibility() == View.VISIBLE);
-    }
 }
diff --git a/src/com/android/contacts/common/list/IndexerListAdapter.java b/src/com/android/contacts/common/list/IndexerListAdapter.java
index 60d7f3c..91d02f0 100644
--- a/src/com/android/contacts/common/list/IndexerListAdapter.java
+++ b/src/com/android/contacts/common/list/IndexerListAdapter.java
@@ -174,6 +174,11 @@
             if (section == -1) {
                 listView.setHeaderInvisible(index, false);
             } else {
+                View topChild = listView.getChildAt(listPosition);
+                if (topChild != null) {
+                    // Match the pinned header's height to the height of the list item.
+                    mHeader.setMinimumHeight(topChild.getMeasuredHeight());
+                }
                 setPinnedSectionTitle(mHeader, (String)mIndexer.getSections()[section]);
 
                 // Compute the item position where the current partition begins
diff --git a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
index 953c409..861f739 100644
--- a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
+++ b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
@@ -276,9 +276,9 @@
     }
 
     @Override
-    protected View newView(Context context, int partition, Cursor cursor, int position,
-            ViewGroup parent) {
-        final ContactListItemView view = new ContactListItemView(context, null);
+    protected ContactListItemView newView(
+            Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
+        ContactListItemView view = super.newView(context, partition, cursor, position, parent);
         view.setUnknownNameText(mUnknownNameText);
         view.setQuickContactEnabled(isQuickContactEnabled());
         view.setPhotoPosition(mPhotoPosition);
diff --git a/src/com/android/contacts/common/list/PinnedHeaderListView.java b/src/com/android/contacts/common/list/PinnedHeaderListView.java
index 8d34981..8c05b26 100644
--- a/src/com/android/contacts/common/list/PinnedHeaderListView.java
+++ b/src/com/android/contacts/common/list/PinnedHeaderListView.java
@@ -99,7 +99,6 @@
     private int mSize;
     private PinnedHeader[] mHeaders;
     private RectF mBounds = new RectF();
-    private Rect mClipRect = new Rect();
     private OnScrollListener mOnScrollListener;
     private OnItemSelectedListener mOnItemSelectedListener;
     private int mScrollState;
@@ -134,10 +133,6 @@
         mHeaderWidth = r - l - mHeaderPaddingStart - getPaddingEnd();
     }
 
-    public void setPinnedHeaderAnimationDuration(int duration) {
-        mAnimationDuration = duration;
-    }
-
     @Override
     public void setAdapter(ListAdapter adapter) {
         mAdapter = (PinnedHeaderAdapter)adapter;
@@ -362,9 +357,18 @@
     private void ensurePinnedHeaderLayout(int viewIndex) {
         View view = mHeaders[viewIndex].view;
         if (view.isLayoutRequested()) {
-            int widthSpec = View.MeasureSpec.makeMeasureSpec(mHeaderWidth, View.MeasureSpec.EXACTLY);
-            int heightSpec;
             ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
+            int widthSpec;
+            int heightSpec;
+
+            if (layoutParams != null && layoutParams.width > 0) {
+                widthSpec = View.MeasureSpec
+                        .makeMeasureSpec(layoutParams.width, View.MeasureSpec.EXACTLY);
+            } else {
+                widthSpec = View.MeasureSpec
+                        .makeMeasureSpec(mHeaderWidth, View.MeasureSpec.EXACTLY);
+            }
+
             if (layoutParams != null && layoutParams.height > 0) {
                 heightSpec = View.MeasureSpec
                         .makeMeasureSpec(layoutParams.height, View.MeasureSpec.EXACTLY);
@@ -374,7 +378,7 @@
             view.measure(widthSpec, heightSpec);
             int height = view.getMeasuredHeight();
             mHeaders[viewIndex].height = height;
-            view.layout(0, 0, mHeaderWidth, height);
+            view.layout(0, 0, view.getMeasuredWidth(), height);
         }
     }
 
@@ -423,7 +427,7 @@
                 // side.
                 final int padding = getPaddingLeft();
                 if (header.visible && header.y <= y && header.y + header.height > y &&
-                        x >= padding && padding + mHeaderWidth >= x) {
+                        x >= padding && padding + header.view.getWidth() >= x) {
                     mHeaderTouched = true;
                     if (mScrollToSectionOnHeaderTouch &&
                             ev.getAction() == MotionEvent.ACTION_DOWN) {
@@ -483,6 +487,7 @@
         long currentTime = mAnimating ? System.currentTimeMillis() : 0;
 
         int top = 0;
+        int right = 0;
         int bottom = getBottom();
         boolean hasVisibleHeaders = false;
         for (int i = 0; i < mSize; i++) {
@@ -502,8 +507,6 @@
 
         if (hasVisibleHeaders) {
             canvas.save();
-            mClipRect.set(0, top, getWidth(), bottom);
-            canvas.clipRect(mClipRect);
         }
 
         super.dispatchDraw(canvas);
@@ -545,11 +548,12 @@
         if (header.visible) {
             View view = header.view;
             int saveCount = canvas.save();
-            canvas.translate(ViewUtil.isViewLayoutRtl(this) ?
-                    getWidth() - mHeaderPaddingStart - mHeaderWidth : mHeaderPaddingStart,
-                    header.y);
+            int translateX = ViewUtil.isViewLayoutRtl(this) ?
+                    getWidth() - mHeaderPaddingStart - header.view.getWidth() :
+                    mHeaderPaddingStart;
+            canvas.translate(translateX, header.y);
             if (header.state == FADING) {
-                mBounds.set(0, 0, mHeaderWidth, view.getHeight());
+                mBounds.set(0, 0, header.view.getWidth(), view.getHeight());
                 canvas.saveLayerAlpha(mBounds, header.alpha, Canvas.ALL_SAVE_FLAG);
             }
             view.draw(canvas);