Merge "Remove "TODO use syncadapter package instead""
diff --git a/src/com/android/contacts/common/list/ContactEntryListAdapter.java b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
index 92048b8..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,29 +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);
-    }
-
-    @Override
-    protected void setPinnedHeaderContactsCount(View header) {
-        // Update the header with the contacts count only if a profile header exists
-        // otherwise, the contacts count are shown in the empty profile header view
-        if (mProfileExists) {
-            ((ContactListPinnedHeaderView)header).setCountView(mContactsCount);
-        } else {
-            clearPinnedHeaderContactsCount(header);
-        }
-    }
-
-    @Override
-    protected void clearPinnedHeaderContactsCount(View header) {
-        ((ContactListPinnedHeaderView)header).setCountView(null);
+        ((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 0750459..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());
@@ -210,19 +210,9 @@
             Cursor cursor) {
         if (isSectionHeaderDisplayEnabled()) {
             Placement placement = getItemPlacementInSection(position);
-
-            // First position, set the contacts number string
-            if (position == 0 && cursor.getInt(ContactQuery.CONTACT_IS_USER_PROFILE) == 1) {
-                view.setCountView(getContactsCount());
-            } else {
-                view.setCountView(null);
-            }
             view.setSectionHeader(placement.sectionHeader);
-            view.setDividerVisible(!placement.lastInSection);
         } else {
             view.setSectionHeader(null);
-            view.setDividerVisible(true);
-            view.setCountView(null);
         }
     }
 
diff --git a/src/com/android/contacts/common/list/ContactListItemView.java b/src/com/android/contacts/common/list/ContactListItemView.java
index b6aa800..462889c 100644
--- a/src/com/android/contacts/common/list/ContactListItemView.java
+++ b/src/com/android/contacts/common/list/ContactListItemView.java
@@ -22,20 +22,17 @@
 import android.database.CharArrayBuffer;
 import android.database.Cursor;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
-import android.telephony.PhoneNumberUtils;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
 import android.text.TextUtils.TruncateAt;
 import android.util.AttributeSet;
-import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
@@ -86,14 +83,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 mCountViewTextSize = 12;
-    private int mContactsCountTextColor = Color.BLACK;
     private int mTextIndent = 0;
+    private int mHeaderWidth;
     private Drawable mActivatedBackgroundDrawable;
 
     /**
@@ -105,15 +96,6 @@
      */
     private int mDataViewWidthWeight = 5;
 
-    // Will be used with adjustListItemSelectionBounds().
-    private int mSelectionBoundsMarginLeft;
-    private int mSelectionBoundsMarginRight;
-
-    // Horizontal divider between contact views.
-    private boolean mHorizontalDividerVisible = true;
-    private Drawable mHorizontalDividerDrawable;
-    private int mHorizontalDividerHeight;
-
     protected static class HighlightSequence {
         private final int start;
         private final int end;
@@ -145,20 +127,19 @@
         final int layoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
         switch (layoutDirection) {
             case View.LAYOUT_DIRECTION_RTL:
-                return (opposite ? PhotoPosition.RIGHT : PhotoPosition.LEFT);
+                return (opposite ? PhotoPosition.LEFT : PhotoPosition.RIGHT);
             case View.LAYOUT_DIRECTION_LTR:
             default:
-                return (opposite ? PhotoPosition.LEFT : PhotoPosition.RIGHT);
+                return (opposite ? PhotoPosition.RIGHT : PhotoPosition.LEFT);
         }
     }
 
     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;
@@ -170,7 +151,6 @@
     private TextView mDataView;
     private TextView mSnippetView;
     private TextView mStatusView;
-    private TextView mCountView;
     private ImageView mPresenceIcon;
 
     private ColorStateList mSecondaryTextColor;
@@ -250,8 +230,6 @@
                 R.styleable.ContactListItemView_list_item_height, mPreferredHeight);
         mActivatedBackgroundDrawable = a.getDrawable(
                 R.styleable.ContactListItemView_activated_background);
