Merge "Make multi import one request"
diff --git a/res/layout-xlarge/people_activity.xml b/res/layout-xlarge/people_activity.xml
index 997ed21..3fbb3d2 100644
--- a/res/layout-xlarge/people_activity.xml
+++ b/res/layout-xlarge/people_activity.xml
@@ -43,12 +43,28 @@
                 android:layout_marginLeft="40dip"
                 android:layout_marginTop="24dip" />
 
+            <!-- Favorites -->
             <fragment
-                android:id="@+id/list_fragment"
+                android:id="@+id/favorites_fragment"
+                class="com.android.contacts.list.StrequentContactListFragment"
+                android:layout_height="match_parent"
+                android:layout_width="match_parent" />
+
+            <!-- Contacts -->
+            <fragment
+                android:id="@+id/contacts_fragment"
                 class="com.android.contacts.list.DefaultContactBrowseListFragment"
                 android:layout_height="0dip"
                 android:layout_width="match_parent"
-                android:layout_weight="1" 
+                android:layout_weight="1"
+            />
+
+            <!-- Groups -->
+            <fragment
+                android:id="@+id/groups_fragment"
+                class="com.android.contacts.group.GroupBrowseListFragment"
+                android:layout_height="match_parent"
+                android:layout_width="match_parent"
             />
         </LinearLayout>
 
diff --git a/res/layout/call_log_contact_photo.xml b/res/layout/call_log_contact_photo.xml
new file mode 100644
index 0000000..b8262ad
--- /dev/null
+++ b/res/layout/call_log_contact_photo.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <ImageView
+        android:id="@+id/contact_photo"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+    />
+</merge>
diff --git a/res/layout/call_log_list_group_item.xml b/res/layout/call_log_list_group_item.xml
index d1bd165..c922540 100644
--- a/res/layout/call_log_list_group_item.xml
+++ b/res/layout/call_log_list_group_item.xml
@@ -20,6 +20,7 @@
     android:paddingLeft="7dip"
 >
 
+    <include layout="@layout/call_log_contact_photo"/>
     <include layout="@layout/call_log_action_group"/>
 
     <TextView android:id="@+id/date"
@@ -39,7 +40,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_alignParentBottom="true"
-        android:layout_marginLeft="36dip"
+        android:layout_marginLeft="86dip"
         android:layout_marginRight="5dip"
         android:layout_alignBaseline="@id/date"
 
@@ -84,7 +85,7 @@
         android:layout_toLeftOf="@+id/groupSize"
         android:layout_above="@id/date"
         android:layout_alignWithParentIfMissing="true"
-        android:layout_marginLeft="36dip"
+        android:layout_marginLeft="86dip"
         android:layout_marginBottom="-10dip"
 
         android:textAppearance="?android:attr/textAppearanceLarge"
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index 10e09a4..88a1ba1 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -20,6 +20,7 @@
     android:paddingLeft="7dip"
 >
 
+    <include layout="@layout/call_log_contact_photo"/>
     <include layout="@layout/call_log_action_call"/>
     <include layout="@layout/call_log_list_item_layout"/>
 
diff --git a/res/layout/call_log_list_item_layout.xml b/res/layout/call_log_list_item_layout.xml
index 8096ee6..2128a79 100644
--- a/res/layout/call_log_list_item_layout.xml
+++ b/res/layout/call_log_list_item_layout.xml
@@ -19,9 +19,9 @@
     <ImageView android:id="@+id/call_type_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentTop="true"
+        android:layout_alignParentBottom="true"
         android:layout_alignParentLeft="true"
-        android:layout_marginLeft="4dip"
+        android:layout_marginLeft="54dip"
     />
 
     <TextView android:id="@+id/date"
@@ -41,7 +41,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_alignParentBottom="true"
-        android:layout_marginLeft="36dip"
+        android:layout_marginLeft="86dip"
         android:layout_marginRight="5dip"
         android:layout_alignBaseline="@id/date"
 
@@ -72,7 +72,7 @@
         android:layout_toLeftOf="@id/divider"
         android:layout_above="@id/date"
         android:layout_alignWithParentIfMissing="true"
-        android:layout_marginLeft="36dip"
+        android:layout_marginLeft="86dip"
         android:layout_marginBottom="-10dip"
 
         android:textAppearance="?android:attr/textAppearanceLarge"
