Merge "Hookup search in the UI."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0259a28..6641114 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -33,6 +33,9 @@
         android:icon="@mipmap/ic_launcher_mail"
         android:label="@string/app_name"
         android:theme="@style/UnifiedEmailTheme" >
+        <!-- Enable search in all activities -->
+        <meta-data android:name="android.app.default_searchable"
+            android:value=".ui.MailActivity" />
         <!-- TODO: add a permission on this -->
         <activity
             android:label="@string/app_name"
@@ -48,6 +51,11 @@
                 <data android:scheme="content"/>
                 <data android:mimeType="application/mail-ls" />
             </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.SEARCH" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
         </activity>
         <activity android:name=".compose.ComposeActivity">
             <intent-filter>
diff --git a/res/layout-sw600dp/actionbar_view.xml b/res/layout-sw600dp/actionbar_view.xml
index 3a4f37d..ef66230 100644
--- a/res/layout-sw600dp/actionbar_view.xml
+++ b/res/layout-sw600dp/actionbar_view.xml
@@ -16,7 +16,7 @@
      limitations under the License.
 -->
 
-<com.android.mail.ui.MailActionBar
+<com.android.mail.ui.ActionBarView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:email="http://schemas.android.com/apk/res/com.android.mail"
     android:orientation="horizontal"
@@ -30,4 +30,4 @@
 
     <include layout="@layout/actionbar_subject" />
 
-</com.android.mail.ui.MailActionBar>
+</com.android.mail.ui.ActionBarView>
diff --git a/res/layout/actionbar_view.xml b/res/layout/actionbar_view.xml
index 4d658c0..eae0e18 100644
--- a/res/layout/actionbar_view.xml
+++ b/res/layout/actionbar_view.xml
@@ -20,7 +20,7 @@
      The custom action bar view Gmail uses (containing drop down account spinner,
     label, and subject).
 -->
-<com.android.mail.ui.MailActionBar xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.mail.ui.ActionBarView xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:email="http://schemas.android.com/apk/res/com.android.mail"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -30,4 +30,4 @@
 
     <include layout="@layout/actionbar_subject" />
 
-</com.android.mail.ui.MailActionBar>
+</com.android.mail.ui.ActionBarView>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 85adc73..b9b6b60 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -201,9 +201,6 @@
     <!-- Attachment description for unknown files [CHAR LIMIT=30]-->
     <string name="attachment_unknown"><xliff:g id="attachmentExtension">%s</xliff:g> File</string>
 
-    <!-- Shown in light gray in the Search box when no text has been entered [CHAR LIMIT=30] -->
-    <string name="search_hint">Search mail</string>
-
     <!-- Webview Context Menu Strings -->
     <!-- Title of dialog for choosing which activity to share a link with. [CHAR LIMIT=50]-->
     <string name="choosertitle_sharevia">Share via</string>
@@ -513,7 +510,6 @@
     </plurals>
     <!-- Manage folders mode, sync option: don't synchronize any conversation with this folder [CHAR LIMIT=100] -->
     <string name="sync_none">Sync: None</string>
-
     <!-- Title for dialog encouraging users enable sync for a currently non-synced folder [CHAR LIMIT=30] -->
     <string name="folder_sync_for_widget_title">Sync folder</string>
 
@@ -526,4 +522,12 @@
     <!-- Folder selection dialog -->
     <!-- Title for change folders dialog [CHAR LIMIT=30] -->
     <string name="folder_selection_dialog_title">Change folders</string>
+
+    <!-- Search -->
+    <!-- Title of the search dialog -->
+    <string name="search_title" translatable="false">Unified Email</string>
+    <!-- Shown in light gray in the Search box when no text has been entered [CHAR LIMIT=20]-->
+    <string name="search_hint">Search mail</string>
+    <!-- Search Results: Text for status of the search when the results are completely loaded [CHAR LIMIT=10] -->
+    <string name="search_results_loaded"><xliff:g id="searchCount">%1$d</xliff:g></string>
 </resources>
diff --git a/res/xml/searchable.xml b/res/xml/searchable.xml
new file mode 100644
index 0000000..66a07c2
--- /dev/null
+++ b/res/xml/searchable.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2012 Google Inc.
+     Licensed to 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.
+-->
+<searchable xmlns:android="http://schemas.android.com/apk/res/android"
+    android:label="@string/search_title"
+    android:hint="@string/search_hint"
+    android:icon="@drawable/ic_menu_search_holo_light"
+    android:searchSuggestIntentAction="android.intent.action.SEARCH"
+    android:imeOptions="actionSearch"
+    android:searchSuggestSelection="query LIKE ?" />
diff --git a/src/com/android/mail/ConversationListContext.java b/src/com/android/mail/ConversationListContext.java
index fa6bbb0..0bda52e 100644
--- a/src/com/android/mail/ConversationListContext.java
+++ b/src/com/android/mail/ConversationListContext.java
@@ -23,10 +23,14 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
+import android.text.TextUtils;
+
 import com.android.mail.providers.Account;
 import com.android.mail.providers.Folder;
 import com.android.mail.providers.Settings;
 import com.android.mail.providers.UIProvider;
+import com.android.mail.utils.Utils;
+import com.google.common.base.Preconditions;
 
 import java.util.ArrayList;
 
