Merge "Add different Uri formats for Contact-Editor Tests"
diff --git a/res/layout-finger/recent_calls_list_child_item.xml b/res/layout-finger/recent_calls_list_child_item.xml
index 14eb24d..527e259 100644
--- a/res/layout-finger/recent_calls_list_child_item.xml
+++ b/res/layout-finger/recent_calls_list_child_item.xml
@@ -21,7 +21,7 @@
     android:background="@drawable/list_item_background_secondary"
 >
 
-    <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_icon"
+    <ImageView android:id="@+id/call_icon"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:paddingLeft="14dip"
diff --git a/res/layout-finger/recent_calls_list_group_item.xml b/res/layout-finger/recent_calls_list_group_item.xml
index 2d3e7af..5b4cf21 100644
--- a/res/layout-finger/recent_calls_list_group_item.xml
+++ b/res/layout-finger/recent_calls_list_group_item.xml
@@ -20,7 +20,7 @@
     android:paddingLeft="7dip"
 >
 
-    <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_icon"
+    <ImageView android:id="@+id/call_icon"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:paddingLeft="14dip"
diff --git a/res/layout-finger/recent_calls_list_item.xml b/res/layout-finger/recent_calls_list_item.xml
index 8efa23c..2c519d6 100644
--- a/res/layout-finger/recent_calls_list_item.xml
+++ b/res/layout-finger/recent_calls_list_item.xml
@@ -20,7 +20,7 @@
     android:paddingLeft="7dip"
 >
 
-    <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_icon"
+    <ImageView android:id="@+id/call_icon"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:paddingLeft="14dip"
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 5d061f7..8a52786 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -17,16 +17,17 @@
 package com.android.contacts;
 
 import com.android.contacts.list.ContactBrowseListContextMenuAdapter;
-import com.android.contacts.list.ContactBrowseListFragment;
 import com.android.contacts.list.ContactEntryListAdapter;
 import com.android.contacts.list.ContactEntryListFragment;
 import com.android.contacts.list.ContactItemListAdapter;
 import com.android.contacts.list.ContactPickerFragment;
 import com.android.contacts.list.ContactsIntentResolver;
+import com.android.contacts.list.DefaultContactBrowseListFragment;
 import com.android.contacts.list.DefaultContactListFragment;
 import com.android.contacts.list.MultiplePhonePickerFragment;
 import com.android.contacts.list.OnContactBrowserActionListener;
 import com.android.contacts.list.OnContactPickerActionListener;
+import com.android.contacts.list.StrequentContactListFragment;
 import com.android.contacts.model.ContactsSource;
 import com.android.contacts.model.Sources;
 import com.android.contacts.ui.ContactsPreferences;
@@ -66,7 +67,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Parcelable;
 import android.preference.PreferenceManager;
 import android.provider.ContactsContract;
 import android.provider.Settings;
@@ -87,9 +87,7 @@
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.Intents.Insert;
 import android.telephony.TelephonyManager;
-import android.text.Editable;
 import android.text.TextUtils;
-import android.text.TextWatcher;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.KeyEvent;
@@ -97,17 +95,12 @@
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnTouchListener;
-import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.ArrayAdapter;
 import android.widget.Button;
-import android.widget.Filter;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.TextView;
@@ -514,10 +507,9 @@
             case MODE_DEFAULT:
             case MODE_INSERT_OR_EDIT_CONTACT:
             case MODE_QUERY_PICK_TO_EDIT:
-            case MODE_STREQUENT:
             case MODE_FREQUENT:
             case MODE_QUERY: {
-                ContactBrowseListFragment fragment = new ContactBrowseListFragment();
+                DefaultContactBrowseListFragment fragment = new DefaultContactBrowseListFragment();
                 if (!mSearchMode) {
                     fragment.setSectionHeaderDisplayEnabled(true);
                 }
@@ -594,6 +586,68 @@
                 mListFragment = fragment;
                 break;
             }