diff --git a/res/layout/people_activity.xml b/res/layout/people_activity.xml
index 8affd46..bcf218b 100644
--- a/res/layout/people_activity.xml
+++ b/res/layout/people_activity.xml
@@ -18,17 +18,30 @@
     android:id="@+id/list_container"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <FrameLayout
-        android:id="@+id/main_view"
+
+    <!-- Favorites -->
+    <fragment
+        android:id="@+id/favorites_fragment"
+        class="com.android.contacts.list.StrequentContactListFragment"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent" />
+
+    <!-- Contacts -->
+    <fragment
+        android:id="@+id/contacts_fragment"
+        class="com.android.contacts.list.DefaultContactBrowseListFragment"
+        android:layout_height="match_parent"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
-        <fragment
-            android:id="@+id/list_fragment"
-            class="com.android.contacts.list.DefaultContactBrowseListFragment"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-        />
-    </FrameLayout>
+    />
+
+    <!-- Groups -->
+    <fragment
+        android:id="@+id/groups_fragment"
+        class="com.android.contacts.group.GroupBrowseListFragment"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+    />
+
     <FrameLayout
         android:id="@+id/contacts_unavailable_view"
         android:layout_width="match_parent"
diff --git a/res/menu/actions.xml b/res/menu/actions.xml
index a53967f..083d352 100644
--- a/res/menu/actions.xml
+++ b/res/menu/actions.xml
@@ -15,10 +15,20 @@
 -->
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
+        android:id="@+id/menu_search"
+        android:showAsAction="always"
+        android:actionViewClass="android.widget.SearchView" />
+
+    <item
         android:id="@+id/menu_add"
         android:showAsAction="always" />
 
     <item
+        android:id="@+id/menu_contacts_filter"
+        android:icon="@drawable/ic_menu_settings_holo_light"
+        android:title="@string/menu_contacts_filter" />
+
+    <item
         android:id="@+id/menu_settings"
         android:icon="@drawable/ic_menu_settings_holo_light"
         android:title="@string/menu_settings" />
diff --git a/res/values-xlarge/styles.xml b/res/values-xlarge/styles.xml
index d44d993..9d0ff29 100644
--- a/res/values-xlarge/styles.xml
+++ b/res/values-xlarge/styles.xml
@@ -36,6 +36,7 @@
         <item name="list_item_header_text_color">?color/section_header_text_color</item>
         <item name="list_item_header_text_size">14sp</item>
         <item name="contact_filter_popup_width">320dip</item>
+        <item name="show_home_icon">true</item>
     </style>
 
     <style name="ContactPickerTheme" parent="@android:Theme.Holo.Light.Dialog">
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2f9acb4..7e7e8b5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -993,6 +993,9 @@
     <!-- The menu item to open the list of accounts -->
     <string name="menu_accounts">Accounts</string>
 
+    <!-- The menu item to filter the list of contacts displayed -->
+    <string name="menu_contacts_filter">Contacts to display</string>
+
     <!-- The menu item to bulk import or bulk export contacts from SIM card or SD card. -->
     <string name="menu_import_export">Import/Export</string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index df8b808..3f9986c 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -107,7 +107,12 @@
         <attr name="list_item_header_text_size" format="dimension" />
     </declare-styleable>
 
-    <style name="PeopleTheme" parent="@android:Theme">
+    <!-- This style defines visibility of the action bar home icon -->
+    <declare-styleable name="ActionBarHomeIcon">
+        <attr name="show_home_icon" format="boolean"/>
+    </declare-styleable>
+
+    <style name="PeopleTheme" parent="android:Theme.Holo.Light">
         <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
         <item name="activated_background">@drawable/list_item_activated_background</item>
         <item name="section_header_background">@drawable/list_title_holo</item>
@@ -128,6 +133,7 @@
         <item name="list_item_header_text_color">?color/section_header_text_color</item>
         <item name="list_item_header_text_size">14sp</item>
         <item name="contact_filter_popup_width">320dip</item>
+        <item name="show_home_icon">false</item>
     </style>
 
     <!-- TODO: Clean up this file so themes aren't copied. -->
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 7ca5921..680c8bd 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -17,22 +17,18 @@
 package com.android.contacts.activities;
 
 import com.android.contacts.R;
+import com.android.contacts.activities.ActionBarAdapter.Listener.Action;
 import com.android.contacts.list.ContactListFilterController;
 import com.android.contacts.list.ContactListFilterController.ContactListFilterListener;