@@ -43,7 +47,7 @@
 public class ConversationListContext {
     private static final String EXTRA_ACCOUNT = "account";
     public static final String EXTRA_FOLDER = "folder";
-    private static final String EXTRA_SEARCH_QUERY = "query";
+    public static final String EXTRA_SEARCH_QUERY = "query";
 
     /**
      * A matcher for data URI's that specify conversation list info.
@@ -125,36 +129,11 @@
     }
 
     /**
-     * Resolves an intent and builds an appropriate context for it.
+     * Builds a context object for viewing a conversation list for a search query.
      */
-    public static ConversationListContext forIntent(Context context, Account callerAccount,
-            Intent intent) {
-        Account account = callerAccount;
-        String action = intent.getAction();
-        // TODO(viki): Implement the other intents: Intent.SEARCH,
-        // Intent.PROVIDER_CHANGED.
-        if (Intent.ACTION_VIEW.equals(action) && intent.getData() != null) {
-            // TODO(viki): Look through the URI to find the account and the
-            // folder.
-        }
-        Folder folder = (Folder) intent.getParcelableExtra(EXTRA_FOLDER);
-        if (folder == null) {
-            Cursor cursor = null;
-            try {
-                cursor = context.getContentResolver().query(callerAccount.folderListUri,
-                        UIProvider.FOLDERS_PROJECTION, null, null, null);
-                if (cursor != null) {
-                    cursor.moveToFirst();
-                    folder = new Folder(cursor);
-                }
-            } finally {
-                if (cursor != null) {
-                    cursor.close();
-                }
-            }
-
-        }
-        return forFolder(context, account, folder);
+    public static ConversationListContext forSearchQuery(Account account, Folder folder,
+            String query) {
+        return new ConversationListContext(account, Preconditions.checkNotNull(query), folder);
     }
 
     /**
@@ -176,7 +155,7 @@
      * @return true if list is showing search results. False otherwise
      */
     public boolean isSearchResult() {
-        return false;
+        return !TextUtils.isEmpty(searchQuery);
     }
 
     /**
diff --git a/src/com/android/mail/providers/Folder.java b/src/com/android/mail/providers/Folder.java
index 8c730b7..72e3227 100644
--- a/src/com/android/mail/providers/Folder.java
+++ b/src/com/android/mail/providers/Folder.java
@@ -19,6 +19,7 @@
 
 import android.database.Cursor;
 import android.net.Uri;
+import android.net.Uri.Builder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -146,6 +147,8 @@
 
     private static final String FOLDER_SEPARATOR = "^**^";
 
+    public static final Uri SEARCH_RESULTS_URI = Uri.parse("content://fakeSearchResults/");
+
     public Folder(Parcel in) {
         id = in.readString();
         uri = in.readParcelable(null);
@@ -230,6 +233,17 @@
         return out.toString();
     }
 
+    public static Folder forSearchResults(Account account, String query) {
+        Folder searchFolder = new Folder();
+        Builder searchBuilder = account.searchUri.buildUpon();
+        searchBuilder.appendQueryParameter(UIProvider.SearchQueryParameters.QUERY, query);
+        Uri searchUri = searchBuilder.build();
+        searchFolder.uri = SEARCH_RESULTS_URI;
+        searchFolder.conversationListUri = searchUri;
+        searchFolder.refreshUri = searchUri;
+        return searchFolder;
+    }
+
     /**
      * Construct a new Folder instance from a previously serialized string.
      * @param serializedFolder string obtained from {@link #serialize()} on a valid folder.
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 0bf375b..988001d 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -21,6 +21,8 @@
 import android.app.ActionBar.LayoutParams;
 import android.app.Activity;
 import android.app.Dialog;
+import android.app.SearchManager;
+import android.app.SearchableInfo;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.CursorLoader;
@@ -40,6 +42,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.LinearLayout;
+import android.widget.SearchView;
 import android.widget.Toast;
 
 import com.android.mail.R;
@@ -113,7 +116,6 @@
     private AsyncRefreshTask mAsyncRefreshTask;
 
     private MenuItem mRefreshItem;
-    private MenuItem mHelpItem;
     private View mRefreshActionView;
     private boolean mRefreshInProgress;
     private final Handler mHandler = new Handler();
@@ -174,16 +176,6 @@
     }
 
     @Override
-    public void enterSearchMode() {
-        // TODO(viki): Auto-generated method stub
-    }
-
-    @Override
-    public void exitSearchMode() {
-        // TODO(viki): Auto-generated method stub
-    }
-
-    @Override
     public Account getCurrentAccount() {
         return mAccount;
     }
@@ -214,18 +206,13 @@
         // TODO(viki): Auto-generated method stub
     }
 
-    @Override
-    public void handleSearchRequested() {
-        // TODO(viki): Auto-generated method stub
-    }
-
     /**
      * Initialize the action bar. This is not visible to OnePaneController and
      * TwoPaneController so they cannot override this behavior.
      */
     private void initCustomActionBarView() {
         ActionBar actionBar = mActivity.getActionBar();
-        mActionBarView = (MailActionBar) LayoutInflater.from(mContext).inflate(
+        mActionBarView = (ActionBarView) LayoutInflater.from(mContext).inflate(
                 R.layout.actionbar_view, null);
 
         if (actionBar != null && mActionBarView != null) {
@@ -256,10 +243,10 @@
             onSettingsChanged(null);
             restartSettingsLoader();
             mActionBarView.setAccount(mAccount);
+            mActivity.invalidateOptionsMenu();
             // Account changed; existing folder is invalid.
             mFolder = null;
             fetchAccountFolderInfo();
-            updateHelpMenuItem();
         }
     }
 
@@ -360,8 +347,8 @@
     public boolean onCreateOptionsMenu(Menu menu) {
         MenuInflater inflater = mActivity.getMenuInflater();
         inflater.inflate(mActionBarView.getOptionsMenuId(), menu);
+        mActionBarView.onCreateOptionsMenu(menu);
         mRefreshItem = menu.findItem(R.id.refresh);
-        mHelpItem = menu.findItem(R.id.help_info_menu_item);
         return true;
     }
 
@@ -436,11 +423,6 @@
     }
 
     @Override
-    public void onPause() {
-        isLoaderInitialized = false;
-    }
-
-    @Override
     public void onPrepareDialog(int id, Dialog dialog, Bundle bundle) {
         // TODO(viki): Auto-generated method stub
 
@@ -462,17 +444,13 @@
                 mRefreshItem.setActionView(null);
             }
         }
-
-        // Show/hide the help menu item
-        updateHelpMenuItem();
+        mActionBarView.prepareOptionsMenu(menu);
         return true;
     }
 