+            case MODE_STREQUENT: {
+                StrequentContactListFragment fragment = new StrequentContactListFragment();
+                fragment.setSectionHeaderDisplayEnabled(false);
+                fragment.setOnContactListActionListener(new OnContactBrowserActionListener() {
+                    public void onSearchAllContactsAction(String string) {
+                        doSearch();
+                    }
+
+                    public void onViewContactAction(Uri contactLookupUri) {
+                        startActivity(new Intent(Intent.ACTION_VIEW, contactLookupUri));
+                    }
+
+                    public void onCreateNewContactAction() {
+                        Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
+                        Bundle extras = getIntent().getExtras();
+                        if (extras != null) {
+                            intent.putExtras(extras);
+                        }
+                        startActivity(intent);
+                    }
+
+                    public void onEditContactAction(Uri contactLookupUri) {
+                        Intent intent = new Intent(Intent.ACTION_EDIT, contactLookupUri);
+                        Bundle extras = getIntent().getExtras();
+                        if (extras != null) {
+                            intent.putExtras(extras);
+                        }
+                        startActivity(intent);
+                    }
+
+                    public void onAddToFavoritesAction(Uri contactUri) {
+                        ContentValues values = new ContentValues(1);
+                        values.put(Contacts.STARRED, 1);
+                        getContentResolver().update(contactUri, values, null, null);
+                    }
+
+                    public void onRemoveFromFavoritesAction(Uri contactUri) {
+                        ContentValues values = new ContentValues(1);
+                        values.put(Contacts.STARRED, 0);
+                        getContentResolver().update(contactUri, values, null, null);
+                    }
+
+                    public void onCallContactAction(Uri contactUri) {
+                        // TODO
+                    }
+
+                    public void onSmsContactAction(Uri contactUri) {
+                        // TODO
+                    }
+
+                    public void onDeleteContactAction(Uri contactUri) {
+                        doContactDelete(contactUri);
+                    }
+
+                    public void onFinishAction() {
+                        onBackPressed();
+                    }
+                });
+                fragment.setContextMenuAdapter(new ContactBrowseListContextMenuAdapter(fragment));
+                mListFragment = fragment;
+                break;
+            }
             case MODE_PICK_CONTACT:
             case MODE_PICK_OR_CREATE_CONTACT: {
                 ContactPickerFragment fragment = new ContactPickerFragment();
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index 5ae425f..0614772 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -15,26 +15,20 @@
  */
 package com.android.contacts.list;
 
-import com.android.contacts.R;
-
 import android.app.patterns.CursorLoader;
 import android.app.patterns.Loader;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
 
 /**
  * Fragment containing a contact list used for browsing (as compared to
  * picking a contact with one of the PICK intents).
  */
-public class ContactBrowseListFragment extends ContactEntryListFragment<ContactListAdapter> {
+public abstract class ContactBrowseListFragment extends
+        ContactEntryListFragment<ContactListAdapter> {
 
     private OnContactBrowserActionListener mListener;
-    private boolean mEditMode;
-    private boolean mCreateContactEnabled;
 
     private CursorLoader mLoader;
 
@@ -44,6 +38,10 @@
         return mLoader;
     }
 
+    public CursorLoader getLoader() {
+        return mLoader;
+    }
+
     @Override
     protected void reloadData() {
         getAdapter().configureLoader(mLoader);
@@ -65,68 +63,12 @@
         getAdapter().changeCursor(data);
     }
 
-    @Override
-    protected void onItemClick(int position, long id) {
-        ContactListAdapter adapter = getAdapter();
-        if (adapter.isSearchAllContactsItemPosition(position)) {
-            mListener.onSearchAllContactsAction((String)null);
-        } else if (isEditMode()) {
-            if (position == 0 && !isSearchMode() && isCreateContactEnabled()) {
-                mListener.onCreateNewContactAction();
-            } else {
-                adapter.moveToPosition(position);
-                mListener.onEditContactAction(adapter.getContactUri());
-            }
-        } else {
-            adapter.moveToPosition(position);
-            mListener.onViewContactAction(adapter.getContactUri());
-        }
+    public void createNewContact() {
+        mListener.onCreateNewContactAction();
     }
 
-    @Override
-    protected ContactListAdapter createListAdapter() {
-        ContactListAdapter adapter = new ContactListAdapter(getActivity());
-        adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
-
-        adapter.setSearchMode(isSearchMode());
-        adapter.setSearchResultsMode(isSearchResultsMode());
-        adapter.setQueryString(getQueryString());
-
-        adapter.setContactNameDisplayOrder(getContactNameDisplayOrder());
-        adapter.setSortOrder(getSortOrder());
-
-        adapter.setDisplayPhotos(true);
-        adapter.setQuickContactEnabled(true);
-
-        adapter.configureLoader(mLoader);
-        return adapter;
-    }
-
-    @Override
-    protected View inflateView(LayoutInflater inflater, ViewGroup container) {
-        if (isSearchMode()) {
-            return inflater.inflate(R.layout.contacts_search_content, null);
-        } else if (isSearchResultsMode()) {
-            return inflater.inflate(R.layout.contacts_list_search_results, null);
-        } else {
-            return inflater.inflate(R.layout.contacts_list_content, null);
-        }
-    }
-
-    public void setEditMode(boolean flag) {
-        mEditMode = flag;
-    }
-
-    public boolean isEditMode() {
-        return mEditMode;
-    }
-
-    public void setCreateContactEnabled(boolean flag) {
-        this.mCreateContactEnabled = flag;
-    }
-
-    public boolean isCreateContactEnabled() {
-        return mCreateContactEnabled;
+    public void searchAllContacts() {
+        mListener.onSearchAllContactsAction((String)null);
     }
 
     public void viewContact(Uri contactUri) {
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/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index fefa718..9a3bf1d 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -90,12 +90,35 @@
 
     protected abstract View inflateView(LayoutInflater inflater, ViewGroup container);
     protected abstract T createListAdapter();
+
+    /**
+     * @param position Please note that the position is already adjusted for
+     *            header views, so "0" means the first list item below header
+     *            views.
+     */
     protected abstract void onItemClick(int position, long id);
 
     public T getAdapter() {
         return mAdapter;
     }
 
+    public void setListAdapter(T adapter) {
+        mAdapter = adapter;
+        mListView.setAdapter(mAdapter);
+        if (isPhotoLoaderEnabled()) {
+            mAdapter.setPhotoLoader(mPhotoLoader);
+        }
+        ((ContactsListActivity)getActivity()).setupListView(mAdapter, mListView);
+    }
+
+    public View getView() {
+        return mView;
+    }
+
+    public ListView getListView() {
+        return mListView;
+    }
+
     // TODO make abstract
     @Override
     protected Loader<Cursor> onCreateLoader(int id, Bundle args) {
@@ -109,12 +132,17 @@
 
     @Override
     protected void onLoadFinished(Loader<Cursor> loader, Cursor data) {
-        if (data != null && isSearchResultsMode()) {
-            TextView foundContactsText = (TextView)mView.findViewById(R.id.search_results_found);
-            String text = getQuantityText(data.getCount(),
-                    R.string.listFoundAllContactsZero, R.plurals.listFoundAllContacts);
-            foundContactsText.setText(text);
+        if (data == null) {
+            return;
         }
+
+        showCount(data);
+    }
+
+    /**
+     * Shows the count of entries included in the list.
+     */
+    protected void showCount(Cursor data) {
     }
 
     protected void reloadData() {
@@ -222,26 +250,27 @@
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container) {
-        mView = inflateView(inflater, container);
+        mView = createView(inflater, container);
         mAdapter = createListAdapter();
-        configureView(mView);
+        setListAdapter(mAdapter);
         return mView;
     }
 
-    protected void configureView(View view) {
-        mListView = (ListView)view.findViewById(android.R.id.list);
+    protected View createView(LayoutInflater inflater, ViewGroup container) {
+        mView = inflateView(inflater, container);
+
+        mListView = (ListView)mView.findViewById(android.R.id.list);
         if (mListView == null) {
             throw new RuntimeException(
                     "Your content must have a ListView whose id attribute is " +
                     "'android.R.id.list'");
         }
 
-        View emptyView = view.findViewById(com.android.internal.R.id.empty);
+        View emptyView = mView.findViewById(com.android.internal.R.id.empty);
         if (emptyView != null) {
             mListView.setEmptyView(emptyView);
         }
 
-        mListView.setAdapter(mAdapter);
         mListView.setOnItemClickListener(this);
         mListView.setOnFocusChangeListener(this);
         mListView.setOnTouchListener(this);
@@ -257,17 +286,14 @@
             mListView.setOnCreateContextMenuListener(mContextMenuAdapter);
         }
 
-        configurePinnedHeader();
-
         if (isPhotoLoaderEnabled()) {
             mPhotoLoader =
                 new ContactPhotoLoader(getActivity(), R.drawable.ic_contact_list_picture);
-            mAdapter.setPhotoLoader(mPhotoLoader);
             mListView.setOnScrollListener(this);
         }
 
         if (isSearchMode()) {
-            mSearchEditText = (SearchEditText)view.findViewById(R.id.search_src_text);
+            mSearchEditText = (SearchEditText)mView.findViewById(R.id.search_src_text);
             mSearchEditText.setText(getQueryString());
             mSearchEditText.addTextChangedListener(this);
             mSearchEditText.setOnEditorActionListener(this);
@@ -275,14 +301,13 @@
         }
 
         if (isSearchResultsMode()) {
-            TextView titleText = (TextView)view.findViewById(R.id.search_results_for);
+            TextView titleText = (TextView)mView.findViewById(R.id.search_results_for);
             if (titleText != null) {
                 titleText.setText(Html.fromHtml(getActivity().getString(R.string.search_results_for,
                         "<b>" + getQueryString() + "</b>")));
             }
         }
-
-        ((ContactsListActivity)getActivity()).setupListView(mAdapter, mListView);
+        return mView;
     }
 
     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
@@ -314,22 +339,14 @@
         super.onDestroy();
     }
 
-    private void configurePinnedHeader() {
-        if (!mSectionHeaderDisplayEnabled) {
-            return;
-        }
-
-        if (mListView instanceof PinnedHeaderListView) {
-            PinnedHeaderListView pinnedHeaderList = (PinnedHeaderListView)mListView;
-            View headerView = mAdapter.createPinnedHeaderView(pinnedHeaderList);
-            pinnedHeaderList.setPinnedHeaderView(headerView);
-        }
-    }
 
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
         hideSoftKeyboard();
 
-        onItemClick(position, id);
+        int adjPosition = position - mListView.getHeaderViewsCount();
+        if (adjPosition >= 0) {
+            onItemClick(adjPosition, id);
+        }
     }
 
     private void hideSoftKeyboard() {
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index db4017c..1d7f72f 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -15,7 +15,6 @@
  */
 package com.android.contacts.list;
 
-import android.app.patterns.CursorLoader;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
@@ -23,7 +22,6 @@
 import android.provider.ContactsContract.ContactCounts;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.SearchSnippetColumns;
-import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
@@ -33,9 +31,9 @@
 /**
  * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type.
  */
-public class ContactListAdapter extends ContactEntryListAdapter {
+public abstract class ContactListAdapter extends ContactEntryListAdapter {
 
-    private static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
+    protected static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
         Contacts._ID,                       // 0
         Contacts.DISPLAY_NAME_PRIMARY,      // 1
         Contacts.DISPLAY_NAME_ALTERNATIVE,  // 2
@@ -49,7 +47,7 @@
         Contacts.HAS_PHONE_NUMBER,          // 10
     };
 
-    private static final String[] CONTACTS_SUMMARY_FILTER_PROJECTION = new String[] {
+    protected static final String[] CONTACTS_SUMMARY_FILTER_PROJECTION = new String[] {
         Contacts._ID,                       // 0
         Contacts.DISPLAY_NAME_PRIMARY,      // 1
         Contacts.DISPLAY_NAME_ALTERNATIVE,  // 2
@@ -66,20 +64,20 @@
         SearchSnippetColumns.SNIPPET_DATA4,     // 13
     };
 
-    private static final int SUMMARY_ID_COLUMN_INDEX = 0;
-    private static final int SUMMARY_DISPLAY_NAME_PRIMARY_COLUMN_INDEX = 1;
-    private static final int SUMMARY_DISPLAY_NAME_ALTERNATIVE_COLUMN_INDEX = 2;
-    private static final int SUMMARY_SORT_KEY_PRIMARY_COLUMN_INDEX = 3;
-    private static final int SUMMARY_STARRED_COLUMN_INDEX = 4;
-    private static final int SUMMARY_TIMES_CONTACTED_COLUMN_INDEX = 5;
-    private static final int SUMMARY_PRESENCE_STATUS_COLUMN_INDEX = 6;
-    private static final int SUMMARY_PHOTO_ID_COLUMN_INDEX = 7;
-    private static final int SUMMARY_LOOKUP_KEY_COLUMN_INDEX = 8;
-    private static final int SUMMARY_PHONETIC_NAME_COLUMN_INDEX = 9;
-    private static final int SUMMARY_HAS_PHONE_COLUMN_INDEX = 10;
-    private static final int SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX = 11;
-    private static final int SUMMARY_SNIPPET_DATA1_COLUMN_INDEX = 12;
-    private static final int SUMMARY_SNIPPET_DATA4_COLUMN_INDEX = 13;
+    protected static final int SUMMARY_ID_COLUMN_INDEX = 0;
+    protected static final int SUMMARY_DISPLAY_NAME_PRIMARY_COLUMN_INDEX = 1;
+    protected static final int SUMMARY_DISPLAY_NAME_ALTERNATIVE_COLUMN_INDEX = 2;
+    protected static final int SUMMARY_SORT_KEY_PRIMARY_COLUMN_INDEX = 3;
+    protected static final int SUMMARY_STARRED_COLUMN_INDEX = 4;
+    protected static final int SUMMARY_TIMES_CONTACTED_COLUMN_INDEX = 5;
+    protected static final int SUMMARY_PRESENCE_STATUS_COLUMN_INDEX = 6;
+    protected static final int SUMMARY_PHOTO_ID_COLUMN_INDEX = 7;
+    protected static final int SUMMARY_LOOKUP_KEY_COLUMN_INDEX = 8;
+    protected static final int SUMMARY_PHONETIC_NAME_COLUMN_INDEX = 9;
+    protected static final int SUMMARY_HAS_PHONE_COLUMN_INDEX = 10;
+    protected static final int SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX = 11;
+    protected static final int SUMMARY_SNIPPET_DATA1_COLUMN_INDEX = 12;
+    protected static final int SUMMARY_SNIPPET_DATA4_COLUMN_INDEX = 13;
 
     private boolean mQuickContactEnabled;
     private CharSequence mUnknownNameText;
@@ -92,37 +90,11 @@
         mUnknownNameText = context.getText(android.R.string.unknownName);
     }
 
-    @Override
-    public void configureLoader(CursorLoader loader) {
-        Uri uri;
-        if (isSearchMode() || isSearchResultsMode()) {
-            String query = getQueryString();
-            uri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
-                    TextUtils.isEmpty(query) ? "" : Uri.encode(query));
-            loader.setProjection(CONTACTS_SUMMARY_FILTER_PROJECTION);
-            if (!isSearchResultsMode()) {
-                loader.setSelection(Contacts.IN_VISIBLE_GROUP + "=1");
-            }
-        } else {
-            uri = Contacts.CONTENT_URI;
-            loader.setProjection(CONTACTS_SUMMARY_PROJECTION);
-            loader.setSelection(Contacts.IN_VISIBLE_GROUP + "=1");
-        }
-
-        if (isSectionHeaderDisplayEnabled()) {
-            uri = buildSectionIndexerUri(uri);
-        }
-
-        loader.setUri(uri);
-
-        if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
-            loader.setSortOrder(Contacts.SORT_KEY_PRIMARY);
-        } else {
-            loader.setSortOrder(Contacts.SORT_KEY_ALTERNATIVE);
-        }
+    public CharSequence getUnknownNameText() {
+        return mUnknownNameText;
     }
 
-    private static Uri buildSectionIndexerUri(Uri uri) {
+    protected static Uri buildSectionIndexerUri(Uri uri) {
         return uri.buildUpon()
                 .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build();
     }
diff --git a/src/com/android/contacts/list/ContactPickerFragment.java b/src/com/android/contacts/list/ContactPickerFragment.java
index 07908dd..930646b 100644
--- a/src/com/android/contacts/list/ContactPickerFragment.java
+++ b/src/com/android/contacts/list/ContactPickerFragment.java
@@ -57,7 +57,8 @@
 
     @Override
     protected ContactListAdapter createListAdapter() {
-        ContactListAdapter adapter = new ContactListAdapter(getActivity());
+        // TODO different adapter
+        ContactListAdapter adapter = new DefaultContactListAdapter(getActivity());
         adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
         adapter.setDisplayPhotos(isPhotoLoaderEnabled());
 
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
new file mode 100644
index 0000000..50a3f4b
--- /dev/null
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * 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 android.database.Cursor;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Fragment containing a contact list used for browsing (as compared to
+ * picking a contact with one of the PICK intents).
+ */
+public class DefaultContactBrowseListFragment extends ContactBrowseListFragment {
+
+    private boolean mEditMode;
+    private boolean mCreateContactEnabled;
+
+    @Override
+    protected void onItemClick(int position, long id) {
+        ContactListAdapter adapter = getAdapter();
+        if (adapter.isSearchAllContactsItemPosition(position)) {
+            searchAllContacts();
+        } else {
+            if (isEditMode()) {
+                if (position == 0 && !isSearchMode() && isCreateContactEnabled()) {
+                    createNewContact();
+                } else {
+                    adapter.moveToPosition(position);
+                    editContact(adapter.getContactUri());
+                }
+            } else {
+                adapter.moveToPosition(position);
+                viewContact(adapter.getContactUri());
+            }
+        }
+    }
+
+    @Override
+    protected ContactListAdapter createListAdapter() {
+        DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity());
+        adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
+
+        adapter.setSearchMode(isSearchMode());
+        adapter.setSearchResultsMode(isSearchResultsMode());
+        adapter.setQueryString(getQueryString());
+
+        adapter.setContactNameDisplayOrder(getContactNameDisplayOrder());
+        adapter.setSortOrder(getSortOrder());
+
+        adapter.setDisplayPhotos(true);
+        adapter.setQuickContactEnabled(true);
+
+        adapter.configureLoader(getLoader());
+        return adapter;
+    }
+
+    @Override
+    protected View inflateView(LayoutInflater inflater, ViewGroup container) {
+        if (isSearchMode()) {
+            return inflater.inflate(R.layout.contacts_search_content, null);
+        } else if (isSearchResultsMode()) {
+            return inflater.inflate(R.layout.contacts_list_search_results, null);
+        } else {
+            return inflater.inflate(R.layout.contacts_list_content, null);
+        }
+    }
+
+    @Override
+    protected View createView(LayoutInflater inflater, ViewGroup container) {
+        View view = super.createView(inflater, container);
+        if (!isSearchResultsMode()) {
+            // In the search-results mode the count is shown in the fat header above the list
+            getListView().addHeaderView(inflater.inflate(R.layout.total_contacts, null, false));
+        }
+        return view;
+    }
+
+    @Override
+    protected void showCount(Cursor data) {
+        int count = data.getCount();
+        if (isSearchMode()) {
+            TextView textView = (TextView) getView().findViewById(R.id.totalContactsText);
+            // TODO
+            // if (TextUtils.isEmpty(getQueryString())) {
+            String text = getQuantityText(count, R.string.listFoundAllContactsZero,
+                    R.plurals.searchFoundContacts);
+            textView.setText(text);
+        }
+        else if (isSearchResultsMode()) {
+            TextView countText = (TextView)getView().findViewById(R.id.search_results_found);
+            String text = getQuantityText(data.getCount(),
+                    R.string.listFoundAllContactsZero, R.plurals.listFoundAllContacts);
+            countText.setText(text);
+        } else {
+            // TODO
+            // if (contactsListActivity.mDisplayOnlyPhones) {
+            // text = contactsListActivity.getQuantityText(count,
+            // R.string.listTotalPhoneContactsZero,
+            // R.plurals.listTotalPhoneContacts);
+            TextView textView = (TextView)getView().findViewById(R.id.totalContactsText);
+            String text = getQuantityText(count, R.string.listTotalAllContactsZero,
+                    R.plurals.listTotalAllContacts);
+            textView.setText(text);
+        }
+    }
+
+    public void setEditMode(boolean flag) {
+        mEditMode = flag;
+    }
+
+    public boolean isEditMode() {
+        return mEditMode;
+    }
+
+    public void setCreateContactEnabled(boolean flag) {
+        this.mCreateContactEnabled = flag;
+    }
+
+    public boolean isCreateContactEnabled() {
+        return mCreateContactEnabled;
+    }
+}
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
new file mode 100644
index 0000000..f310c5c
--- /dev/null
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.list;
+
+import android.app.patterns.CursorLoader;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type.
+ */
+public class DefaultContactListAdapter extends ContactListAdapter {
+
+    public DefaultContactListAdapter(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void configureLoader(CursorLoader loader) {
+        Uri uri;
+        if (isSearchMode() || isSearchResultsMode()) {
+            String query = getQueryString();
+            uri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
+                    TextUtils.isEmpty(query) ? "" : Uri.encode(query));
+            loader.setProjection(CONTACTS_SUMMARY_FILTER_PROJECTION);
+            if (!isSearchResultsMode()) {
+                loader.setSelection(Contacts.IN_VISIBLE_GROUP + "=1");
+            }
+        } else {
+            uri = Contacts.CONTENT_URI;
+            loader.setProjection(CONTACTS_SUMMARY_PROJECTION);
+            loader.setSelection(Contacts.IN_VISIBLE_GROUP + "=1");
+        }
+
+        if (isSectionHeaderDisplayEnabled()) {
+            uri = buildSectionIndexerUri(uri);
+        }
+
+        loader.setUri(uri);
+
+        if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
+            loader.setSortOrder(Contacts.SORT_KEY_PRIMARY);
+        } else {
+            loader.setSortOrder(Contacts.SORT_KEY_ALTERNATIVE);
+        }
+    }
+
+    @Override
+    public View newView(Context context, Cursor cursor, ViewGroup parent) {
+        final ContactListItemView view = new ContactListItemView(context, null);
+        view.setUnknownNameText(getUnknownNameText());
+        view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
+        // TODO
+//        view.setOnCallButtonClickListener(contactsListActivity);
+        return view;
+    }
+
+    @Override
+    public void bindView(View itemView, Context context, Cursor cursor) {
+        super.bindView(itemView, context, cursor);
+    }
+}
diff --git a/src/com/android/contacts/list/StrequentContactListAdapter.java b/src/com/android/contacts/list/StrequentContactListAdapter.java
new file mode 100644
index 0000000..dc20c97
--- /dev/null
+++ b/src/com/android/contacts/list/StrequentContactListAdapter.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * 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 android.app.patterns.CursorLoader;
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListView;
+import android.widget.TextView;
+
+/**
+ * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type loading
+ * a combination of starred and frequently contacted.
+ */
+public class StrequentContactListAdapter extends ContactListAdapter {
+
+    private int mFrequentSeparatorPos;
+    private TextView mSeparatorView;
+
+    public StrequentContactListAdapter(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void configureLoader(CursorLoader loader) {
+        loader.setUri(Contacts.CONTENT_STREQUENT_URI);
+        loader.setProjection(CONTACTS_SUMMARY_PROJECTION);
+        if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
+            loader.setSortOrder(Contacts.SORT_KEY_PRIMARY);
+        } else {
+            loader.setSortOrder(Contacts.SORT_KEY_ALTERNATIVE);
+        }
+    }
+
+    @Override
+    public void changeCursor(Cursor cursor) {
+        super.changeCursor(cursor);
+
+        // Get the split between starred and frequent items, if the mode is strequent
+        mFrequentSeparatorPos = ListView.INVALID_POSITION;
+        int count = 0;
+        if (cursor != null && (count = cursor.getCount()) > 0) {
+            cursor.moveToPosition(-1);
+            for (int i = 0; cursor.moveToNext(); i++) {
+                int starred = cursor.getInt(SUMMARY_STARRED_COLUMN_INDEX);
+                if (starred == 0) {
+                    if (i > 0) {
+                        // Only add the separator when there are starred items present
+                        mFrequentSeparatorPos = i;
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    @Override
+    public int getCount() {
+        if (mFrequentSeparatorPos == ListView.INVALID_POSITION) {
+            return super.getCount();
+        } else {
+            // Add a row for the separator
+            return super.getCount() + 1;
+        }
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() {
+        return mFrequentSeparatorPos == ListView.INVALID_POSITION;
+    }
+
+    @Override
+    public boolean isEnabled(int position) {
+        return position != mFrequentSeparatorPos;
+    }
+
+    @Override
+    public Object getItem(int position) {
+        if (position < mFrequentSeparatorPos) {
+            return super.getItem(position);
+        } else {
+            return super.getItem(position - 1);
+        }
+    }
+
+    @Override
+    public long getItemId(int position) {
+        if (position < mFrequentSeparatorPos) {
+            return super.getItemId(position);
+        } else {
+            return super.getItemId(position - 1);
+        }
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (position == mFrequentSeparatorPos) {
+            return IGNORE_ITEM_VIEW_TYPE;
+        }
+
+        return super.getItemViewType(position);
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (position < mFrequentSeparatorPos) {
+            return super.getView(position, convertView, parent);
+        } else if (position == mFrequentSeparatorPos) {
+            if (mSeparatorView == null) {
+                mSeparatorView = (TextView)LayoutInflater.from(getContext()).
+                        inflate(R.layout.list_separator, parent, false);
+                mSeparatorView.setText(R.string.favoritesFrquentSeparator);
+            }
+            return mSeparatorView;
+        } else {
+            return super.getView(position - 1, convertView, parent);
+        }
+    }
+
+    @Override
+    public View newView(Context context, Cursor cursor, ViewGroup parent) {
+        final ContactListItemView view = new ContactListItemView(context, null);
+        view.setUnknownNameText(getUnknownNameText());
+        view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
+        // TODO
+//        view.setOnCallButtonClickListener(contactsListActivity);
+        return view;
+    }
+
+    @Override
+    public void bindView(View itemView, Context context, Cursor cursor) {
+        super.bindView(itemView, context, cursor);
+    }
+}
diff --git a/src/com/android/contacts/list/StrequentContactListFragment.java b/src/com/android/contacts/list/StrequentContactListFragment.java
new file mode 100644
index 0000000..fd746ae
--- /dev/null
+++ b/src/com/android/contacts/list/StrequentContactListFragment.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * 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 android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Fragment containing a list of starred contacts followed by a list of frequently contacted.
+ */
+public class StrequentContactListFragment extends ContactBrowseListFragment {
+
+    @Override
+    protected void onItemClick(int position, long id) {
+        ContactListAdapter adapter = getAdapter();
+        adapter.moveToPosition(position);
+        viewContact(adapter.getContactUri());
+    }
+
+    @Override
+    protected ContactListAdapter createListAdapter() {
+        StrequentContactListAdapter adapter = new StrequentContactListAdapter(getActivity());
+        adapter.setSectionHeaderDisplayEnabled(false);
+
+        adapter.setContactNameDisplayOrder(getContactNameDisplayOrder());
+        adapter.setSortOrder(getSortOrder());
+
+        adapter.setDisplayPhotos(true);
+        adapter.setQuickContactEnabled(true);
+
+        adapter.configureLoader(getLoader());
+        return adapter;
+    }
+
+    @Override
+    protected View inflateView(LayoutInflater inflater, ViewGroup container) {
+        return inflater.inflate(R.layout.contacts_list_content, null);
+    }
+}
diff --git a/src/com/android/contacts/list/PinnedHeaderListAdapter.java b/src/com/android/contacts/widget/PinnedHeaderListAdapter.java
similarity index 78%
rename from src/com/android/contacts/list/PinnedHeaderListAdapter.java
rename to src/com/android/contacts/widget/PinnedHeaderListAdapter.java
index 27deef3..db99e14 100644
--- a/src/com/android/contacts/list/PinnedHeaderListAdapter.java
+++ b/src/com/android/contacts/widget/PinnedHeaderListAdapter.java
@@ -13,10 +13,7 @@
  * 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;
@@ -35,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) {
@@ -131,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);
@@ -162,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 24e5638..80db26f 100644
--- a/src/com/android/contacts/widget/PinnedHeaderListView.java
+++ b/src/com/android/contacts/widget/PinnedHeaderListView.java
@@ -20,6 +20,7 @@
 import android.graphics.Canvas;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.AbsListView;
 import android.widget.ListAdapter;
 import android.widget.ListView;
@@ -53,6 +54,11 @@
         public static final int PINNED_HEADER_PUSHED_UP = 2;
 
         /**
+         * Creates the pinned header view.
+         */
+        View createPinnedHeaderView(ViewGroup parent);
+
+        /**
          * Computes the desired state of the pinned header for the given
          * position of the first visible list item. Allowed return values are
          * {@link #PINNED_HEADER_GONE}, {@link #PINNED_HEADER_VISIBLE} or
@@ -75,13 +81,14 @@
     private PinnedHeaderAdapter mAdapter;
     private View mHeaderView;
     private boolean mHeaderViewVisible;
-
+    private float mHeaderOffset;
     private int mHeaderViewWidth;
-
     private int mHeaderViewHeight;
 
     private OnScrollListener mOnScrollListener;
 
+    private boolean mHeaderViewConfigured;
+
     public PinnedHeaderListView(Context context) {
         super(context);
     }
@@ -105,6 +112,7 @@
         if (mHeaderView != null) {
             setFadingEdgeLength(0);
         }
+        mHeaderViewConfigured = false;
         requestLayout();
     }
 
@@ -112,6 +120,8 @@
     public void setAdapter(ListAdapter adapter) {
         super.setAdapter(adapter);
         mAdapter = (PinnedHeaderAdapter)adapter;
+        View headerView = mAdapter.createPinnedHeaderView(this);
+        setPinnedHeaderView(headerView);
     }
 
     @Override
@@ -124,7 +134,9 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         if (mHeaderView != null) {
-            configureHeaderView(getFirstVisiblePosition());
+            if (!mHeaderViewConfigured) {
+                configureHeaderView(getFirstVisiblePosition() - getHeaderViewsCount());
+            }
             measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);
             mHeaderViewWidth = mHeaderView.getMeasuredWidth();
             mHeaderViewHeight = mHeaderView.getMeasuredHeight();
@@ -135,13 +147,16 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         if (mHeaderView != null) {
+            if (!mHeaderViewConfigured) {
+                configureHeaderView(getFirstVisiblePosition() - getHeaderViewsCount());
+            }
             mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
         }
     }
 
     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
             int totalItemCount) {
-        configureHeaderView(firstVisibleItem);
+        configureHeaderView(firstVisibleItem - getHeaderViewsCount());
         if (mOnScrollListener != null) {
             mOnScrollListener.onScroll(this, firstVisibleItem, visibleItemCount, totalItemCount);
         }
@@ -167,9 +182,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;
             }
@@ -177,10 +190,9 @@
             case PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP: {
                 View firstView = getChildAt(0);
                 int bottom = firstView.getBottom();
-                int itemHeight = firstView.getHeight();
-                int headerHeight = mHeaderView.getHeight();
-                int y;
+                int headerHeight = mHeaderViewHeight;
                 int alpha;
+                int y;
                 if (bottom < headerHeight) {
                     y = (bottom - headerHeight);
                     alpha = MAX_ALPHA * (headerHeight + y) / headerHeight;
@@ -189,20 +201,22 @@
                     alpha = MAX_ALPHA;
                 }
                 mAdapter.configurePinnedHeader(mHeaderView, position, alpha);
-                if (mHeaderView.getTop() != y) {
-                    mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight + y);
-                }
+                mHeaderOffset = y;
                 mHeaderViewVisible = true;
                 break;
             }
         }
+        mHeaderViewConfigured = true;
     }
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
         super.dispatchDraw(canvas);
         if (mHeaderViewVisible) {
+            canvas.save();
+            canvas.translate(0, mHeaderOffset);
             drawChild(canvas, mHeaderView, getDrawingTime());
+            canvas.restore();
         }
     }
 }