-import com.android.contacts.list.ContactListFilterView;
 import com.android.contacts.list.ContactsRequest;
 
 import android.app.ActionBar;
-import android.app.ActionBar.LayoutParams;
 import android.content.Context;
 import android.os.Bundle;
 import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
 import android.widget.SearchView;
 import android.widget.SearchView.OnCloseListener;
 import android.widget.SearchView.OnQueryTextListener;
-import android.widget.TextView;
 
 /**
  * Adapter for the action bar at the top of the Contacts activity.
@@ -41,7 +37,11 @@
         implements OnQueryTextListener, OnCloseListener, ContactListFilterListener {
 
     public interface Listener {
-        void onAction();
+        public enum Action {
+            CHANGE_SEARCH_QUERY, START_SEARCH_MODE, STOP_SEARCH_MODE
+        }
+
+        void onAction(Action action);
     }
 
     private static final String EXTRA_KEY_SEARCH_MODE = "navBar.searchMode";
@@ -50,24 +50,25 @@
     private boolean mSearchMode;
     private String mQueryString;
 
-    private View mNavigationBar;
-    private TextView mSearchLabel;
+    private String mSearchLabelText;
     private SearchView mSearchView;
 
     private final Context mContext;
 
     private Listener mListener;
-    private ContactListFilterView mFilterView;
     private ContactListFilterController mFilterController;
 
-    private boolean mEnabled;
+    private ActionBar mActionBar;
 
     public ActionBarAdapter(Context context) {
         mContext = context;
+        mSearchLabelText = mContext.getString(R.string.search_label);
     }
 
     public void onCreate(Bundle savedState, ContactsRequest request, ActionBar actionBar) {
+        mActionBar = actionBar;
         mQueryString = null;
+
         if (savedState != null) {
             mSearchMode = savedState.getBoolean(EXTRA_KEY_SEARCH_MODE);
             mQueryString = savedState.getString(EXTRA_KEY_QUERY);
@@ -76,33 +77,18 @@
             mQueryString = request.getQueryString();
         }
 
-        if (actionBar != null) {
-            actionBar.setDisplayOptions(
-                    ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM);
+        if (mSearchView != null) {
+            mSearchView.setQuery(mQueryString, false);
         }
 
-        mNavigationBar = LayoutInflater.from(mContext).inflate(R.layout.navigation_bar, null);
-        LayoutParams layoutParams = new LayoutParams(
-                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-        if (actionBar != null) {
-            actionBar.setCustomView(mNavigationBar, layoutParams);
-        }
-
-        mFilterView = (ContactListFilterView) mNavigationBar.findViewById(R.id.filter_view);
-        mSearchLabel = (TextView) mNavigationBar.findViewById(R.id.search_label);
-        mSearchView = (SearchView) mNavigationBar.findViewById(R.id.search_view);
-
-        mSearchView.setOnQueryTextListener(this);
-        mSearchView.setOnCloseListener(this);
-        mSearchView.setQuery(mQueryString, false);
-        mSearchView.setQueryHint(mContext.getString(R.string.hint_findContacts));
-
         update();
     }
 
-    public void setEnabled(boolean enabled) {
-        mEnabled = enabled;
-        update();
+    public void setSearchView(SearchView searchView) {
+        mSearchView = searchView;
+        mSearchView.setOnQueryTextListener(this);
+        mSearchView.setOnCloseListener(this);
+        mSearchView.setQuery(mQueryString, false);
     }
 
     public void setListener(Listener listener) {
@@ -111,7 +97,6 @@
 
     public void setContactListFilterController(ContactListFilterController controller) {
         mFilterController = controller;
-        mFilterController.setAnchor(mFilterView);
         mFilterController.addListener(this);
     }
 
@@ -128,9 +113,6 @@
             } else {
                 mSearchView.setQuery(null, false);
             }
-            if (mListener != null) {
-                mListener.onAction();
-            }
         }
     }
 
@@ -144,39 +126,36 @@
     }
 
     public void update() {
-        if (!mEnabled) {
-            mNavigationBar.setVisibility(View.GONE);
-        } else if (mSearchMode) {
-            mNavigationBar.setVisibility(View.VISIBLE);
-            mSearchLabel.setVisibility(View.VISIBLE);
-            mFilterView.setVisibility(View.GONE);
-            if (mFilterController != null) {
-                mFilterController.setEnabled(false);
+        if (mSearchMode) {
+            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+            mActionBar.setTitle(mSearchLabelText);
+            if (mListener != null) {
+                mListener.onAction(Action.START_SEARCH_MODE);
             }
         } else {
-            mNavigationBar.setVisibility(View.VISIBLE);
-            mSearchLabel.setVisibility(View.GONE);
-            mFilterView.setVisibility(View.VISIBLE);
-            if (mFilterController != null){
-                mFilterController.setEnabled(true);
-                if (mFilterController.isLoaded()) {
-                    mFilterView.setContactListFilter(mFilterController.getFilter());
-                    mFilterView.setSingleAccount(mFilterController.getAccountCount() == 1);
-                    mFilterView.bindView(false);
-                }
+            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+            mActionBar.setTitle(null);
+            if (mListener != null) {
+                mListener.onAction(Action.STOP_SEARCH_MODE);
             }
         }
     }
 
     @Override
     public boolean onQueryTextChange(String queryString) {
+        // TODO: Clean up SearchView code because it keeps setting the SearchView query,
+        // invoking onQueryChanged, setting up the fragment again, invalidating the options menu,
+        // storing the SearchView again, and etc... unless we add in the early return statements.
+        if (queryString.equals(mQueryString)) {
+            return false;
+        }
         mQueryString = queryString;
         if (!mSearchMode) {
             if (!TextUtils.isEmpty(queryString)) {
                 setSearchMode(true);
             }
         } else if (mListener != null) {
-            mListener.onAction();
+            mListener.onAction(Action.CHANGE_SEARCH_QUERY);
         }
 
         return true;
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 1379e08..f537c9e 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -19,7 +19,10 @@
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.ContactsActivity;
 import com.android.contacts.R;
+import com.android.contacts.calllog.CallLogFragment;
 import com.android.contacts.detail.ContactDetailFragment;
+import com.android.contacts.dialpad.DialpadFragment;
+import com.android.contacts.group.GroupBrowseListFragment;
 import com.android.contacts.interactions.ContactDeletionInteraction;
 import com.android.contacts.interactions.GroupDeletionDialogFragment;
 import com.android.contacts.interactions.GroupRenamingDialogFragment;
@@ -34,11 +37,13 @@
 import com.android.contacts.list.ContactsRequest;
 import com.android.contacts.list.ContactsUnavailableFragment;
 import com.android.contacts.list.CustomContactListFilterActivity;
+import com.android.contacts.list.DefaultContactBrowseListFragment;
 import com.android.contacts.list.DirectoryListLoader;
 import com.android.contacts.list.OnContactBrowserActionListener;
 import com.android.contacts.list.OnContactsUnavailableActionListener;
 import com.android.contacts.list.ProviderStatusLoader;
 import com.android.contacts.list.ProviderStatusLoader.ProviderStatusListener;
+import com.android.contacts.list.StrequentContactListFragment;
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.preference.ContactsPreferenceActivity;
 import com.android.contacts.util.AccountSelectionUtil;
@@ -47,12 +52,17 @@
 
 import android.accounts.Account;
 import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.ActionBar.TabListener;
 import android.app.Activity;
 import android.app.Dialog;
 import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
 import android.content.ActivityNotFoundException;
 import android.content.ContentValues;
 import android.content.Intent;
+import android.content.res.TypedArray;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract;
@@ -68,6 +78,7 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.Window;
+import android.widget.SearchView;
 import android.widget.Toast;
 
 import java.util.ArrayList;
@@ -94,7 +105,6 @@
     private ContactsIntentResolver mIntentResolver;
     private ContactsRequest mRequest;
 
-    private boolean mHasActionBar;
     private ActionBarAdapter mActionBarAdapter;
 
     private boolean mSearchMode;
@@ -126,8 +136,14 @@
     private boolean mOptionsMenuContactsAvailable;
     private boolean mOptionsMenuGroupActionsEnabled;
 
+    private DefaultContactBrowseListFragment mContactsFragment;
+    private StrequentContactListFragment mFavoritesFragment;
+    private GroupBrowseListFragment mGroupsFragment;
+
     public PeopleActivity() {
         mIntentResolver = new ContactsIntentResolver(this);
+        // TODO: Get rid of the ContactListFilterController class because there aren't any
+        // dropdown filters anymore. Just store the selected filter as a member variable.
         mContactListFilterController = new ContactListFilterController(this);
         mContactListFilterController.addListener(this);
         mProviderStatusLoader = new ProviderStatusLoader(this);
@@ -201,6 +217,21 @@
 
         if (createContentView) {
             setContentView(R.layout.people_activity);
+
+            final FragmentManager fragmentManager = getFragmentManager();
+            mFavoritesFragment = (StrequentContactListFragment) fragmentManager
+                    .findFragmentById(R.id.favorites_fragment);
+            mContactsFragment = (DefaultContactBrowseListFragment) fragmentManager
+                    .findFragmentById(R.id.contacts_fragment);
+            mGroupsFragment = (GroupBrowseListFragment) fragmentManager
+                    .findFragmentById(R.id.groups_fragment);
+
+            // Hide all tabs (the current tab will later be reshown once a tab is selected)
+            final FragmentTransaction transaction = fragmentManager.beginTransaction();
+            transaction.hide(mFavoritesFragment);
+            transaction.hide(mContactsFragment);
+            transaction.hide(mGroupsFragment);
+            transaction.commit();
         }
 
         if (mRequest.getActionCode() == ContactsRequest.ACTION_VIEW_CONTACT
@@ -214,21 +245,66 @@
         }
 
         setTitle(mRequest.getActivityTitle());
+        ActionBar actionBar = getActionBar();
+        mActionBarAdapter = new ActionBarAdapter(this);
+        mActionBarAdapter.onCreate(savedState, mRequest, getActionBar());
+        mActionBarAdapter.setContactListFilterController(mContactListFilterController);
 
         if (createContentView) {
-            mHasActionBar = getWindow().hasFeature(Window.FEATURE_ACTION_BAR);
-            if (mHasActionBar) {
-                ActionBar actionBar = getActionBar();
+            actionBar.removeAllTabs();
+            Tab favoritesTab = actionBar.newTab();
+            favoritesTab.setText(getString(R.string.strequentList));
+            favoritesTab.setTabListener(new TabChangeListener(mFavoritesFragment));
+            actionBar.addTab(favoritesTab);
 
-                mActionBarAdapter = new ActionBarAdapter(this);
-                mActionBarAdapter.onCreate(savedState, mRequest, actionBar);
-                mActionBarAdapter.setContactListFilterController(mContactListFilterController);
-            }
+            Tab peopleTab = actionBar.newTab();
+            peopleTab.setText(getString(R.string.people));
+            peopleTab.setTabListener(new TabChangeListener(mContactsFragment));
+            actionBar.addTab(peopleTab);
+
+            Tab groupsTab = actionBar.newTab();
+            groupsTab.setText(getString(R.string.contactsGroupsLabel));
+            groupsTab.setTabListener(new TabChangeListener(mGroupsFragment));
+            actionBar.addTab(groupsTab);
+            actionBar.setDisplayShowTitleEnabled(true);
+
+            TypedArray a = obtainStyledAttributes(null, R.styleable.ActionBarHomeIcon);
+            boolean showHomeIcon = a.getBoolean(R.styleable.ActionBarHomeIcon_show_home_icon, true);
+            actionBar.setDisplayShowHomeEnabled(showHomeIcon);
+
+            invalidateOptionsMenu();
         }
 
         configureFragments(savedState == null);
     }
 
+    /**
+     * Tab change listener that is instantiated once for each tab. Handles showing/hiding fragments.
+     * TODO: Use ViewPager so that tabs can be swiped left and right. Figure out how to use the
+     * support library in our app.
+     */
+    private class TabChangeListener implements TabListener {
+        private final Fragment mFragment;
+
+        public TabChangeListener(Fragment fragment) {
+            mFragment = fragment;
+        }
+
+        @Override
+        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
+            ft.hide(mFragment);
+        }
+
+        @Override
+        public void onTabSelected(Tab tab, FragmentTransaction ft) {
+            ft.show(mFragment);
+        }
+
+        @Override
+        public void onTabReselected(Tab tab, FragmentTransaction ft) {
+        }
+    }
+
     @Override
     protected void onPause() {
         if (mActionBarAdapter != null) {
@@ -259,12 +335,6 @@
         super.onStart();
     }
 
-    @Override
-    protected void onStop() {
-        mContactListFilterController.onStop();
-        super.onStop();
-    }
-
     private void configureFragments(boolean fromRequest) {
         if (fromRequest) {
             ContactListFilter filter = null;
@@ -303,7 +373,7 @@
             mListFragment.setContactsRequest(mRequest);
             configureListFragmentForRequest();
 
-        } else if (mHasActionBar) {
+        } else {
             mSearchMode = mActionBarAdapter.isSearchMode();
         }
 
@@ -348,9 +418,23 @@
      * Handler for action bar actions.
      */
     @Override
-    public void onAction() {
-        configureFragments(false /* from request */);
-        mListFragment.setQueryString(mActionBarAdapter.getQueryString(), true);
+    public void onAction(Action action) {
+        switch (action) {
+            case START_SEARCH_MODE:
+                // Bring the contact list fragment to the front.
+                FragmentTransaction ft = getFragmentManager().beginTransaction();
+                ft.show(mContactsFragment);
+                ft.commit();
+                break;
+            case STOP_SEARCH_MODE:
+            case CHANGE_SEARCH_QUERY:
+                // Refresh the contact list fragment.
+                configureFragments(false /* from request */);
+                mListFragment.setQueryString(mActionBarAdapter.getQueryString(), true);
+                break;
+            default:
+                throw new IllegalStateException("Unkonwn ActionBarAdapter action: " + action);
+        }
     }
 
     private void configureListFragmentForRequest() {
@@ -403,17 +487,13 @@
 
         if (mProviderStatus == ProviderStatus.STATUS_NORMAL) {
             contactsUnavailableView.setVisibility(View.GONE);
-            mainView.setVisibility(View.VISIBLE);
+            if (mainView != null) {
+                mainView.setVisibility(View.VISIBLE);
+            }
             if (mListFragment != null) {
                 mListFragment.setEnabled(true);
             }
-            if (mHasActionBar) {
-                mActionBarAdapter.setEnabled(true);
-            }
         } else {
-            if (mHasActionBar) {
-                mActionBarAdapter.setEnabled(false);
-            }
             if (mListFragment != null) {
                 mListFragment.setEnabled(false);
             }
@@ -429,7 +509,9 @@
                 mContactsUnavailableFragment.update();
             }
             contactsUnavailableView.setVisibility(View.VISIBLE);
-            mainView.setVisibility(View.INVISIBLE);
+            if (mainView != null) {
+                mainView.setVisibility(View.INVISIBLE);
+            }
         }
 
         invalidateOptionsMenu();
@@ -625,27 +707,28 @@
         if (!areContactsAvailable()) {
             return false;
         }
-
         super.onCreateOptionsMenu(menu);
 
         MenuInflater inflater = getMenuInflater();
-        if (mHasActionBar) {
-            inflater.inflate(R.menu.actions, menu);
+        inflater.inflate(R.menu.actions, menu);
+        // TODO: Figure out if R.menu.list or R.menu.search are necessary according to the overflow
+        // menus on the UX mocks.
+        MenuItem searchMenuItem = menu.findItem(R.id.menu_search);
+        if (searchMenuItem != null && searchMenuItem.getActionView() instanceof SearchView) {
+            SearchView searchView = (SearchView) searchMenuItem.getActionView();
+            searchView.setQueryHint(getString(R.string.hint_findContacts));
+            searchView.setIconifiedByDefault(false);
 
-            // Change add contact button to button with a custom view
-            final MenuItem addContact = menu.findItem(R.id.menu_add);
-            addContact.setActionView(mAddContactImageView);
-            return true;
-        } else if (mRequest.getActionCode() == ContactsRequest.ACTION_ALL_CONTACTS ||
-                mRequest.getActionCode() == ContactsRequest.ACTION_STREQUENT) {
-            inflater.inflate(R.menu.list, menu);
-            return true;
-        } else if (!mListFragment.isSearchMode()) {
-            inflater.inflate(R.menu.search, menu);
-            return true;
-        } else {
-            return false;
+            if (mActionBarAdapter != null) {
+                mActionBarAdapter.setSearchView(searchView);
+            }
         }
+
+        // TODO: Can remove this as a custom view because the account selector is in the editor now.
+        // Change add contact button to button with a custom view
+        final MenuItem addContact = menu.findItem(R.id.menu_add);
+        addContact.setActionView(mAddContactImageView);
+        return true;
     }
 
     @Override
@@ -723,6 +806,11 @@
                 startActivity(intent);
                 return true;
             }
+            case R.id.menu_contacts_filter: {
+                final Intent intent = new Intent(this, CustomContactListFilterActivity.class);
+                startActivityForResult(intent, SUBACTIVITY_CUSTOMIZE_FILTER);
+                return true;
+            }
             case R.id.menu_search: {
                 onSearchRequested();
                 return true;
@@ -865,12 +953,10 @@
                 final int unicodeChar = event.getUnicodeChar();
                 if (unicodeChar != 0 && !Character.isWhitespace(unicodeChar)) {
                     String query = new String(new int[]{ unicodeChar }, 0, 1);
-                    if (mHasActionBar) {
-                        if (!mActionBarAdapter.isSearchMode()) {
-                            mActionBarAdapter.setQueryString(query);
-                            mActionBarAdapter.setSearchMode(true);
-                            return true;
-                        }
+                    if (!mActionBarAdapter.isSearchMode()) {
+                        mActionBarAdapter.setQueryString(query);
+                        mActionBarAdapter.setSearchMode(true);
+                        return true;
                     } else if (!mRequest.isSearchMode()) {
                         if (!mSearchInitiated) {
                             mSearchInitiated = true;
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 79e9ae5..eff5c41 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -18,6 +18,7 @@
 
 import com.android.common.widget.GroupingListAdapter;
 import com.android.contacts.CallDetailActivity;
+import com.android.contacts.ContactPhotoManager;
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
 import com.android.internal.telephony.CallerInfo;
@@ -111,7 +112,8 @@
                 PhoneLookup.TYPE,
                 PhoneLookup.LABEL,
                 PhoneLookup.NUMBER,
-                PhoneLookup.NORMALIZED_NUMBER};
+                PhoneLookup.NORMALIZED_NUMBER,
+                PhoneLookup.PHOTO_ID};
 
         public static final int PERSON_ID = 0;
         public static final int NAME = 1;
@@ -119,6 +121,7 @@
         public static final int LABEL = 3;
         public static final int MATCHED_NUMBER = 4;
         public static final int NORMALIZED_NUMBER = 5;
+        public static final int PHOTO_ID = 6;
     }
 
     private static final class MenuItems {
@@ -146,6 +149,7 @@
         public String number;
         public String formattedNumber;
         public String normalizedNumber;
+        public long photoId;
 
         public static ContactInfo EMPTY = new ContactInfo();
     }
@@ -165,6 +169,8 @@
          * entries.
          */
         public TextView groupSize;
+        /** The contact photo for the contact. Only present for group and stand alone entries. */
+        public ImageView photoView;
     }
 
     public static final class CallerInfoQuery {
@@ -173,6 +179,7 @@
         public String name;
         public int numberType;
         public String numberLabel;
+        public long photoId;
     }
 
     /** Adapter class to fill in data for the Call Log */
@@ -197,6 +204,8 @@
          */
         private CharArrayBuffer mBuffer1 = new CharArrayBuffer(128);
         private CharArrayBuffer mBuffer2 = new CharArrayBuffer(128);
+        /** Helper to set up contact photos. */
+        private final ContactPhotoManager mContactPhotoManager;
 
         @Override
         public void onClick(View view) {
@@ -251,6 +260,8 @@
                     R.drawable.ic_call_log_list_outgoing_call);
             mDrawableMissed = getResources().getDrawable(
                     R.drawable.ic_call_log_list_missed_call);
+
+            mContactPhotoManager = ContactPhotoManager.getInstance(getActivity());
         }
 
         /**
@@ -311,7 +322,8 @@
             // Check if they are different. If not, don't update.
             if (TextUtils.equals(ciq.name, ci.name)
                     && TextUtils.equals(ciq.numberLabel, ci.label)
-                    && ciq.numberType == ci.type) {
+                    && ciq.numberType == ci.type
+                    && ciq.photoId == ci.photoId) {
                 return;
             }
             ContentValues values = new ContentValues(3);
@@ -332,13 +344,14 @@
         }
 
         private void enqueueRequest(String number, int position,
-                String name, int numberType, String numberLabel) {
+                String name, int numberType, String numberLabel, long photoId) {
             CallerInfoQuery ciq = new CallerInfoQuery();
             ciq.number = number;
             ciq.position = position;
             ciq.name = name;
             ciq.numberType = numberType;
             ciq.numberLabel = numberLabel;
+            ciq.photoId = photoId;
             synchronized (mRequests) {
                 mRequests.add(ciq);
                 mRequests.notifyAll();
@@ -414,6 +427,8 @@
                             info.number = dataTableCursor.getString(
                                     dataTableCursor.getColumnIndex(Data.DATA1));
                             info.normalizedNumber = null;  // meaningless for SIP addresses
+                            info.photoId = dataTableCursor.getLong(
+                                    dataTableCursor.getColumnIndex(Data.PHOTO_ID));
 
                             infoUpdated = true;
                         }
@@ -438,6 +453,7 @@
                                     .getString(PhoneQuery.MATCHED_NUMBER);
                             info.normalizedNumber = phonesCursor
                                     .getString(PhoneQuery.NORMALIZED_NUMBER);
+                            info.photoId = phonesCursor.getLong(PhoneQuery.PHOTO_ID);
 
                             infoUpdated = true;
                         }
@@ -624,6 +640,7 @@
             }
             views.groupIndicator = (ImageView) view.findViewById(R.id.groupIndicator);
             views.groupSize = (TextView) view.findViewById(R.id.groupSize);
+            views.photoView = (ImageView) view.findViewById(R.id.contact_photo);
             view.setTag(views);
         }
 
@@ -649,7 +666,7 @@
                 info = ContactInfo.EMPTY;
                 mContactInfo.put(number, info);
                 enqueueRequest(number, c.getPosition(),
-                        callerName, callerNumberType, callerNumberLabel);
+                        callerName, callerNumberType, callerNumberLabel, 0L);
             } else if (info != ContactInfo.EMPTY) { // Has been queried
                 // Check if any data is different from the data cached in the
                 // calls db. If so, queue the request so that we can update
@@ -659,7 +676,7 @@
                         || !TextUtils.equals(info.label, callerNumberLabel)) {
                     // Something is amiss, so sync up.
                     enqueueRequest(number, c.getPosition(),
-                            callerName, callerNumberType, callerNumberLabel);
+                            callerName, callerNumberType, callerNumberLabel, info.photoId);
                 }
 
                 // Format and cache phone number for found contact
@@ -673,6 +690,7 @@
             String name = info.name;
             int ntype = info.type;
             String label = info.label;
+            long photoId = info.photoId;
             // If there's no name cached in our hashmap, but there's one in the
             // calls db, use the one in the calls db. Otherwise the name in our
             // hashmap is more recent, so it has precedence.
@@ -759,6 +777,10 @@
                 views.labelView.setVisibility(View.GONE);
             }
 
+            if (views.photoView != null) {
+                mContactPhotoManager.loadPhoto(views.photoView, photoId);
+            }
+
             long date = c.getLong(CallLogQuery.DATE);
 
             // Set the date/time field by mixing relative and absolute times.
diff --git a/src/com/android/contacts/list/ContactListFilterController.java b/src/com/android/contacts/list/ContactListFilterController.java
index c9f5530..4da5baa 100644
--- a/src/com/android/contacts/list/ContactListFilterController.java
+++ b/src/com/android/contacts/list/ContactListFilterController.java
@@ -43,6 +43,8 @@
 /**
  * Controls a list of {@link ContactListFilter}'s.
  */
+// TODO: Remove the extra functionality dealing with loading and displaying a list of filters in
+// the action bar.
 public class ContactListFilterController
         implements LoaderCallbacks<List<ContactListFilter>>, OnClickListener, OnItemClickListener {
 
@@ -84,11 +86,6 @@
         mListeners.remove(listener);
     }
 
-    public void setAnchor(View anchor) {
-        mAnchor = anchor;
-        mAnchor.setOnClickListener(this);
-    }
-
     public ContactListFilter getFilter() {
         return mFilter;
     }
@@ -105,11 +102,6 @@
         if (mFilter == null) {
             mFilter = ContactListFilter.restoreFromPreferences(getSharedPreferences());
         }
-        mLoaderManager.initLoader(R.id.contact_list_filter_loader, null, this);
-    }
-
-    public void onStop() {
-        mLoaderManager.destroyLoader(R.id.contact_list_filter_loader);
     }
 
     private SharedPreferences getSharedPreferences() {