Pinned header optimizations and fixes

Change-Id: I4a53d55f18dc7b4e21518f8c4c653a7ecde8470e
diff --git a/src/com/android/contacts/list/ContactEntryListAdapter.java b/src/com/android/contacts/list/ContactEntryListAdapter.java
index 9da3704..c37010e 100644
--- a/src/com/android/contacts/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/list/ContactEntryListAdapter.java
@@ -18,6 +18,7 @@
 import com.android.contacts.ContactPhotoLoader;
 import com.android.contacts.ContactsSectionIndexer;
 import com.android.contacts.R;
+import com.android.contacts.widget.PinnedHeaderListAdapter;
 import com.android.contacts.widget.TextWithHighlightingFactory;
 
 import android.app.patterns.CursorLoader;
@@ -53,7 +54,8 @@
     private boolean mSearchResultsMode;
 
     public ContactEntryListAdapter(Context context) {
-        super(context);
+        super(context, R.layout.list_section, R.id.header_text,
+                context.getResources().getColor(R.color.pinned_header_background));
     }
 
     public Context getContext() {
diff --git a/src/com/android/contacts/list/PinnedHeaderListAdapter.java b/src/com/android/contacts/widget/PinnedHeaderListAdapter.java
similarity index 77%
rename from src/com/android/contacts/list/PinnedHeaderListAdapter.java
rename to src/com/android/contacts/widget/PinnedHeaderListAdapter.java
index dd1542e..db99e14 100644
--- a/src/com/android/contacts/list/PinnedHeaderListAdapter.java
+++ b/src/com/android/contacts/widget/PinnedHeaderListAdapter.java
@@ -13,16 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.contacts.list;
-
-import com.android.contacts.R;
-import com.android.contacts.widget.PinnedHeaderListView;
+package com.android.contacts.widget;
 
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
-import android.opengl.Visibility;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -36,22 +32,32 @@
 public abstract class PinnedHeaderListAdapter extends CursorAdapter
         implements SectionIndexer, PinnedHeaderListView.PinnedHeaderAdapter {
 
-    /**
-     * An approximation of the background color of the pinned header. This color
-     * is used when the pinned header is being pushed up.  At that point the header
-     * "fades away".  Rather than computing a faded bitmap based on the 9-patch
-     * normally used for the background, we will use a solid color, which will
-     * provide better performance and reduced complexity.
-     */
-    private int mPinnedHeaderBackgroundColor;
+    private final int mPinnedHeaderBackgroundColor;
+    private final int mSectionHeaderTextViewId;
+    private final int mSectionHeaderLayoutResId;
 
     private SectionIndexer mIndexer;
 
-    public PinnedHeaderListAdapter(Context context) {
+    /**
+     * Constructor.
+     *
+     * @param context
+     * @param sectionHeaderLayoutResourceId section header layout resource ID
+     * @param sectionHeaderTextViewId section header text view ID
+     * @param backgroundColor An approximation of the background color of the
+     *            pinned header. This color is used when the pinned header is
+     *            being pushed up. At that point the header "fades away". Rather
+     *            than computing a faded bitmap based on the 9-patch normally
+     *            used for the background, we will use a solid color, which will
+     *            provide better performance and reduced complexity.
+     */
+    public PinnedHeaderListAdapter(Context context, int sectionHeaderLayoutResourceId,
+            int sectionHeaderTextViewId, int backgroundColor) {
         super(context, null, false);
         this.mContext = context;
-        mPinnedHeaderBackgroundColor =
-                context.getResources().getColor(R.color.pinned_header_background);
+        mPinnedHeaderBackgroundColor = backgroundColor;
+        mSectionHeaderLayoutResId = sectionHeaderLayoutResourceId;
+        mSectionHeaderTextViewId = sectionHeaderTextViewId;
     }
 
     public void setIndexer(SectionIndexer indexer) {
@@ -97,7 +103,7 @@
      * visible or partially pushed up out of the view.
      */
     public int getPinnedHeaderState(int position) {
-        if (mIndexer == null || position < 0 || mCursor == null || mCursor.getCount() == 0) {
+        if (mIndexer == null || mCursor == null || mCursor.getCount() == 0) {
             return PINNED_HEADER_GONE;
         }
 
@@ -132,7 +138,7 @@
         PinnedHeaderCache cache = (PinnedHeaderCache)header.getTag();
         if (cache == null) {
             cache = new PinnedHeaderCache();
-            cache.titleView = (TextView)header.findViewById(R.id.header_text);
+            cache.titleView = (TextView)header.findViewById(mSectionHeaderTextViewId);
             cache.textColor = cache.titleView.getTextColors();
             cache.background = header.getBackground();
             header.setTag(cache);
@@ -163,6 +169,6 @@
     }
 
     public View createPinnedHeaderView(ViewGroup parent) {
-        return LayoutInflater.from(mContext).inflate(R.layout.list_section, parent, false);
+        return LayoutInflater.from(mContext).inflate(mSectionHeaderLayoutResId, parent, false);
     }
 }
diff --git a/src/com/android/contacts/widget/PinnedHeaderListView.java b/src/com/android/contacts/widget/PinnedHeaderListView.java
index bdc66d5..9562714 100644
--- a/src/com/android/contacts/widget/PinnedHeaderListView.java
+++ b/src/com/android/contacts/widget/PinnedHeaderListView.java
@@ -81,6 +81,7 @@
     private PinnedHeaderAdapter mAdapter;
     private View mHeaderView;
     private boolean mHeaderViewVisible;
+    private float mHeaderOffset;
     private int mHeaderViewWidth;
     private int mHeaderViewHeight;
 
@@ -130,7 +131,6 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         if (mHeaderView != null) {
-            configureHeaderView(getFirstVisiblePosition() - getHeaderViewsCount());
             measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);
             mHeaderViewWidth = mHeaderView.getMeasuredWidth();
             mHeaderViewHeight = mHeaderView.getMeasuredHeight();
@@ -141,7 +141,8 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         if (mHeaderView != null) {
-            mHeaderView.layout(0, mHeaderView.getTop(), mHeaderViewWidth, mHeaderViewHeight);
+            configureHeaderView(getFirstVisiblePosition() - getHeaderViewsCount());
+            mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
         }
     }
 
@@ -173,9 +174,7 @@
 
             case PinnedHeaderAdapter.PINNED_HEADER_VISIBLE: {
                 mAdapter.configurePinnedHeader(mHeaderView, position, MAX_ALPHA);
-                if (mHeaderView.getTop() != 0) {
-                    mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
-                }
+                mHeaderOffset = 0;
                 mHeaderViewVisible = true;
                 break;
             }
@@ -184,8 +183,8 @@
                 View firstView = getChildAt(0);
                 int bottom = firstView.getBottom();
                 int headerHeight = mHeaderViewHeight;
-                int y;
                 int alpha;
+                int y;
                 if (bottom < headerHeight) {
                     y = (bottom - headerHeight);
                     alpha = MAX_ALPHA * (headerHeight + y) / headerHeight;
@@ -194,9 +193,7 @@
                     alpha = MAX_ALPHA;
                 }
                 mAdapter.configurePinnedHeader(mHeaderView, position, alpha);
-                if (mHeaderView.getTop() != y) {
-                    mHeaderView.layout(0, y, headerHeight, headerHeight + y);
-                }
+                mHeaderOffset = y;
                 mHeaderViewVisible = true;
                 break;
             }
@@ -207,7 +204,10 @@
     protected void dispatchDraw(Canvas canvas) {
         super.dispatchDraw(canvas);
         if (mHeaderViewVisible) {
+            canvas.save();
+            canvas.translate(0, mHeaderOffset);
             drawChild(canvas, mHeaderView, getDrawingTime());
+            canvas.restore();
         }
     }
 }