Restoring Strequents in Contacts

Call button will come back in the next CL.

Change-Id: I98b1991f7ac4cd12a252090634874ef90551e96f
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 c963b83..0614772 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -15,27 +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;
-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 ContactBrowseListFragment extends ContactEntryListFragment<ContactListAdapter> {
+public abstract class ContactBrowseListFragment extends
+        ContactEntryListFragment<ContactListAdapter> {
 
     private OnContactBrowserActionListener mListener;
-    private boolean mEditMode;
-    private boolean mCreateContactEnabled;
 
     private CursorLoader mLoader;
 
@@ -45,6 +38,10 @@
         return mLoader;
     }
 
+    public CursorLoader getLoader() {
+        return mLoader;
+    }
+
     @Override
     protected void reloadData() {
         getAdapter().configureLoader(mLoader);
@@ -66,107 +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);
-        }
-    }
-
-    @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;
+    public void searchAllContacts() {
+        mListener.onSearchAllContactsAction((String)null);
     }
 
     public void viewContact(Uri contactUri) {
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);
+    }
+}