-    private void updateHelpMenuItem() {
-        if (mHelpItem != null) {
-            mHelpItem.setVisible(mAccount != null
-                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
-        }
+    @Override
+    public void onPause() {
+        isLoaderInitialized = false;
     }
 
     @Override
@@ -494,8 +472,13 @@
     }
 
     @Override
-    public void onSearchRequested() {
-        // TODO(viki): Auto-generated method stub
+    public void onSearchRequested(String query) {
+        Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_SEARCH);
+        intent.putExtra(ConversationListContext.EXTRA_SEARCH_QUERY, query);
+        intent.putExtra(Utils.EXTRA_ACCOUNT, mAccount);
+        intent.setComponent(mActivity.getComponentName());
+        mActivity.startActivity(intent);
     }
 
     @Override
@@ -568,17 +551,17 @@
      * @param savedState
      */
     protected void restoreState(Bundle savedState) {
+        final Intent intent = mActivity.getIntent();
         if (savedState != null) {
             restoreListContext(savedState);
             mAccount = savedState.getParcelable(SAVED_ACCOUNT);
             restartSettingsLoader();
-        } else {
-            final Intent intent = mActivity.getIntent();
-            if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
+        } else if (intent != null) {
+            if (Intent.ACTION_VIEW.equals(intent.getAction())) {
                 if (intent.hasExtra(Utils.EXTRA_ACCOUNT)) {
                     mAccount = ((Account) intent.getParcelableExtra(Utils.EXTRA_ACCOUNT));
                     mActivity.getLoaderManager().restartLoader(ACCOUNT_SETTINGS_LOADER, null, this);
-                    updateHelpMenuItem();
+                    mActivity.invalidateOptionsMenu();
                 }
                 if (intent.hasExtra(Utils.EXTRA_FOLDER)) {
                     // Open the folder.
@@ -593,9 +576,18 @@
                     showConversation((Conversation) intent
                             .getParcelableExtra(Utils.EXTRA_CONVERSATION));
                 }
+            } else if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+                mViewMode.enterSearchResultsListMode();
+                mAccount = ((Account) intent.getParcelableExtra(Utils.EXTRA_ACCOUNT));
+                Folder searchFolder = Folder.forSearchResults(mAccount, intent
+                        .getStringExtra(ConversationListContext.EXTRA_SEARCH_QUERY));
+                setFolder(searchFolder);
+                mConvListContext = ConversationListContext.forSearchQuery(mAccount, searchFolder,
+                        Utils.mailSearchQueryForIntent(intent));
+                showConversationList(mConvListContext);
             }
         }
-        // Create the accounts loader; this loads the acount switch spinner.
+        // Create the accounts loader; this loads the account switch spinner.
         mActivity.getLoaderManager().initLoader(ACCOUNT_CURSOR_LOADER, null, this);
     }
 
@@ -624,7 +616,11 @@
     public void onConversationSelected(Conversation conversation) {
         mCurrentConversation = conversation;
         showConversation(mCurrentConversation);
-        mViewMode.enterConversationMode();
+        if (mConvListContext != null && mConvListContext.isSearchResult()) {
+            mViewMode.enterSearchResultsConversationMode();
+        } else {
+            mViewMode.enterConversationMode();
+        }
     }
 
     /**
@@ -637,8 +633,11 @@
             return new CursorLoader(mContext, AccountCacheProvider.getAccountsUri(),
                     UIProvider.ACCOUNTS_PROJECTION, null, null, null);
         } else if (id == FOLDER_CURSOR_LOADER) {
-            return new CursorLoader(mActivity.getActivityContext(), mFolder.uri,
-                    UIProvider.FOLDERS_PROJECTION, null, null, null);
+            // Don't bother running a cursor loader for the search results folder.
+            if (!mFolder.uri.equals(Folder.SEARCH_RESULTS_URI)) {
+                return new CursorLoader(mActivity.getActivityContext(), mFolder.uri,
+                        UIProvider.FOLDERS_PROJECTION, null, null, null);
+            }
         } else if (id == ACCOUNT_SETTINGS_LOADER) {
             if (mAccount.settingsQueryUri != null) {
                 return new CursorLoader(mActivity.getActivityContext(), mAccount.settingsQueryUri,
diff --git a/src/com/android/mail/ui/ActionBarView.java b/src/com/android/mail/ui/ActionBarView.java
index b44ce55..13b5312 100644
--- a/src/com/android/mail/ui/ActionBarView.java
+++ b/src/com/android/mail/ui/ActionBarView.java
@@ -1,118 +1,342 @@
-/*******************************************************************************
- *      Copyright (C) 2012 Google Inc.
- *      Licensed to The Android Open Source Project.
+/*
+ * Copyright (C) 2012 Google Inc.
+ * Licensed to 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
+ * 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
+ *      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.
- *******************************************************************************/
+ * 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.mail.ui;
 
 import android.app.ActionBar;
+import android.app.SearchManager;
+import android.app.SearchableInfo;
 import android.app.ActionBar.OnNavigationListener;
+import android.content.Context;
 import android.os.Bundle;
+import android.util.AttributeSet;
 import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.SearchView;
+import android.widget.SearchView.OnQueryTextListener;
+import android.widget.SpinnerAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
 
+import com.android.mail.R;
+import com.android.mail.AccountSpinnerAdapter;
+import com.android.mail.ConversationListContext;
 import com.android.mail.providers.Account;
+import com.android.mail.providers.UIProvider.AccountCapabilities;
 import com.android.mail.providers.Folder;
 
 /**
- * ActionBarView simplifies supporting both MailActionBar and MailActionBarDeprecated (used for
- * pre-v14 devices).
+ * View to manage the various states of the Mail Action Bar
+ *
+ * TODO(viki): Include ConversationSubjectDisplayer here as well.
  */