-        mHorizontalDividerDrawable = a.getDrawable(
-                R.styleable.ContactListItemView_list_item_divider);
 
         mGapBetweenImageAndText = a.getDimensionPixelOffset(
                 R.styleable.ContactListItemView_list_item_gap_between_image_and_text,
@@ -266,28 +244,8 @@
                 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);
-        mCountViewTextSize = a.getDimensionPixelSize(
-                R.styleable.ContactListItemView_list_item_contacts_count_text_size,
-                mCountViewTextSize);
-        mContactsCountTextColor = a.getColor(
-                R.styleable.ContactListItemView_list_item_contacts_count_text_color,
-                mContactsCountTextColor);
         mDataViewWidthWeight = a.getInteger(
                 R.styleable.ContactListItemView_list_item_data_width_weight, mDataViewWidthWeight);
         mLabelViewWidthWeight = a.getInteger(
@@ -312,7 +270,8 @@
         mSecondaryTextColor = a.getColorStateList(R.styleable.Theme_android_textColorSecondary);
         a.recycle();
 
-        mHorizontalDividerHeight = mHorizontalDividerDrawable.getIntrinsicHeight();
+        mHeaderWidth =
+                getResources().getDimensionPixelSize(R.dimen.contact_list_section_header_width);
 
         if (mActivatedBackgroundDrawable != null) {
             mActivatedBackgroundDrawable.setCallback(this);
@@ -335,12 +294,7 @@
         // We will match parent's width and wrap content vertically, but make sure
         // height is no less than listPreferredItemHeight.
         final int specWidth = resolveSize(0, widthMeasureSpec);
-        final int preferredHeight;
-        if (mHorizontalDividerVisible) {
-            preferredHeight = mPreferredHeight + mHorizontalDividerHeight;
-        } else {
-            preferredHeight = mPreferredHeight;
-        }
+        final int preferredHeight = mPreferredHeight;
 
         mNameTextViewHeight = 0;
         mPhoneticNameTextViewHeight = 0;
@@ -353,7 +307,7 @@
         ensurePhotoViewSize();
 
         // Width each TextView is able to use.
-        final int effectiveWidth;
+        int effectiveWidth;
         // All the other Views will honor the photo, so available width for them may be shrunk.
         if (mPhotoViewWidth > 0 || mKeepHorizontalPaddingForPhotoView) {
             effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight()
@@ -362,11 +316,15 @@
             effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight();
         }
 
+        if (mIsSectionHeaderEnabled) {
+            effectiveWidth -= mHeaderWidth + mGapBetweenImageAndText;
+        }
+
         // Go over all visible text views and measure actual width of each of them.
         // Also calculate their heights to get the total height for this entire view.
 
         if (isVisible(mNameTextView)) {
-            // Caculate width for name text - this parallels similar measurement in onLayout.
+            // Claculate width for name text - this parallels similar measurement in onLayout.
             int nameTextWidth = effectiveWidth;
             if (mPhotoPosition != PhotoPosition.LEFT) {
                 nameTextWidth -= mTextIndent;
@@ -463,29 +421,15 @@
         // Make sure the height is at least as high as the photo
         height = Math.max(height, mPhotoViewHeight + getPaddingBottom() + getPaddingTop());
 
-        // Add horizontal divider height
-        if (mHorizontalDividerVisible) {
-            height += mHorizontalDividerHeight;
-        }
-
         // 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));
-            if (mCountView != null) {
-                mCountView.measure(
-                        MeasureSpec.makeMeasureSpec(headerWidth, MeasureSpec.AT_MOST),
-                        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);
@@ -504,36 +448,31 @@
 
         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);
-            if (mCountView != null) {
-                mCountView.layout(rightBound - mCountView.getMeasuredWidth(),
-                        0,
-                        rightBound,
+        // 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);
             }
-            mHeaderDivider.layout(leftBound,
-                    mHeaderBackgroundHeight,
-                    rightBound,
-                    mHeaderBackgroundHeight + mHeaderUnderlineHeight);
-            topBound += (mHeaderBackgroundHeight + mHeaderUnderlineHeight);
+            if (isLayoutRtl) {
+                rightBound -= mHeaderWidth;
+            } else {
+                leftBound += mHeaderWidth;
+            }
         }
 
-        // Put horizontal divider at the bottom
-        if (mHorizontalDividerVisible) {
-            mHorizontalDividerDrawable.setBounds(
-                    leftBound,
-                    height - mHorizontalDividerHeight,
-                    rightBound,
-                    height);
-            bottomBound -= mHorizontalDividerHeight;
-        }
+        mBoundsWithoutHeader.set(leftBound, topBound, rightBound, bottomBound);
 
-        mBoundsWithoutHeader.set(0, topBound, width, bottomBound);
+        if (mIsSectionHeaderEnabled) {
+            if (isLayoutRtl) {
+                rightBound -= mGapBetweenImageAndText;
+            } else {
+                leftBound += mGapBetweenImageAndText;
+            }
+        }
 
         if (mActivatedStateSupported && isActivated()) {
             mActivatedBackgroundDrawable.setBounds(mBoundsWithoutHeader);
@@ -685,8 +624,8 @@
     public void adjustListItemSelectionBounds(Rect bounds) {
         bounds.top += mBoundsWithoutHeader.top;
         bounds.bottom = bounds.top + mBoundsWithoutHeader.height();
-        bounds.left += mSelectionBoundsMarginLeft;
-        bounds.right -= mSelectionBoundsMarginRight;
+        bounds.left = mBoundsWithoutHeader.left;
+        bounds.right = mBoundsWithoutHeader.right;
     }
 
     protected boolean isVisible(View view) {
@@ -712,10 +651,6 @@
         }
     }
 
-    protected void setDefaultPhotoViewSize(int pixels) {
-        mDefaultPhotoViewSize = pixels;
-    }
-
     protected int getDefaultPhotoViewSize() {
         return mDefaultPhotoViewSize;
     }
@@ -758,56 +693,34 @@
         if (mActivatedStateSupported && isActivated()) {
             mActivatedBackgroundDrawable.draw(canvas);
         }
-        if (mHorizontalDividerVisible) {
-            mHorizontalDividerDrawable.draw(canvas);
-        }
 
         super.dispatchDraw(canvas);
     }
 
     /**
-     * Sets the flag that determines whether a divider should drawn at the bottom
-     * of the view.
-     */
-    public void setDividerVisible(boolean visible) {
-        mHorizontalDividerVisible = visible;
-    }
-
-    /**
      * Sets section header or makes it invisible if the title is null.
      */
     public void setSectionHeader(String title) {
         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_VERTICAL |
+                        (ViewUtil.isViewLayoutRtl(this) ? Gravity.RIGHT : Gravity.LEFT));
                 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.
      */
@@ -987,7 +900,6 @@
             mLabelView.setEllipsize(getTextEllipsis());
             mLabelView.setTextAppearance(getContext(), R.style.TextAppearanceSmall);
             if (mPhotoPosition == PhotoPosition.LEFT) {
-                //mLabelView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mCountViewTextSize);
                 mLabelView.setAllCaps(true);
                 mLabelView.setGravity(Gravity.END);
             } else {
@@ -1134,39 +1046,6 @@
     }
 
     /**
-     * Returns the text view for the contacts count, creating it if necessary.
-     */
-    public TextView getCountView() {
-        if (mCountView == null) {
-            mCountView = new TextView(getContext());
-            mCountView.setSingleLine(true);
-            mCountView.setEllipsize(getTextEllipsis());
-            mCountView.setTextAppearance(getContext(), android.R.style.TextAppearance_Medium);
-            mCountView.setTextColor(R.color.people_app_theme_color);
-            addView(mCountView);
-        }
-        return mCountView;
-    }
-
-    /**
-     * Adds or updates a text view for the contacts count.
-     */
-    public void setCountView(CharSequence text) {
-        if (TextUtils.isEmpty(text)) {
-            if (mCountView != null) {
-                mCountView.setVisibility(View.GONE);
-            }
-        } else {
-            getCountView();
-            setMarqueeText(mCountView, text);
-            mCountView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mCountViewTextSize);
-            mCountView.setGravity(Gravity.CENTER_VERTICAL);
-            mCountView.setTextColor(mContactsCountTextColor);
-            mCountView.setVisibility(VISIBLE);
-        }
-    }
-
-    /**
      * Adds or updates a text view for the status.
      */
     public void setStatus(CharSequence text) {
@@ -1510,15 +1389,6 @@
     }
 
     /**
-     * Specifies left and right margin for selection bounds. See also
-     * {@link #adjustListItemSelectionBounds(Rect)}.
-     */
-    public void setSelectionBoundsHorizontalMargin(int left, int right) {
-        mSelectionBoundsMarginLeft = left;
-        mSelectionBoundsMarginRight = right;
-    }
-
-    /**
      * Set drawable resources directly for both the background and the drawable resource
      * of the photo view
      *
diff --git a/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java b/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
index 401b3e3..e0c3e1a 100644
--- a/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
+++ b/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
@@ -19,13 +19,11 @@
 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;
@@ -34,169 +32,34 @@
 /**
  * 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 final int mContactsCountTextColor;
-    private final int mCountViewTextSize;
-
-    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);
-        mContactsCountTextColor = a.getColor(
-                R.styleable.ContactListItemView_list_item_contacts_count_text_color, Color.BLACK);
-        mCountViewTextSize = (int)a.getDimensionPixelSize(
-                R.styleable.ContactListItemView_list_item_contacts_count_text_size, 12);
-
+        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;
-
-        int leftCountTextView = 0;
-        int rightCountTextView = 0;
-
-        if (ViewUtil.isViewLayoutRtl(this)) {
-            rightHeaderTextView = width - mPaddingRight - mHeaderTextIndent;
-            leftHeaderTextView = rightHeaderTextView - mHeaderTextView.getMeasuredWidth();
-
-            leftCountTextView = mHeaderTextIndent + mPaddingLeft;
-            rightCountTextView = mCountTextView.getMeasuredWidth() + leftCountTextView;
-        } else {
-            leftHeaderTextView = mHeaderTextIndent + mPaddingLeft;
-            rightHeaderTextView = mHeaderTextView.getMeasuredWidth() + leftHeaderTextView;
-
-            // Order of statements matters
-            rightCountTextView = width - mPaddingRight;
-            leftCountTextView = rightCountTextView - mCountTextView.getMeasuredWidth();
-        }
-
-        // Take into account left and right padding when laying out the below views.
-        mHeaderTextView.layout(leftHeaderTextView,
-                topTextView,
-                rightHeaderTextView,
-                bottomTextView);
-
-        if (isViewMeasurable(mCountTextView)) {
-            mCountTextView.layout(leftCountTextView,
-                    topTextView,
-                    rightCountTextView,
-                    bottomTextView);
-        }
-
-        mHeaderDivider.layout(mPaddingLeft,
-                mHeaderBackgroundHeight,
-                width - mPaddingRight,
-                mHeaderBackgroundHeight + mHeaderUnderlineHeight);
+        setBackgroundColor(backgroundColor);
+        setTextAppearance(getContext(), R.style.SectionHeaderStyle);
+        setLayoutParams(new LayoutParams(
+                getResources().getDimensionPixelSize(R.dimen.contact_list_section_header_width),
+                LayoutParams.WRAP_CONTENT));
+        setGravity(Gravity.CENTER_VERTICAL |
+                (ViewUtil.isViewLayoutRtl(this) ? Gravity.RIGHT : Gravity.LEFT));
     }
 
     /**
      * 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();
-    }
-
-    public void setCountView(String count) {
-        if (mCountTextView == null) {
-            mCountTextView = new TextView(mContext);
-            mCountTextView.setTextColor(mContactsCountTextColor);
-            mCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mCountViewTextSize);
-            mCountTextView.setGravity(Gravity.CENTER_VERTICAL);
-            addView(mCountTextView);
-        }
-        mCountTextView.setText(count);
-        if (count == null || count.isEmpty()) {
-            mCountTextView.setVisibility(View.GONE);
-        } else {
-            mCountTextView.setVisibility(View.VISIBLE);
-        }
-    }
-
-    private boolean isViewMeasurable(View view) {
-        return (view != null && view.getVisibility() == View.VISIBLE);
-    }
 }
diff --git a/src/com/android/contacts/common/list/ContactTileAdapter.java b/src/com/android/contacts/common/list/ContactTileAdapter.java
index d9fbeac..9dab6b4 100644
--- a/src/com/android/contacts/common/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/common/list/ContactTileAdapter.java
@@ -164,6 +164,10 @@
         mPhoneNumberLabelIndex = ContactTileLoaderFactory.PHONE_NUMBER_LABEL;
     }
 
+    private static boolean cursorIsValid(Cursor cursor) {
+        return cursor != null && !cursor.isClosed();
+    }
+
     /**
      * Gets the number of frequents from the passed in cursor.
      *
@@ -180,10 +184,11 @@
                 break;
             case STREQUENT:
             case STREQUENT_PHONE_ONLY:
-                mNumFrequents = cursor.getCount() - mDividerPosition;
+                mNumFrequents = cursorIsValid(cursor) ?
+                    cursor.getCount() - mDividerPosition : 0;
                 break;
             case FREQUENT_ONLY:
-                mNumFrequents = cursor.getCount();
+                mNumFrequents = cursorIsValid(cursor) ? cursor.getCount() : 0;
                 break;
             default:
                 throw new IllegalArgumentException("Unrecognized DisplayType " + mDisplayType);
@@ -212,20 +217,22 @@
      * Returns 0 if {@link DisplayType#FREQUENT_ONLY}
      */
     protected int getDividerPosition(Cursor cursor) {
-        if (cursor == null || cursor.isClosed()) {
-            throw new IllegalStateException("Unable to access cursor");
-        }
-
         switch (mDisplayType) {
             case STREQUENT:
             case STREQUENT_PHONE_ONLY:
+                if (!cursorIsValid(cursor)) {
+                    return 0;
+                }
                 cursor.moveToPosition(-1);
                 while (cursor.moveToNext()) {
                     if (cursor.getInt(mStarredIndex) == 0) {
                         return cursor.getPosition();
                     }
                 }
-                break;
+
+                // There are not NON Starred contacts in cursor
+                // Set divider positon to end
+                return cursor.getCount();
             case STARRED_ONLY:
                 // There is no divider
                 return -1;
@@ -235,16 +242,14 @@
             default:
                 throw new IllegalStateException("Unrecognized DisplayType " + mDisplayType);
         }
-
-        // There are not NON Starred contacts in cursor
-        // Set divider positon to end
-        return cursor.getCount();
     }
 
     protected ContactEntry createContactEntryFromCursor(Cursor cursor, int position) {
         // If the loader was canceled we will be given a null cursor.
         // In that case, show an empty list of contacts.
-        if (cursor == null || cursor.isClosed() || cursor.getCount() <= position) return null;
+        if (!cursorIsValid(cursor) || cursor.getCount() <= position) {
+            return null;
+        }
 
         cursor.moveToPosition(position);
         long id = cursor.getLong(mIdIndex);
@@ -302,7 +307,7 @@
 
     @Override
     public int getCount() {
-        if (mContactCursor == null || mContactCursor.isClosed()) {
+        if (!cursorIsValid(mContactCursor)) {
             return 0;
         }
 
diff --git a/src/com/android/contacts/common/list/IndexerListAdapter.java b/src/com/android/contacts/common/list/IndexerListAdapter.java
index 14243ce..91d02f0 100644
--- a/src/com/android/contacts/common/list/IndexerListAdapter.java
+++ b/src/com/android/contacts/common/list/IndexerListAdapter.java
@@ -70,16 +70,6 @@
      */
     protected abstract void setPinnedSectionTitle(View pinnedHeaderView, String title);
 
-    /**
-     * Sets the contacts count in the pinned header.
-     */
-    protected abstract void setPinnedHeaderContactsCount(View header);
-
-    /**
-     * clears the contacts count in the pinned header and makes the view invisible.
-     */
-    protected abstract void clearPinnedHeaderContactsCount(View header);
-
     public boolean isSectionHeaderDisplayEnabled() {
         return mSectionHeaderDisplayEnabled;
     }
@@ -184,12 +174,13 @@
             if (section == -1) {
                 listView.setHeaderInvisible(index, false);
             } else {
-                setPinnedSectionTitle(mHeader, (String)mIndexer.getSections()[section]);
-                if (section == 0) {
-                    setPinnedHeaderContactsCount(mHeader);
-                } else {
-                    clearPinnedHeaderContactsCount(mHeader);
+                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
                 int partitionStart = getPositionForPartition(mIndexedPartition);
                 if (hasHeader(mIndexedPartition)) {
diff --git a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
index a6d67ce..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);
@@ -363,7 +363,6 @@
 
         final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
         bindPhoneNumber(view, cursor, directory.isDisplayNumber());
-        view.setDividerVisible(showBottomDivider);
     }
 
     protected void bindPhoneNumber(ContactListItemView view, Cursor cursor, boolean displayNumber) {
@@ -396,10 +395,8 @@
         if (isSectionHeaderDisplayEnabled()) {
             Placement placement = getItemPlacementInSection(position);
             view.setSectionHeader(placement.firstInSection ? placement.sectionHeader : null);
-            view.setDividerVisible(!placement.lastInSection);
         } else {
             view.setSectionHeader(null);
-            view.setDividerVisible(true);
         }
     }
 
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);
diff --git a/src/com/android/contacts/common/util/ViewUtil.java b/src/com/android/contacts/common/util/ViewUtil.java
index fadb3de..1dfe427 100644
--- a/src/com/android/contacts/common/util/ViewUtil.java
+++ b/src/com/android/contacts/common/util/ViewUtil.java
@@ -16,9 +16,13 @@
 
 package com.android.contacts.common.util;
 
+import android.content.res.Resources;
+import android.graphics.Outline;
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.contacts.common.R;
+
 /**
  * Provides static functions to work with views
  */
@@ -49,4 +53,29 @@
     public static boolean isViewLayoutRtl(View view) {
         return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
     }
+
+    /**
+     * Configures the floating action button, clipping it to a circle and setting its translation z.
+     * @param view The float action button's view.
+     * @param res The resources file.
+     */
+    public static void setupFloatingActionButton(View view, Resources res) {
+        // Once layout is complete and the floating action button has been assigned a width and
+        // height, assign the outline.
+        view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+            @Override
+            public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                final Outline outline = new Outline();
+                final int minDimension = Math.min(right - left, bottom - top);
+                if (minDimension <= 0) {
+                    return;
+                }
+                outline.setRoundRect(0, 0, right - left, bottom - top, minDimension / 2);
+                v.setOutline(outline);
+            }
+        });
+        view.setTranslationZ(
+                res.getDimensionPixelSize(R.dimen.floating_action_button_translation_z));
+    }
 }