-
-public interface ActionBarView extends OnNavigationListener, ViewMode.ModeChangeListener {
+public final class ActionBarView extends LinearLayout implements OnNavigationListener,
+        ViewMode.ModeChangeListener, OnQueryTextListener {
     /**
-     * Initialize the ActionBarView
-     * @param activity
-     * @param callback
-     * @param viewMode
-     * @param actionBar
+     * This interface is used to send notifications back to the calling
+     * activity. MenuHandler takes care of updating the provider, so this
+     * interface should be used for notification purposes only (such as updating
+     * the UI).
      */
-    void initialize(RestrictedActivity activity, ActivityController controller, ViewMode viewMode,
-            ActionBar actionBar);
+    // TODO(viki): This callback is currently unused and may be entirely unnecessary in the new
+    // code, where the Actionbar is switched into navigation mode, relying on the framework for most
+    // heavy lifting. Also, we can switch ViewMode to the appropriate mode and rely on all UI
+    // components updating through ViewMode change listeners.
+    public interface Callback {
+        /**
+         * Returns the current account.
+         */
+        Account getCurrentAccount();
+
+        /**
+         * Called when the TwoPaneActionBar wants to get the current conversation list context.
+         */
+        ConversationListContext getCurrentListContext();
+
+        /**
+         * Invoked when the user is already viewing search results
+         * and enters a new query.
+         * @param string Query
+         */
+        void reloadSearch(String string);
+
+        void showFolderList();
+
+        void startActionBarStatusCursorLoader(String account);
+
+        void stopActionBarStatusCursorLoader(String account);
+    }
+
+    private String[] mAccountNames;
+    private ActionBar mActionBar;
+    private RestrictedActivity mActivity;
+    private ActivityController mCallback;
+    private View mFolderView;
+    /**
+     * The current mode of the ActionBar. This references constants in {@link ViewMode}
+     */
+    private int mMode = ViewMode.UNKNOWN;
+
+    private MenuItem mSearch;
+    AccountSpinnerAdapter mSpinner;
+    /**
+     * The account currently being shown
+     */
+    private Account mAccount;
+
+    // TODO(viki): This is a SnippetTextView in the Gmail source code. Resolve.
+    private TextView mSubjectView;
+    private SearchView mSearchWidget;
+    private MenuItem mHelpItem;
+
+    public ActionBarView(Context context) {
+        this(context, null);
+    }
+
+    public ActionBarView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ActionBarView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // If the mode is valid, then set the initial menu
+        if (mMode == ViewMode.UNKNOWN) {
+            return false;
+        }
+        MenuItem search = menu.findItem(R.id.search);
+        if (search != null) {
+            mSearchWidget = (SearchView) search.getActionView();
+            SearchManager searchManager = (SearchManager) mActivity.getActivityContext()
+                    .getSystemService(Context.SEARCH_SERVICE);
+            if (searchManager != null) {
+                SearchableInfo info = searchManager.getSearchableInfo(mActivity.getComponentName());
+                mSearchWidget.setSearchableInfo(info);
+                mSearchWidget.setOnQueryTextListener(this);
+            }
+        }
+        mHelpItem = menu.findItem(R.id.help_info_menu_item);
+        return true;
+    }
+
+    public int getOptionsMenuId() {
+        // Relies on the ordering of the view modes, since they are integer constants.
+        final int[] modeMenu = {
+                // 0: UNKNOWN
+                R.menu.conversation_list_menu,
+                // 1: CONVERSATION
+                R.menu.conversation_actions,
+                // 2: CONVERSATION_LIST
+                R.menu.conversation_list_menu,
+                // 3: FOLDER_LIST
+                R.menu.folder_list_menu,
+                // 4: SEARCH_RESULTS_LIST
+                R.menu.conversation_list_search_results_actions,
+                // 5: SEARCH_RESULTS_CONVERSATION
+                R.menu.conversation_actions
+        };
+        return modeMenu[mMode];
+    }
+
+    public void handleRestore(Bundle savedInstanceState) {
+    }
+
+    public void handleSaveInstanceState(Bundle outState) {
+    }
+
+    public void initialize(RestrictedActivity activity, ActivityController callback,
+            ViewMode viewMode, ActionBar actionBar) {
+        mActionBar = actionBar;
+        mCallback = callback;
+        mActivity = activity;
+
+        mSpinner = new AccountSpinnerAdapter(getContext());
+        // Set the mode to Navigation mode and listen on navigation changes.
+        mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+        mActionBar.setListNavigationCallbacks(mSpinner, this);
+    }
+
+    public void setAccounts(Account[] accounts) {
+        Account currentAccount = mCallback.getCurrentAccount();
+        mSpinner.setAccounts(accounts);
+        mSpinner.setCurrentAccount(currentAccount);
+        int position = -1;
+        for (position = 0; position < accounts.length; position++) {
+            if (accounts[position].equals(currentAccount)) {
+                break;
+            }
+        }
+        if (position >= accounts.length) {
+            position = 0;
+        }
+        mActionBar.setSelectedNavigationItem(position);
+    }
 
     /**
-     * Handle handleRestore from the Android framework.
-     * @param savedInstanceState
+     * Called by the owner of the ActionBar to set the
+     * folder that is currently being displayed.
      */
-    void handleRestore(Bundle savedInstanceState);
+    public void setFolder(Folder folder) {
+        mSpinner.setCurrentFolder(folder);
+        mSpinner.notifyDataSetChanged();
+    }
 
     /**
-     * Handle onResume from the Android framework.
+     * Called by the owner of the ActionBar to set the
+     * account that is currently being displayed.
      */
-    void onResume();
+    public void setAccount(Account account) {
+        mSpinner.setCurrentAccount(account);
+        mSpinner.notifyDataSetChanged();
+    }
+
+    @Override
+    public boolean onNavigationItemSelected(int position, long id) {
+        final int type = mSpinner.getItemViewType(position);
+        switch (type) {
+            case AccountSpinnerAdapter.TYPE_ACCOUNT:
+                // Get the capabilities associated with this account.
+                final Object item = mSpinner.getItem(position);
+                assert (item instanceof Account);
+                mCallback.onAccountChanged((Account) mSpinner.getItem(position));
+                break;
+            case AccountSpinnerAdapter.TYPE_FOLDER:
+                final Object folder = mSpinner.getItem(position);
+                assert (folder instanceof Folder);
+                mCallback.onFolderChanged((Folder) folder);
+                break;
+        }
+        return false;
+    }
+
+    public void onPause() {
+    }
+
+    public void onResume() {
+    }
+
+    public void onStatusResult(String account, int status) {
+        // Update the inbox folder if required
+        mCallback.stopActionBarStatusCursorLoader(account);
+    }
+
+    public void onViewModeChanged(int newMode) {
+        mMode = newMode;
+        // Always update the options menu and redraw. This will read the new mode and redraw
+        // the options menu.
+        mActivity.invalidateOptionsMenu();
+    }
 
     /**
-     * Handle onPause from the Android framework.
+     * If shouldSetView is true, then the view is made visible, otherwise its visiblity is View.GONE
+     * @param view the view whose visibility is modified
+     * @param shouldSetView if true, the view is made visible, GONE otherwise
      */
-    void onPause();
+    private void setVisibility(int resourceId, boolean shouldSetView) {
+        final View view = findViewById(resourceId);
+        assert (view != null);
+        final int visibility = shouldSetView ? View.VISIBLE : View.GONE;
+        view.setVisibility(visibility);
+    }
 
-    /**
-     * @param outState
-     */
-    void handleSaveInstanceState(Bundle outState);
+    public boolean prepareOptionsMenu(Menu menu) {
+        // We start out with every option enabled. Based on the current view, we disable actions
+        // that are possible.
+        if (mSubjectView != null){
+            mSubjectView.setVisibility(GONE);
+        }
+        if (mFolderView != null){
+            mFolderView.setVisibility(GONE);
+        }
+        if (mAccount == null) {
+            return false;
+        }
 
-    /**
-     * Update the folder that the user is currently viewing
-     * @param folder
-     */
-    void setFolder(Folder folder);
+        if (mHelpItem != null) {
+            mHelpItem.setVisible(mAccount != null
+                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
+        }
+        switch (mMode){
+            case ViewMode.UNKNOWN:
+                if (mSearch != null){
+                    mSearch.collapseActionView();
+                }
+                break;
+            case ViewMode.CONVERSATION_LIST:
+                // Show compose, search, labels, and sync based on the account
+                // The only option that needs to be disabled is search
+                setVisibility(R.id.search, mAccount.supportsCapability(
+                        AccountCapabilities.FOLDER_SERVER_SEARCH));
+                break;
+            case ViewMode.CONVERSATION:
+                setVisibility(R.id.y_button, mAccount.supportsCapability(
+                        AccountCapabilities.ARCHIVE));
+                setVisibility(R.id.report_spam, mAccount.supportsCapability(
+                        AccountCapabilities.REPORT_SPAM));
+                setVisibility(R.id.mute, mAccount.supportsCapability(AccountCapabilities.MUTE));
+                break;
+            case ViewMode.SEARCH_RESULTS_LIST:
+                mActionBar.setDisplayHomeAsUpEnabled(true);
+                if (mSearch != null) {
+                    mSearch.expandActionView();
+                }
+                break;
+            case ViewMode.SEARCH_RESULTS_CONVERSATION:
+                mActionBar.setDisplayHomeAsUpEnabled(true);
+                break;
+            case ViewMode.FOLDER_LIST:
+                break;
+        }
+        return false;
+    }
 
-    /**
-     * Update the account that the user is currently viewing
-     * @param account
-     */
-    void setAccount(Account account);
+    public void removeBackButton() {
+        if (mActionBar == null) {
+            return;
+        }
+        mActionBar.setDisplayOptions(
+                ActionBar.DISPLAY_SHOW_HOME,
+                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
+        mActivity.getActionBar().setHomeButtonEnabled(false);
+    }
 
-    /**
-     * Returns the menu ID for the menu in this actionbar.
-     * @return the Menu ID for the menu.
-     */
-    int getOptionsMenuId();
+    public void setBackButton() {
+        if (mActionBar == null){
+            return;
+        }
+        mActionBar.setDisplayOptions(
+                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
+                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
+        mActivity.getActionBar().setHomeButtonEnabled(true);
+    }
 
-    /**
-     * Shows a back button in the top left. We have progressed one level into the application.
-     */
-    void setBackButton();
+    @Override
+    public boolean onQueryTextSubmit(String query) {
+        mActivity.onSearchRequested(query);
+        return true;
+    }
 
-    /**
-     * Removes any back button from the top left. We have returned to the top of the application.
-     */
-    void removeBackButton();
-
-    /**
-     * Prepares all the icons that go inside the options menu. This depends on the context of
-     * the action bar.
-     * @param menu
-     */
-    boolean prepareOptionsMenu(Menu menu);
-
-    /**
-     * Creates the first time options menu.
-     * @param menu
-     */
-    boolean createOptionsMenu(Menu menu);
-
-    /**
-     * Updates the action bar based on a new status received from the server.
-     * @param account
-     * @param status
-     */
-    void onStatusResult(String account, int status);
-
-    /**
-     * Sets the list of accounts in the drop-down navigation.
-     * @param accounts the array of accounts to be set.
-     */
-    void setAccounts(Account[] accounts);
+    @Override
+    public boolean onQueryTextChange(String newText) {
+        // TODO Auto-generated method stub
+        return false;
+    }
 }
diff --git a/src/com/android/mail/ui/ActivityController.java b/src/com/android/mail/ui/ActivityController.java
index 2db0bb6..69781fb 100644
--- a/src/com/android/mail/ui/ActivityController.java
+++ b/src/com/android/mail/ui/ActivityController.java
@@ -22,7 +22,6 @@
 import android.content.Intent;
 import android.database.Cursor;
 import android.os.Bundle;
-import android.view.ActionMode;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -40,7 +39,7 @@
  * or respond to user action.
  */
 public interface ActivityController extends MenuCallback, LayoutListener, SubjectDisplayChanger,
-        ModeChangeListener, MailActionBar.Callback, StarHandler, ConversationListCallbacks,
+        ModeChangeListener, ActionBarView.Callback, StarHandler, ConversationListCallbacks,
         FolderChangeListener, AccountChangeListener, LoaderManager.LoaderCallbacks<Cursor> {
 
     // As far as possible, the methods here that correspond to Activity lifecycle have the same name
@@ -189,7 +188,7 @@
     /**
      * @see android.app.Activity#onSearchRequested()
      */
-    void onSearchRequested();
+    void onSearchRequested(String query);
 
     /**
      * Called by the Mail activity on Activity stop.
diff --git a/src/com/android/mail/ui/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java
index e415050..12afa26 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -172,6 +172,20 @@
     }
 
     /**
+     * Show the header if the current conversation list is showing search results.
+     */
+    private void updateSearchResultHeader(int count) {
+        // Only show the header if the context is for a search result
+        final Resources res = getResources();
+        final boolean showHeader = isSearchResult();
+        if (showHeader) {
+            mSearchStatusTextView.setText(res.getString(R.string.search_results_header));
+            mSearchResultCountTextView
+                    .setText(res.getString(R.string.search_results_loaded, count));
+        }
+    }
+
+    /**
      * Initializes all internal state for a rendering.
      */
     private void initializeUiForFirstDisplay() {
@@ -499,8 +513,9 @@
 
     @Override
     public Loader<ConversationCursor> onCreateLoader(int id, Bundle args) {
+        configureSearchResultHeader();
         return new ConversationCursorLoader((Activity) mActivity,
-                UIProvider.CONVERSATION_PROJECTION, mFolder.conversationListUri);
+                    UIProvider.CONVERSATION_PROJECTION, mFolder.conversationListUri);
     }
 
     @Override
@@ -508,7 +523,7 @@
         mConversationListCursor = data;
         mListAdapter.swapCursor(mConversationListCursor);
         mConversationListCursor.addListener(this);
-        configureSearchResultHeader();
+        updateSearchResultHeader(data != null ? data.getCount() : 0);
     }
 
     @Override
diff --git a/src/com/android/mail/ui/FolderSelectionActivity.java b/src/com/android/mail/ui/FolderSelectionActivity.java
index bbf8093..7df84c9 100644
--- a/src/com/android/mail/ui/FolderSelectionActivity.java
+++ b/src/com/android/mail/ui/FolderSelectionActivity.java
@@ -268,4 +268,9 @@
     public Settings getSettings() {
         return null;
     }
+
+    @Override
+    public boolean onSearchRequested(String query) {
+        return false;
+    }
 }
diff --git a/src/com/android/mail/ui/MailActionBar.java b/src/com/android/mail/ui/MailActionBar.java
deleted file mode 100644
index 8f107ef..0000000
--- a/src/com/android/mail/ui/MailActionBar.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc.
- * Licensed to 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.mail.ui;
-
-import android.app.ActionBar;
-import android.app.ActionBar.OnNavigationListener;
-import android.content.Context;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.SpinnerAdapter;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.mail.R;
-import com.android.mail.AccountSpinnerAdapter;
-import com.android.mail.ConversationListContext;
-import com.android.mail.providers.Account;
-import com.android.mail.providers.UIProvider.AccountCapabilities;
-import com.android.mail.providers.Folder;
-
-/**
- * View to manage the various states of the Mail Action Bar
- *
- * TODO(viki): Include ConversationSubjectDisplayer here as well.
- */
-public final class MailActionBar extends LinearLayout implements ActionBarView {
-    /**
-     * This interface is used to send notifications back to the calling
-     * activity. MenuHandler takes care of updating the provider, so this
-     * interface should be used for notification purposes only (such as updating
-     * the UI).
-     */
-    // TODO(viki): This callback is currently unused and may be entirely unnecessary in the new
-    // code, where the Actionbar is switched into navigation mode, relying on the framework for most
-    // heavy lifting. Also, we can switch ViewMode to the appropriate mode and rely on all UI
-    // components updating through ViewMode change listeners.
-    public interface Callback {
-        /**
-         * Enter search mode
-         */
-        void enterSearchMode();
-
-        /**
-         * Exits search mode
-         */
-        void exitSearchMode();
-
-        /**
-         * Returns the current account.
-         */
-        Account getCurrentAccount();
-
-        /**
-         * Called when the TwoPaneActionBar wants to get the current conversation list context.
-         */
-        ConversationListContext getCurrentListContext();
-
-        /**
-         * Invoked when the user is already viewing search results
-         * and enters a new query.
-         * @param string Query
-         */
-        void reloadSearch(String string);
-
-        void showFolderList();
-
-        void startActionBarStatusCursorLoader(String account);
-
-        void stopActionBarStatusCursorLoader(String account);
-    }
-
-    private String[] mAccountNames;
-    private ActionBar mActionBar;
-    private RestrictedActivity mActivity;
-    private ActivityController mCallback;
-    private View mFolderView;
-    /**
-     * The current mode of the ActionBar. This references constants in {@link ViewMode}
-     */
-    private int mMode = ViewMode.UNKNOWN;
-
-    private MenuItem mRefreshItem;
-
-    private MenuItem mSearch;
-    AccountSpinnerAdapter mSpinner;
-    /**
-     * The account currently being shown
-     */
-    private Account mAccount;
-
-    // TODO(viki): This is a SnippetTextView in the Gmail source code. Resolve.
-    private TextView mSubjectView;
-
-    public MailActionBar(Context context) {
-        this(context, null);
-    }
-
-    public MailActionBar(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public MailActionBar(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    public boolean createOptionsMenu(Menu menu) {
-        // If the mode is valid, then set the initial menu
-        if (mMode == ViewMode.UNKNOWN) {
-            return false;
-        }
-        mActivity.getMenuInflater().inflate(getOptionsMenuId(), menu);
-        // mSearch = menu.findItem(R.id.search);
-        // mRefreshItem = menu.findItem(R.id.refresh);
-        return true;
-    }
-
-    @Override
-    public int getOptionsMenuId() {
-        // Relies on the ordering of the view modes, since they are integer constants.
-        final int[] modeMenu = {
-                // 0: UNKNOWN
-                R.menu.conversation_list_menu,
-                // 1: CONVERSATION
-                R.menu.conversation_actions,
-                // 2: CONVERSATION_LIST
-                R.menu.conversation_list_menu,
-                // 3: FOLDER_LIST
-                R.menu.folder_list_menu,
-                // 4: SEARCH_RESULTS
-                R.menu.conversation_list_menu
-        };
-        return modeMenu[mMode];
-    }
-
-    @Override
-    public void handleRestore(Bundle savedInstanceState) {
-    }
-
-    @Override
-    public void handleSaveInstanceState(Bundle outState) {
-    }
-
-    @Override
-    public void initialize(RestrictedActivity activity, ActivityController callback, ViewMode viewMode,
-            ActionBar actionBar) {
-        mActionBar = actionBar;
-        mCallback = callback;
-        mActivity = activity;
-
-        mSpinner = new AccountSpinnerAdapter(getContext());
-        // Set the mode to Navigation mode and listen on navigation changes.
-        mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
-        mActionBar.setListNavigationCallbacks(mSpinner, this);
-    }
-
-    @Override
-    public void setAccounts(Account[] accounts) {
-        Account currentAccount = mCallback.getCurrentAccount();
-        mSpinner.setAccounts(accounts);
-        mSpinner.setCurrentAccount(currentAccount);
-        int position = -1;
-        for (position = 0; position < accounts.length; position++) {
-            if (accounts[position].equals(currentAccount)) {
-                break;
-            }
-        }
-        if (position >= accounts.length) {
-            position = 0;
-        }
-        mActionBar.setSelectedNavigationItem(position);
-    }
-
-    /**
-     * Called by the owner of the ActionBar to set the
-     * folder that is currently being displayed.
-     */
-    @Override
-    public void setFolder(Folder folder) {
-        mSpinner.setCurrentFolder(folder);
-        mSpinner.notifyDataSetChanged();
-    }
-
-    /**
-     * Called by the owner of the ActionBar to set the
-     * account that is currently being displayed.
-     */
-    @Override
-    public void setAccount(Account account) {
-        mSpinner.setCurrentAccount(account);
-        mSpinner.notifyDataSetChanged();
-    }
-
-    @Override
-    public boolean onNavigationItemSelected(int position, long id) {
-        final int type = mSpinner.getItemViewType(position);
-        switch (type) {
-            case AccountSpinnerAdapter.TYPE_ACCOUNT:
-                // Get the capabilities associated with this account.
-                final Object item = mSpinner.getItem(position);
-                assert (item instanceof Account);
-                mCallback.onAccountChanged((Account) mSpinner.getItem(position));
-                break;
-            case AccountSpinnerAdapter.TYPE_FOLDER:
-                final Object folder = mSpinner.getItem(position);
-                assert (folder instanceof Folder);
-                mCallback.onFolderChanged((Folder) folder);
-                break;
-        }
-        return false;
-    }
-
-    @Override
-    public void onPause() {
-    }
-
-    @Override
-    public void onResume() {
-    }
-
-    @Override
-    public void onStatusResult(String account, int status) {
-        // Update the inbox folder if required
-        mCallback.stopActionBarStatusCursorLoader(account);
-    }
-
-    @Override
-    public void onViewModeChanged(int newMode) {
-        mMode = newMode;
-        // Always update the options menu and redraw. This will read the new mode and redraw
-        // the options menu.
-        mActivity.invalidateOptionsMenu();
-    }
-
-    /**
-     * If shouldSetView is true, then the view is made visible, otherwise its visiblity is View.GONE
-     * @param view the view whose visibility is modified
-     * @param shouldSetView if true, the view is made visible, GONE otherwise
-     */
-    private void setVisibility(int resourceId, boolean shouldSetView) {
-        final View view = findViewById(resourceId);
-        assert (view != null);
-        final int visibility = shouldSetView ? View.VISIBLE : View.GONE;
-        view.setVisibility(visibility);
-    }
-
-    @Override
-    public boolean prepareOptionsMenu(Menu menu) {
-        // We start out with every option enabled. Based on the current view, we disable actions
-        // that are possible.
-        if (mSubjectView != null){
-            mSubjectView.setVisibility(GONE);
-        }
-        if (mFolderView != null){
-            mFolderView.setVisibility(GONE);
-        }
-
-        switch (mMode){
-            case ViewMode.UNKNOWN:
-                if (mSearch != null){
-                    mSearch.collapseActionView();
-                }
-                break;
-            case ViewMode.CONVERSATION_LIST:
-                // Show compose, search, labels, and sync based on the account
-                // The only option that needs to be disabled is search
-                setVisibility(R.id.search, mAccount.supportsCapability(
-                        AccountCapabilities.FOLDER_SERVER_SEARCH));
-                break;
-            case ViewMode.CONVERSATION:
-                setVisibility(R.id.y_button, mAccount.supportsCapability(
-                        AccountCapabilities.ARCHIVE));
-                setVisibility(R.id.report_spam, mAccount.supportsCapability(
-                        AccountCapabilities.REPORT_SPAM));
-                setVisibility(R.id.mute, mAccount.supportsCapability(AccountCapabilities.MUTE));
-                break;
-            case ViewMode.SEARCH_RESULTS:
-                mActionBar.setDisplayHomeAsUpEnabled(true);
-                if (mSearch != null) {
-                    mSearch.collapseActionView();
-                }
-            case ViewMode.FOLDER_LIST:
-                break;
-        }
-        return false;
-    }
-
-    @Override
-    public void removeBackButton() {
-        if (mActionBar == null) {
-            return;
-        }
-        mActionBar.setDisplayOptions(
-                ActionBar.DISPLAY_SHOW_HOME,
-                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
-        mActivity.getActionBar().setHomeButtonEnabled(false);
-    }
-
-    @Override
-    public void setBackButton() {
-        if (mActionBar == null){
-            return;
-        }
-        mActionBar.setDisplayOptions(
-                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
-                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
-        mActivity.getActionBar().setHomeButtonEnabled(true);
-    }
-}
diff --git a/src/com/android/mail/ui/MailActivity.java b/src/com/android/mail/ui/MailActivity.java
index 8ed9134..5b3663e 100644
--- a/src/com/android/mail/ui/MailActivity.java
+++ b/src/com/android/mail/ui/MailActivity.java
@@ -201,8 +201,8 @@
     }
 
     @Override
-    public boolean onSearchRequested() {
-        mController.onSearchRequested();
+    public boolean onSearchRequested(String query) {
+        mController.onSearchRequested(query);
         return true;
     }
 
diff --git a/src/com/android/mail/ui/MenuCallback.java b/src/com/android/mail/ui/MenuCallback.java
index 4c4ef3d..c992f70 100644
--- a/src/com/android/mail/ui/MenuCallback.java
+++ b/src/com/android/mail/ui/MenuCallback.java
@@ -27,11 +27,6 @@
 // Called MenuHandler.ActivityCallback in the previous code.
 public interface MenuCallback extends HelpCallback {
     /**
-     * Invoked when the user requests search mode
-     */
-    void handleSearchRequested();
-
-    /**
      * Invoked when user starts drag and drop mode.
      */
     void onStartDragMode();
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 9074050..e655b27 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -80,8 +80,10 @@
         // If the settings aren't loaded yet, we may not know what the default
         // inbox is, so err toward this being the account inbox.
         if ((mCachedSettings != null && mConvListContext != null && !inInbox())
-                || (mode == ViewMode.CONVERSATION_LIST && mConvListContext.isSearchResult())
-                || mode == ViewMode.CONVERSATION || mode == ViewMode.FOLDER_LIST) {
+                || mode == ViewMode.SEARCH_RESULTS_LIST
+                || mode == ViewMode.SEARCH_RESULTS_CONVERSATION
+                || mode == ViewMode.CONVERSATION
+                || mode == ViewMode.FOLDER_LIST) {
             mActionBarView.setBackButton();
         } else {
             mActionBarView.removeBackButton();
@@ -116,15 +118,16 @@
     public void showConversationList(ConversationListContext listContext) {
         // TODO(viki): Check if the account has been changed since the previous
         // time.
-        mViewMode.enterConversationListMode();
+        if (listContext != null && listContext.isSearchResult()) {
+            mViewMode.enterSearchResultsListMode();
+        } else {
+            mViewMode.enterConversationListMode();
+        }
         final boolean accountChanged = false;
         // TODO(viki): This account transition looks strange in two pane mode.
         // Revisit as the app is coming together and improve the look and feel.
         final int transition = accountChanged ? FragmentTransaction.TRANSIT_FRAGMENT_FADE
                 : FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
-        if (listContext == null) {
-            listContext = getCurrentListContext();
-        }
         Fragment conversationListFragment = ConversationListFragment.newInstance(listContext);
         if (!inInbox()) {
             // Maintain fragment transaction history so we can get back to the
@@ -142,7 +145,11 @@
 
     @Override
     public void showConversation(Conversation conversation) {
-        mViewMode.enterConversationMode();
+        if (mConvListContext != null && mConvListContext.isSearchResult()) {
+            mViewMode.enterSearchResultsConversationMode();
+        } else {
+            mViewMode.enterConversationMode();
+        }
         mLastConversationTransactionId = replaceFragment(
                 ConversationViewFragment.newInstance(mAccount, conversation),
                 FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
@@ -187,6 +194,8 @@
         if (mode == ViewMode.FOLDER_LIST) {
             mLastFolderListTransactionId = INVALID_ID;
             transitionToInbox();
+        } else if (mode == ViewMode.SEARCH_RESULTS_LIST) {
+            mActivity.finish();
         } else if (mode == ViewMode.CONVERSATION_LIST && !inInbox()) {
             if (isTransactionIdValid(mLastFolderListTransactionId)) {
                 // Go back to previous label list.
@@ -196,7 +205,7 @@
                 // Go back to Inbox.
                 transitionToInbox();
             }
-        } else if (mode == ViewMode.CONVERSATION) {
+        } else if (mode == ViewMode.CONVERSATION || mode == ViewMode.SEARCH_RESULTS_CONVERSATION) {
             transitionBackToConversationListMode();
         } else {
             mActivity.finish();
@@ -234,18 +243,25 @@
     @Override
     public boolean onUpPressed() {
         int mode = mViewMode.getMode();
-        if ((!inInbox() && mode == ViewMode.CONVERSATION_LIST) || mode == ViewMode.CONVERSATION
-                || mode == ViewMode.FOLDER_LIST) {
+        if (mode == ViewMode.SEARCH_RESULTS_LIST) {
+            mActivity.finish();
+        } else if ((!inInbox() && mode == ViewMode.CONVERSATION_LIST)
+                || mode == ViewMode.CONVERSATION
+                || mode == ViewMode.FOLDER_LIST
+                || mode == ViewMode.SEARCH_RESULTS_CONVERSATION) {
             // Same as go back.
             mActivity.onBackPressed();
-        } else if (mode == ViewMode.SEARCH_RESULTS) {
-            mActivity.finish();
         }
         return true;
     }
 
     private void transitionBackToConversationListMode() {
-        mViewMode.enterConversationListMode();
+        int mode = mViewMode.getMode();
+        if (mode == ViewMode.SEARCH_RESULTS_CONVERSATION) {
+            mViewMode.enterSearchResultsListMode();
+        } else {
+            mViewMode.enterConversationListMode();
+        }
         mActivity.getFragmentManager().popBackStack(mLastConversationTransactionId,
                 FragmentManager.POP_BACK_STACK_INCLUSIVE);
         resetActionBarIcon();
diff --git a/src/com/android/mail/ui/RestrictedActivity.java b/src/com/android/mail/ui/RestrictedActivity.java
index 7fbedfc..15b25a9 100644
--- a/src/com/android/mail/ui/RestrictedActivity.java
+++ b/src/com/android/mail/ui/RestrictedActivity.java
@@ -122,7 +122,7 @@
     /**
      * @see android.app.Activity#onSearchRequested()
      */
-    public boolean onSearchRequested();
+    public boolean onSearchRequested(String query);
 
     /**
      * @see android.app.Activity#setContentView(int)
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 7b9c8a4..36e49bd 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -191,7 +191,7 @@
             } else {
                 mActivity.onBackPressed();
             }
-        } else if (mode == ViewMode.SEARCH_RESULTS) {
+        } else if (mode == ViewMode.SEARCH_RESULTS_LIST) {
             mActivity.finish();
         }
         return true;
diff --git a/src/com/android/mail/ui/TwoPaneLayout.java b/src/com/android/mail/ui/TwoPaneLayout.java
index 07b39a2..ec8dfa5 100644
--- a/src/com/android/mail/ui/TwoPaneLayout.java
+++ b/src/com/android/mail/ui/TwoPaneLayout.java
@@ -312,7 +312,7 @@
         switch (currentMode) {
             case ViewMode.CONVERSATION:
                 // Fallthrough
-            case ViewMode.SEARCH_RESULTS:
+            case ViewMode.SEARCH_RESULTS_CONVERSATION:
                 if (isConversationListCollapsible()) {
                     return totalWidth;
                 }
@@ -665,7 +665,8 @@
                 break;
             case ViewMode.FOLDER_LIST:
                 break;
-            case ViewMode.SEARCH_RESULTS:
+            case ViewMode.SEARCH_RESULTS_LIST:
+            case ViewMode.SEARCH_RESULTS_CONVERSATION:
                 // Show search results here
                 break;
         }
diff --git a/src/com/android/mail/ui/ViewMode.java b/src/com/android/mail/ui/ViewMode.java
index 40aad55..ac2d28e 100644
--- a/src/com/android/mail/ui/ViewMode.java
+++ b/src/com/android/mail/ui/ViewMode.java
@@ -56,7 +56,11 @@
     /**
      * Mode when showing results from user search.
      */
-    public static final int SEARCH_RESULTS = 4;
+    public static final int SEARCH_RESULTS_LIST = 4;
+    /**
+     * Mode when showing results from user search.
+     */
+    public static final int SEARCH_RESULTS_CONVERSATION = 5;
     /**
      * Uncertain mode. The mode has not been initialized.
      */
@@ -121,6 +125,26 @@
     }
 
     /**
+     * Requests a transition of the mode to show a list of search results as the
+     * prominent view.
+     *
+     * @return Whether or not a change occurred.
+     */
+    public boolean enterSearchResultsListMode() {
+        return setModeInternal(SEARCH_RESULTS_LIST);
+    }
+
+    /**
+     * Requests a transition of the mode to show a conversation that was part of
+     * search results.
+     *
+     * @return Whether or not a change occurred.
+     */
+    public boolean enterSearchResultsConversationMode() {
+        return setModeInternal(SEARCH_RESULTS_CONVERSATION);
+    }
+
+    /**
      * @return The current mode.
      */
     public int getMode() {
diff --git a/src/com/android/mail/utils/Utils.java b/src/com/android/mail/utils/Utils.java
index e06613d..c9032fd 100644
--- a/src/com/android/mail/utils/Utils.java
+++ b/src/com/android/mail/utils/Utils.java
@@ -18,6 +18,7 @@
 
 import com.google.common.collect.Maps;
 
+import android.app.SearchManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -683,4 +684,13 @@
         final Intent settingsIntent = new Intent(Intent.ACTION_EDIT, account.settingsIntentUri);
         context.startActivity(settingsIntent);
     }
+
+    /**
+     * Retrieves the mailbox search query associated with an intent (or null if not available),
+     * doing proper sanitizing (e.g. trims whitespace).
+     */
+    public static String mailSearchQueryForIntent(Intent intent) {
+        String query = intent.getStringExtra(SearchManager.QUERY);
+        return TextUtils.isEmpty(query) ? null : query.trim();
+   }
 }