Merge latest green fx-team changeset and mozilla-central
authorEd Morley <emorley@mozilla.com>
Wed, 21 Aug 2013 12:56:05 +0100
changeset 143588 d25f59701c033c1e63c4b5a6eae9919a238e78d4
parent 143587 072341c2c66f4ec9b65a56d826a4fd52f512bf62 (current diff)
parent 143572 b2486721572e18f2b936f98f68624301dc490ad8 (diff)
child 143594 e78c725d45bd197d87c8732f8877925f2967a5d4
push id25131
push useremorley@mozilla.com
push dateWed, 21 Aug 2013 11:56:22 +0000
treeherdermozilla-central@d25f59701c03 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge latest green fx-team changeset and mozilla-central
mobile/android/base/AwesomeBar.java
mobile/android/base/AwesomeBarTabs.java
mobile/android/base/AwesomebarResultHandler.java
mobile/android/base/SearchEngine.java
mobile/android/base/SearchEngineRow.java
mobile/android/base/SuggestClient.java
mobile/android/base/awesomebar/AllPagesTab.java
mobile/android/base/awesomebar/AwesomeBarTab.java
mobile/android/base/awesomebar/BookmarksTab.java
mobile/android/base/awesomebar/HistoryTab.java
mobile/android/base/resources/anim/awesomebar_fade_in.xml
mobile/android/base/resources/anim/awesomebar_fade_out.xml
mobile/android/base/resources/anim/awesomebar_hold_still.xml
mobile/android/base/resources/color/abouthome_section_more_text.xml
mobile/android/base/resources/color/abouthome_section_subtitle.xml
mobile/android/base/resources/color/abouthome_section_title.xml
mobile/android/base/resources/color/awesome_bar_title.xml
mobile/android/base/resources/color/awesome_bar_title_hint.xml
mobile/android/base/resources/drawable-hdpi/abouthome_icon.png
mobile/android/base/resources/drawable-hdpi/abouthome_logo_dark.png
mobile/android/base/resources/drawable-hdpi/abouthome_logo_light.png
mobile/android/base/resources/drawable-hdpi/abouthome_promo_box_bg.9.png
mobile/android/base/resources/drawable-hdpi/abouthome_promo_box_pressed_bg.9.png
mobile/android/base/resources/drawable-hdpi/abouthome_promo_logo_apps.png
mobile/android/base/resources/drawable-hdpi/abouthome_promo_logo_sync.png
mobile/android/base/resources/drawable-hdpi/abouthome_thumbnail_add.png
mobile/android/base/resources/drawable-hdpi/abouthome_thumbnail_bg.png
mobile/android/base/resources/drawable-hdpi/address_bar_bg_shadow.png
mobile/android/base/resources/drawable-hdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-hdpi/address_bar_url_default_pb.9.png
mobile/android/base/resources/drawable-hdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-hdpi/address_bar_url_pressed_pb.9.png
mobile/android/base/resources/drawable-hdpi/ic_addons_empty.png
mobile/android/base/resources/drawable-hdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-hdpi/ic_awesomebar_reader.png
mobile/android/base/resources/drawable-hdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-hdpi/ic_awesomebar_star.png
mobile/android/base/resources/drawable-hdpi/ic_awesomebar_tab.png
mobile/android/base/resources/drawable-mdpi/abouthome_icon.png
mobile/android/base/resources/drawable-mdpi/abouthome_logo_dark.png
mobile/android/base/resources/drawable-mdpi/abouthome_logo_light.png
mobile/android/base/resources/drawable-mdpi/abouthome_promo_box_bg.9.png
mobile/android/base/resources/drawable-mdpi/abouthome_promo_box_pressed_bg.9.png
mobile/android/base/resources/drawable-mdpi/abouthome_promo_logo_apps.png
mobile/android/base/resources/drawable-mdpi/abouthome_promo_logo_sync.png
mobile/android/base/resources/drawable-mdpi/abouthome_thumbnail_add.png
mobile/android/base/resources/drawable-mdpi/abouthome_thumbnail_bg.png
mobile/android/base/resources/drawable-mdpi/address_bar_bg_shadow.png
mobile/android/base/resources/drawable-mdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-mdpi/address_bar_url_default_pb.9.png
mobile/android/base/resources/drawable-mdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-mdpi/address_bar_url_pressed_pb.9.png
mobile/android/base/resources/drawable-mdpi/ic_addons_empty.png
mobile/android/base/resources/drawable-mdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-mdpi/ic_awesomebar_reader.png
mobile/android/base/resources/drawable-mdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-mdpi/ic_awesomebar_star.png
mobile/android/base/resources/drawable-mdpi/ic_awesomebar_tab.png
mobile/android/base/resources/drawable-xhdpi/abouthome_icon.png
mobile/android/base/resources/drawable-xhdpi/abouthome_logo_dark.png
mobile/android/base/resources/drawable-xhdpi/abouthome_logo_light.png
mobile/android/base/resources/drawable-xhdpi/abouthome_promo_box_bg.9.png
mobile/android/base/resources/drawable-xhdpi/abouthome_promo_box_pressed_bg.9.png
mobile/android/base/resources/drawable-xhdpi/abouthome_promo_logo_apps.png
mobile/android/base/resources/drawable-xhdpi/abouthome_promo_logo_sync.png
mobile/android/base/resources/drawable-xhdpi/abouthome_thumbnail_add.png
mobile/android/base/resources/drawable-xhdpi/abouthome_thumbnail_bg.png
mobile/android/base/resources/drawable-xhdpi/address_bar_bg_shadow.png
mobile/android/base/resources/drawable-xhdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-xhdpi/address_bar_url_default_pb.9.png
mobile/android/base/resources/drawable-xhdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-xhdpi/address_bar_url_pressed_pb.9.png
mobile/android/base/resources/drawable-xhdpi/ic_addons_empty.png
mobile/android/base/resources/drawable-xhdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-xhdpi/ic_awesomebar_reader.png
mobile/android/base/resources/drawable-xhdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-xhdpi/ic_awesomebar_star.png
mobile/android/base/resources/drawable-xhdpi/ic_awesomebar_tab.png
mobile/android/base/resources/drawable/abouthome_logo.xml
mobile/android/base/resources/drawable/abouthome_promo_box.xml
mobile/android/base/resources/drawable/address_bar_bg.xml
mobile/android/base/resources/drawable/address_bar_bg_shadow_repeat.xml
mobile/android/base/resources/drawable/address_bar_nav_button.xml
mobile/android/base/resources/drawable/address_bar_right_edge.xml
mobile/android/base/resources/drawable/address_bar_url.xml
mobile/android/base/resources/drawable/awesomebar_header_row.xml
mobile/android/base/resources/drawable/awesomebar_listview_divider.xml
mobile/android/base/resources/drawable/awesomebar_tab_indicator.xml
mobile/android/base/resources/drawable/awesomebar_tab_selected.xml
mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml
mobile/android/base/resources/layout-large-v11/awesomebar_search.xml
mobile/android/base/resources/layout-xlarge-land-v11/abouthome_content.xml
mobile/android/base/resources/layout-xlarge-v11/awesomebar_search.xml
mobile/android/base/resources/layout/abouthome_addon_row.xml
mobile/android/base/resources/layout/abouthome_content.xml
mobile/android/base/resources/layout/abouthome_last_tabs_row.xml
mobile/android/base/resources/layout/abouthome_remote_tab_row.xml
mobile/android/base/resources/layout/abouthome_section.xml
mobile/android/base/resources/layout/abouthome_topsite_item.xml
mobile/android/base/resources/layout/awesomebar.xml
mobile/android/base/resources/layout/awesomebar_allpages_list.xml
mobile/android/base/resources/layout/awesomebar_folder_row.xml
mobile/android/base/resources/layout/awesomebar_header_row.xml
mobile/android/base/resources/layout/awesomebar_row.xml
mobile/android/base/resources/layout/awesomebar_search.xml
mobile/android/base/resources/layout/awesomebar_suggestion_prompt.xml
mobile/android/base/resources/layout/awesomebar_tab_indicator.xml
mobile/android/base/resources/layout/awesomebar_tabs.xml
mobile/android/base/resources/menu/abouthome_topsites_contextmenu.xml
mobile/android/base/resources/menu/awesomebar_contextmenu.xml
mobile/android/base/tests/testAllPagesTab.java.in
mobile/android/base/tests/testBookmarksTab.java.in
mobile/android/base/tests/testHistoryTab.java.in
mobile/android/base/tests/testInputAwesomeBar.java.in
mobile/android/base/widget/AboutHome.java
mobile/android/base/widget/AboutHomeSection.java
mobile/android/base/widget/AboutHomeView.java
mobile/android/base/widget/AddonsSection.java
mobile/android/base/widget/LastTabsSection.java
mobile/android/base/widget/LinkTextView.java
mobile/android/base/widget/PromoBox.java
mobile/android/base/widget/RemoteTabsSection.java
mobile/android/base/widget/TopSitesView.java
mobile/android/chrome/content/browser.js
--- a/build/mobile/robocop/Actions.java.in
+++ b/build/mobile/robocop/Actions.java.in
@@ -78,12 +78,19 @@ public interface Actions {
      * @param key The special key to send
      */
     void sendSpecialKey(SpecialKey key);
     void sendKeyCode(int keyCode);
 
     void drag(int startingX, int endingX, int startingY, int endingY);
 
     /**
+     * This is the implementation of clickLongOnScreen from Robotium 4.0 since this sometimes fails for Robotium 3.6
+     * TODO : Remove this when Robotium is updated
+     */
+
+    void clickLongOnScreen(float x, float y);
+
+    /**
      * Run a sql query on the specified database
      */
     public Cursor querySql(String dbPath, String sql);
 }
--- a/build/mobile/robocop/FennecNativeActions.java.in
+++ b/build/mobile/robocop/FennecNativeActions.java.in
@@ -17,17 +17,19 @@ import java.util.ArrayList;
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.database.Cursor;
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 
 import com.jayway.android.robotium.solo.Solo;
 
 import static @ANDROID_PACKAGE_NAME@.FennecNativeDriver.LogLevel;
 
 public class FennecNativeActions implements Actions {
     private Solo mSolo;
     private Instrumentation mInstr;
@@ -453,16 +455,51 @@ public class FennecNativeActions impleme
     public void sendKeys(String input) {
         mInstr.sendStringSync(input);
     }
 
     public void drag(int startingX, int endingX, int startingY, int endingY) {
         mSolo.drag(startingX, endingX, startingY, endingY, 10);
     }
 
+     /**
+     * This is the implementation of clickLongOnScreen from Robotium 4.0 since this sometimes fails for Robotium 3.6
+     * TODO : Remove this when Robotium is updated
+     */
+
+    public void clickLongOnScreen(float x, float y) {
+    	boolean successfull = false;
+        int retry = 0;
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
+
+        while(!successfull && retry < 10) {
+            try{
+                mInstr.sendPointerSync(event);
+                successfull = true;
+            }catch(SecurityException e){
+                FennecNativeDriver.log(LogLevel.ERROR, e);
+                retry++;
+            }
+        }
+
+        mAsserter.ok(successfull, "Trying to click on long on screen at (" + x + "," + y + ")", "Was able to click long on screen");
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x + 1.0f, y + 1.0f, 0);
+        mInstr.sendPointerSync(event);
+        mSolo.sleep(((int)(ViewConfiguration.getLongPressTimeout() * 2.5f)));
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        mInstr.sendPointerSync(event);
+        mSolo.sleep(500);
+    }
+
     public Cursor querySql(String dbPath, String sql) {
         try {
             return (Cursor)mQuerySql.invoke(mRobocopApi, dbPath, sql);
         } catch(InvocationTargetException ex) {
             Log.e(LOGTAG, "Error invoking method", ex);
         } catch(IllegalAccessException ex) {
             Log.e(LOGTAG, "Error using field", ex);
         }
--- a/mobile/android/base/ActivityHandlerHelper.java
+++ b/mobile/android/base/ActivityHandlerHelper.java
@@ -31,17 +31,16 @@ import java.util.concurrent.TimeUnit;
 
 public class ActivityHandlerHelper implements GeckoEventListener {
     private static final String LOGTAG = "GeckoActivityHandlerHelper";
 
     private final ConcurrentLinkedQueue<String> mFilePickerResult;
 
     private final ActivityResultHandlerMap mActivityResultHandlerMap;
     private final FilePickerResultHandlerSync mFilePickerResultHandlerSync;
-    private final AwesomebarResultHandler mAwesomebarResultHandler;
     private final CameraImageResultHandler mCameraImageResultHandler;
     private final CameraVideoResultHandler mCameraVideoResultHandler;
 
     public interface FileResultHandler {
         public void gotFile(String filename);
     }
 
     @SuppressWarnings("serial")
@@ -53,17 +52,16 @@ public class ActivityHandlerHelper imple
                     GeckoAppShell.sendEventToGecko(GeckoEvent.createNoOpEvent());
                     return true;
                 }
                 return false;
             }
         };
         mActivityResultHandlerMap = new ActivityResultHandlerMap();
         mFilePickerResultHandlerSync = new FilePickerResultHandlerSync(mFilePickerResult);
-        mAwesomebarResultHandler = new AwesomebarResultHandler();
         mCameraImageResultHandler = new CameraImageResultHandler(mFilePickerResult);
         mCameraVideoResultHandler = new CameraVideoResultHandler(mFilePickerResult);
         GeckoAppShell.getEventDispatcher().registerEventListener("FilePicker:Show", this);
     }
 
     @Override
     public void handleMessage(String event, final JSONObject message) {
         if (event.equals("FilePicker:Show")) {
@@ -86,20 +84,16 @@ public class ActivityHandlerHelper imple
                     }
                     GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(
                         "FilePicker:Result", message.toString()));
                 }
             });
         }
     }
 
-    public int makeRequestCodeForAwesomebar() {
-        return mActivityResultHandlerMap.put(mAwesomebarResultHandler);
-    }
-
     public int makeRequestCode(ActivityResultHandler aHandler) {
         return mActivityResultHandlerMap.put(aHandler);
     }
 
     public void startIntentForActivity (Activity activity, Intent intent, ActivityResultHandler activityResultHandler) {
         activity.startActivityForResult(intent, mActivityResultHandlerMap.put(activityResultHandler));
     }
 
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -225,21 +225,16 @@
         <activity android:name="org.mozilla.gecko.VideoPlayer"
                   android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation"
                   android:theme="@android:style/Theme.NoTitleBar">
             <intent-filter>
                 <action android:name="org.mozilla.gecko.PLAY_VIDEO" />
             </intent-filter>
         </activity>
 
-        <activity android:name="org.mozilla.gecko.AwesomeBar"
-                  android:theme="@style/Gecko.AwesomeBar"
-                  android:configChanges="orientation|screenSize"
-                  android:windowSoftInputMode="stateUnspecified|adjustResize"/>
-
         <activity android:name="org.mozilla.gecko.GeckoPreferences"
                   android:theme="@style/Gecko.Preferences"
                   android:label="@string/settings_title"
                   android:configChanges="orientation|screenSize"
                   android:excludeFromRecents="true"/>
 
         <provider android:name="org.mozilla.gecko.db.BrowserProvider"
                   android:authorities="@ANDROID_PACKAGE_NAME@.db.browser"
--- a/mobile/android/base/AnimatedHeightLayout.java
+++ b/mobile/android/base/AnimatedHeightLayout.java
@@ -12,18 +12,22 @@ import android.view.animation.Animation;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.RelativeLayout;
 
 public class AnimatedHeightLayout extends RelativeLayout {
     private static final String LOGTAG = "GeckoAnimatedHeightLayout";
     private static final int ANIMATION_DURATION = 100;
     private boolean mAnimating = false;
 
+    public AnimatedHeightLayout(Context context) {
+        super(context, null);
+    }
+
     public AnimatedHeightLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
+        super(context, attrs, 0);
     }
 
     public AnimatedHeightLayout(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/AutocompleteHandler.java
@@ -0,0 +1,10 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko;
+
+public interface AutocompleteHandler {
+    void onAutocomplete(String res);
+}
deleted file mode 100644
--- a/mobile/android/base/AwesomeBar.java
+++ /dev/null
@@ -1,730 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.health.BrowserHealthRecorder;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.StringUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.util.UiAsyncTask;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.os.Bundle;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.Spanned;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.TabWidget;
-import android.widget.Toast;
-
-import org.json.JSONObject;
-
-import java.net.URLEncoder;
-
-interface AutocompleteHandler {
-    void onAutocomplete(String res);
-}
-
-public class AwesomeBar extends GeckoActivity
-                        implements AutocompleteHandler,
-                                   TextWatcher {
-    private static final String LOGTAG = "GeckoAwesomeBar";
-
-    public static final String URL_KEY = "url";
-    public static final String TAB_KEY = "tab";
-    public static final String CURRENT_URL_KEY = "currenturl";
-    public static final String TARGET_KEY = "target";
-    public static final String SEARCH_KEY = "search";
-    public static final String TITLE_KEY = "title";
-    public static final String USER_ENTERED_KEY = "user_entered";
-    public static final String READING_LIST_KEY = "reading_list";
-    public static enum Target { NEW_TAB, CURRENT_TAB, PICK_SITE };
-
-    private String mTarget;
-    private AwesomeBarTabs mAwesomeTabs;
-    private CustomEditText mText;
-    private ImageButton mGoButton;
-    private ContextMenuSubject mContextMenuSubject;
-    private boolean mDelayRestartInput;
-    // The previous autocomplete result returned to us
-    private String mAutoCompleteResult = "";
-    // The user typed part of the autocomplete result
-    private String mAutoCompletePrefix = null;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        LayoutInflater.from(this).setFactory(this);
-
-        super.onCreate(savedInstanceState);
-
-        Log.d(LOGTAG, "creating awesomebar");
-
-        setContentView(R.layout.awesomebar);
-
-        mGoButton = (ImageButton) findViewById(R.id.awesomebar_button);
-        mText = (CustomEditText) findViewById(R.id.awesomebar_text);
-
-        TabWidget tabWidget = (TabWidget) findViewById(android.R.id.tabs);
-        tabWidget.setDividerDrawable(null);
-
-        mAwesomeTabs = (AwesomeBarTabs) findViewById(R.id.awesomebar_tabs);
-        mAwesomeTabs.setOnUrlOpenListener(new AwesomeBarTabs.OnUrlOpenListener() {
-            @Override
-            public void onUrlOpen(String url, String title) {
-                openUrlAndFinish(url, title, false);
-            }
-
-            @Override
-            public void onSearch(SearchEngine engine, String text) {
-                Intent resultIntent = new Intent();
-                resultIntent.putExtra(URL_KEY, text);
-                resultIntent.putExtra(TARGET_KEY, mTarget);
-                resultIntent.putExtra(SEARCH_KEY, engine.name);
-                recordSearch(engine.identifier, "barsuggest");
-                finishWithResult(resultIntent);
-            }
-
-            @Override
-            public void onEditSuggestion(final String text) {
-                ThreadUtils.postToUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        mText.setText(text);
-                        mText.setSelection(mText.getText().length());
-                        mText.requestFocus();
-                    }
-                });
-            }
-
-            @Override
-            public void onSwitchToTab(final int tabId) {
-                Intent resultIntent = new Intent();
-                resultIntent.putExtra(TAB_KEY, Integer.toString(tabId));
-                finishWithResult(resultIntent);
-            }
-        });
-
-        mGoButton.setOnClickListener(new Button.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                openUserEnteredAndFinish(mText.getText().toString());
-            }
-        });
-
-        Intent intent = getIntent();
-        String currentUrl = intent.getStringExtra(CURRENT_URL_KEY);
-        if (currentUrl != null) {
-            mText.setText(currentUrl);
-            mText.selectAll();
-        }
-
-        mTarget = intent.getStringExtra(TARGET_KEY);
-        if (mTarget.equals(Target.CURRENT_TAB.name())) {
-            Tab tab = Tabs.getInstance().getSelectedTab();
-            if (tab != null && tab.isPrivate()) {
-                BrowserToolbarBackground mAddressBarBg = (BrowserToolbarBackground) findViewById(R.id.address_bar_bg);
-                mAddressBarBg.setPrivateMode(true);
-
-                ShapedButton mTabs = (ShapedButton) findViewById(R.id.dummy_tab);
-                if (mTabs != null)
-                    mTabs.setPrivateMode(true);
-
-                mText.setPrivateMode(true);
-            }
-        }
-        mAwesomeTabs.setTarget(mTarget);
-
-        mText.setOnKeyPreImeListener(new CustomEditText.OnKeyPreImeListener() {
-            @Override
-            public boolean onKeyPreIme(View v, int keyCode, KeyEvent event) {
-                // We only want to process one event per tap
-                if (event.getAction() != KeyEvent.ACTION_DOWN)
-                    return false;
-
-                if (keyCode == KeyEvent.KEYCODE_ENTER) {
-                    // If the AwesomeBar has a composition string, don't submit the text yet.
-                    // ENTER is needed to commit the composition string.
-                    Editable content = mText.getText();
-                    if (!hasCompositionString(content)) {
-                        openUserEnteredAndFinish(content.toString());
-                        return true;
-                    }
-                }
-
-                // If input method is in fullscreen mode, we want to dismiss
-                // it instead of closing awesomebar straight away.
-                InputMethodManager imm =
-                        (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-                if (keyCode == KeyEvent.KEYCODE_BACK && !imm.isFullscreenMode()) {
-                    return handleBackKey();
-                }
-
-                return false;
-            }
-        });
-
-        mText.addTextChangedListener(this);
-
-        mText.setOnKeyListener(new View.OnKeyListener() {
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_ENTER) {
-                    if (event.getAction() != KeyEvent.ACTION_DOWN)
-                        return true;
-
-                    openUserEnteredAndFinish(mText.getText().toString());
-                    return true;
-                } else if (GamepadUtils.isBackKey(event)) {
-                    return handleBackKey();
-                } else {
-                    return false;
-                }
-            }
-        });
-
-        mText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                if (v == null || hasFocus) {
-                    return;
-                }
-
-                InputMethodManager imm = (InputMethodManager)
-                    getSystemService(Context.INPUT_METHOD_SERVICE);
-                try {
-                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
-                } catch (NullPointerException e) {
-                    Log.e(LOGTAG, "InputMethodManagerService, why are you throwing"
-                                  + " a NullPointerException? See bug 782096", e);
-                }
-            }
-        });
-
-        boolean showReadingList = intent.getBooleanExtra(READING_LIST_KEY, false);
-        if (showReadingList) {
-            BookmarksTab bookmarksTab = mAwesomeTabs.getBookmarksTab();
-            bookmarksTab.setShowReadingList(true);
-            mAwesomeTabs.setCurrentItemByTag(bookmarksTab.getTag());
-        }
-    }
-
-    private boolean handleBackKey() {
-        // Let mAwesomeTabs try to handle the back press, since we may be in a
-        // bookmarks sub-folder.
-        if (mAwesomeTabs.onBackPressed())
-            return true;
-
-        // If mAwesomeTabs.onBackPressed() returned false, we didn't move up
-        // a folder level, so just exit the activity.
-        cancelAndFinish();
-        return true;
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfiguration) {
-        super.onConfigurationChanged(newConfiguration);
-    }
-
-    @Override
-    public boolean onSearchRequested() {
-        cancelAndFinish();
-        return true;
-    }
-
-    private void updateGoButton(String text) {
-        if (text.length() == 0) {
-            mGoButton.setVisibility(View.GONE);
-            return;
-        }
-
-        mGoButton.setVisibility(View.VISIBLE);
-
-        int imageResource = R.drawable.ic_awesomebar_go;
-        String contentDescription = getString(R.string.go);
-        int imeAction = EditorInfo.IME_ACTION_GO;
-
-        int actionBits = mText.getImeOptions() & EditorInfo.IME_MASK_ACTION;
-        if (StringUtils.isSearchQuery(text, actionBits == EditorInfo.IME_ACTION_SEARCH)) {
-            imageResource = R.drawable.ic_awesomebar_search;
-            contentDescription = getString(R.string.search);
-            imeAction = EditorInfo.IME_ACTION_SEARCH;
-        }
-
-        InputMethodManager imm = InputMethods.getInputMethodManager(mText.getContext());
-        if (imm == null) {
-            return;
-        }
-        boolean restartInput = false;
-        if (actionBits != imeAction) {
-            int optionBits = mText.getImeOptions() & ~EditorInfo.IME_MASK_ACTION;
-            mText.setImeOptions(optionBits | imeAction);
-
-            mDelayRestartInput = (imeAction == EditorInfo.IME_ACTION_GO) &&
-                                 (InputMethods.shouldDelayAwesomebarUpdate(mText.getContext()));
-            if (!mDelayRestartInput) {
-                restartInput = true;
-            }
-        } else if (mDelayRestartInput) {
-            // Only call delayed restartInput when actionBits == imeAction
-            // so if there are two restarts in a row, the first restarts will
-            // be discarded and the second restart will be properly delayed
-            mDelayRestartInput = false;
-            restartInput = true;
-        }
-        if (restartInput) {
-            updateKeyboardInputType();
-            imm.restartInput(mText);
-            mGoButton.setImageResource(imageResource);
-            mGoButton.setContentDescription(contentDescription);
-        }
-    }
-
-    private void updateKeyboardInputType() {
-        // If the user enters a space, then we know they are entering search terms, not a URL.
-        // We can then switch to text mode so,
-        // 1) the IME auto-inserts spaces between words
-        // 2) the IME doesn't reset input keyboard to Latin keyboard.
-        String text = mText.getText().toString();
-        int currentInputType = mText.getInputType();
-        int newInputType = StringUtils.isSearchQuery(text, false)
-                           ? (currentInputType & ~InputType.TYPE_TEXT_VARIATION_URI) // Text mode
-                           : (currentInputType | InputType.TYPE_TEXT_VARIATION_URI); // URL mode
-        if (newInputType != currentInputType) {
-            mText.setRawInputType(newInputType);
-        }
-    }
-
-    private void cancelAndFinish() {
-        setResult(Activity.RESULT_CANCELED);
-        finish();
-        overridePendingTransition(R.anim.awesomebar_hold_still, R.anim.awesomebar_fade_out);
-    }
-
-    private void finishWithResult(Intent intent) {
-        setResult(Activity.RESULT_OK, intent);
-        finish();
-        overridePendingTransition(R.anim.awesomebar_hold_still, R.anim.awesomebar_fade_out);
-    }
-
-    private void openUrlAndFinish(String url) {
-        openUrlAndFinish(url, null, false);
-    }
-
-    private void openUrlAndFinish(String url, String title, boolean userEntered) {
-        Intent resultIntent = new Intent();
-        resultIntent.putExtra(URL_KEY, url);
-        if (title != null && !TextUtils.isEmpty(title))
-            resultIntent.putExtra(TITLE_KEY, title);
-        if (userEntered)
-            resultIntent.putExtra(USER_ENTERED_KEY, userEntered);
-        resultIntent.putExtra(TARGET_KEY, mTarget);
-        finishWithResult(resultIntent);
-    }
-
-    /**
-     * Record in Health Report that a search has occurred.
-     *
-     * @param identifier
-     *        a search identifier, such as "partnername". Can be null.
-     * @param where
-     *        where the search was initialized; one of the values in
-     *        {@link BrowserHealthRecorder#SEARCH_LOCATIONS}.
-     */
-    private static void recordSearch(String identifier, String where) {
-        Log.i(LOGTAG, "Recording search: " + identifier + ", " + where);
-        try {
-            JSONObject message = new JSONObject();
-            message.put("type", BrowserHealthRecorder.EVENT_SEARCH);
-            message.put("location", where);
-            message.put("identifier", identifier);
-            GeckoAppShell.getEventDispatcher().dispatchEvent(message);
-        } catch (Exception e) {
-            Log.w(LOGTAG, "Error recording search.", e);
-        }
-    }
-
-    private void openUserEnteredAndFinish(final String url) {
-        final int index = url.indexOf(' ');
-
-        // Check for a keyword if the URL looks like a search query
-        if (!StringUtils.isSearchQuery(url, true)) {
-            openUrlAndFinish(url, "", true);
-            return;
-        }
-        ThreadUtils.postToBackgroundThread(new Runnable() {
-            @Override
-            public void run() {
-                final String keyword;
-                final String keywordSearch;
-
-                if (index == -1) {
-                    keyword = url;
-                    keywordSearch = "";
-                } else {
-                    keyword = url.substring(0, index);
-                    keywordSearch = url.substring(index + 1);
-                }
-
-                final String keywordUrl = BrowserDB.getUrlForKeyword(getContentResolver(), keyword);
-                final String searchUrl = (keywordUrl != null)
-                                       ? keywordUrl.replace("%s", URLEncoder.encode(keywordSearch))
-                                       : url;
-                if (keywordUrl != null) {
-                    recordSearch(null, "barkeyword");
-                }
-                openUrlAndFinish(searchUrl, "", true);
-            }
-        });
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        // Galaxy Note sends key events for the stylus that are outside of the
-        // valid keyCode range (see bug 758427)
-        if (keyCode > KeyEvent.getMaxKeyCode())
-            return true;
-
-        // This method is called only if the key event was not handled
-        // by any of the views, which usually means the edit box lost focus
-        if (keyCode == KeyEvent.KEYCODE_BACK ||
-            keyCode == KeyEvent.KEYCODE_MENU ||
-            keyCode == KeyEvent.KEYCODE_DPAD_UP ||
-            keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
-            keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
-            keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
-            keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
-            keyCode == KeyEvent.KEYCODE_DEL ||
-            keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
-            keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
-            GamepadUtils.isActionKey(event)) {
-            return super.onKeyDown(keyCode, event);
-        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
-             mText.setText("");
-             mText.requestFocus();
-             return true;
-        } else {
-            int prevSelStart = mText.getSelectionStart();
-            int prevSelEnd = mText.getSelectionEnd();
-
-            // Manually dispatch the key event to the AwesomeBar. If selection changed as
-            // a result of the key event, then give focus back to mText
-            mText.dispatchKeyEvent(event);
-
-            int curSelStart = mText.getSelectionStart();
-            int curSelEnd = mText.getSelectionEnd();
-            if (prevSelStart != curSelStart || prevSelEnd != curSelEnd) {
-                mText.requestFocusFromTouch();
-                // Restore the selection, which gets lost due to the focus switch
-                mText.setSelection(curSelStart, curSelEnd);
-            }
-            return true;
-        }
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        if (mText != null && mText.getText() != null) {
-            updateGoButton(mText.getText().toString());
-            if (mDelayRestartInput) {
-                // call updateGoButton again to force a restartInput call
-                updateGoButton(mText.getText().toString());
-            }
-        }
-
-        // Invlidate the cached value that keeps track of whether or
-        // not desktop bookmarks exist
-        BrowserDB.invalidateCachedState();
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        mAwesomeTabs.destroy();
-    }
-
-    @Override
-    public void onBackPressed() {
-        // Let mAwesomeTabs try to handle the back press, since we may be in a
-        // bookmarks sub-folder.
-        if (mAwesomeTabs.onBackPressed())
-            return;
-
-        // Otherwise, just exit the awesome screen
-        cancelAndFinish();
-    }
-
-    static public class ContextMenuSubject {
-        public int id;
-        public String url;
-        public byte[] favicon;
-        public String title;
-        public String keyword;
-        public int display;
-
-        public ContextMenuSubject(int id, String url, byte[] favicon, String title, String keyword) {
-            this(id, url, favicon, title, keyword, Combined.DISPLAY_NORMAL);
-        }
-
-        public ContextMenuSubject(int id, String url, byte[] favicon, String title, String keyword, int display) {
-            this.id = id;
-            this.url = url;
-            this.favicon = favicon;
-            this.title = title;
-            this.keyword = keyword;
-            this.display = display;
-        }
-    };
-
-    @Override
-    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
-        super.onCreateContextMenu(menu, view, menuInfo);
-        AwesomeBarTab tab = mAwesomeTabs.getAwesomeBarTabForView(view);
-        mContextMenuSubject = tab.getSubject(menu, view, menuInfo);
-    }
-
-    @Override
-    public boolean onContextItemSelected(MenuItem item) {
-        if (mContextMenuSubject == null)
-            return false;
-
-        final int id = mContextMenuSubject.id;
-        final String url = mContextMenuSubject.url;
-        final byte[] b = mContextMenuSubject.favicon;
-        final String title = mContextMenuSubject.title;
-        final String keyword = mContextMenuSubject.keyword;
-        final int display = mContextMenuSubject.display;
-
-        final int itemId = item.getItemId();
-        if (itemId == R.id.open_private_tab || itemId == R.id.open_new_tab) {
-            if (url == null) {
-                Log.e(LOGTAG, "Can't open in new tab because URL is null");
-            }
-
-            String newTabUrl = url;
-            if (display == Combined.DISPLAY_READER)
-                newTabUrl = ReaderModeUtils.getAboutReaderForUrl(url, true);
-
-            int flags = Tabs.LOADURL_NEW_TAB;
-            if (item.getItemId() == R.id.open_private_tab)
-                flags |= Tabs.LOADURL_PRIVATE;
-
-            Tabs.getInstance().loadUrl(newTabUrl, flags);
-            Toast.makeText(this, R.string.new_tab_opened, Toast.LENGTH_SHORT).show();
-
-            return true;
-        }
-
-        if (itemId == R.id.open_in_reader) {
-            if (url == null) {
-                Log.e(LOGTAG, "Can't open in reader mode because URL is null");
-            } else {
-                openUrlAndFinish(ReaderModeUtils.getAboutReaderForUrl(url, true));
-            }
-            return true;
-        }
-
-        if (itemId == R.id.edit_bookmark) {
-            new EditBookmarkDialog(this).show(id, title, url, keyword);
-            return true;
-        }
-
-        if (itemId == R.id.remove_bookmark) {
-            (new UiAsyncTask<Void, Void, Integer>(ThreadUtils.getBackgroundHandler()) {
-                private boolean mInReadingList;
-
-                @Override
-                public void onPreExecute() {
-                    mInReadingList = mAwesomeTabs.isInReadingList();
-                }
-
-                @Override
-                public Integer doInBackground(Void... params) {
-                    BrowserDB.removeBookmark(getContentResolver(), id);
-                    Integer count = mInReadingList ?
-                        BrowserDB.getReadingListCount(getContentResolver()) : 0;
-
-                    return count;
-                }
-
-                @Override
-                public void onPostExecute(Integer aCount) {
-                    int messageId = R.string.bookmark_removed;
-                    if (mInReadingList) {
-                        messageId = R.string.reading_list_removed;
-
-                        GeckoEvent e = GeckoEvent.createBroadcastEvent("Reader:Remove", url);
-                        GeckoAppShell.sendEventToGecko(e);
-
-                        // Delete from Awesomebar context menu can alter reading list bookmark count
-                        e = GeckoEvent.createBroadcastEvent("Reader:ListCountUpdated", Integer.toString(aCount));
-                        GeckoAppShell.sendEventToGecko(e);
-                    }
-
-                    Toast.makeText(AwesomeBar.this, messageId, Toast.LENGTH_SHORT).show();
-                }
-            }).execute();
-
-            return true;
-        }
-
-        if (itemId == R.id.remove_history) {
-            (new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) {
-                @Override
-                public Void doInBackground(Void... params) {
-                    BrowserDB.removeHistoryEntry(getContentResolver(), id);
-                    return null;
-                }
-
-                @Override
-                public void onPostExecute(Void result) {
-                    Toast.makeText(AwesomeBar.this, R.string.history_removed, Toast.LENGTH_SHORT).show();
-                }
-            }).execute();
-
-            return true;
-        }
-
-        if (itemId == R.id.add_to_launcher) {
-            if (url == null) {
-                Log.e(LOGTAG, "Can't add to home screen because URL is null");
-            } else {
-                Bitmap bitmap = null;
-                if (b != null) {
-                    bitmap = BitmapUtils.decodeByteArray(b);
-                }
-
-                String shortcutTitle = TextUtils.isEmpty(title) ? url.replaceAll("^([a-z]+://)?(www\\.)?", "") : title;
-                GeckoAppShell.createShortcut(shortcutTitle, url, bitmap, "");
-            }
-
-            return true;
-        }
-
-        if (itemId == R.id.share) {
-            if (url == null) {
-                Log.e(LOGTAG, "Can't share because URL is null");
-            } else {
-                GeckoAppShell.openUriExternal(url, "text/plain", "", "",
-                                              Intent.ACTION_SEND, title);
-            }
-
-            return true;
-        }
-
-        return super.onContextItemSelected(item);
-    }
-
-    public static String getReaderForUrl(String url) {
-        // FIXME: still need to define the final way to open items from
-        // reading list. For now, we're using an about:reader page.
-        return "about:reader?url=" + Uri.encode(url) + "&readingList=1";
-    }
-
-    private static boolean hasCompositionString(Editable content) {
-        Object[] spans = content.getSpans(0, content.length(), Object.class);
-        if (spans != null) {
-            for (Object span : spans) {
-                if ((content.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
-                    // Found composition string.
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    // return early if we're backspacing through the string, or have no autocomplete results
-    public void onAutocomplete(final String result) {
-        final String text = mText.getText().toString();
-
-        if (result == null) {
-            mAutoCompleteResult = "";
-            return;
-        }
-
-        if (!result.startsWith(text) || text.equals(result)) {
-            return;
-        }
-
-        mAutoCompleteResult = result;
-        mText.getText().append(result.substring(text.length()));
-        mText.setSelection(text.length(), result.length());
-    }
-
-    @Override
-    public void afterTextChanged(final Editable s) {
-        final String text = s.toString();
-        boolean useHandler = false;
-        boolean reuseAutocomplete = false;
-        if (!hasCompositionString(s) && !StringUtils.isSearchQuery(text, false)) {
-            useHandler = true;
-
-            // If you're hitting backspace (the string is getting smaller
-            // or is unchanged), don't autocomplete.
-            if (mAutoCompletePrefix != null && (mAutoCompletePrefix.length() >= text.length())) {
-                useHandler = false;
-            } else if (mAutoCompleteResult != null && mAutoCompleteResult.startsWith(text)) {
-                // If this text already matches our autocomplete text, autocomplete likely
-                // won't change. Just reuse the old autocomplete value.
-                useHandler = false;
-                reuseAutocomplete = true;
-            }
-        }
-
-        // If this is the autocomplete text being set, don't run the filter.
-        if (TextUtils.isEmpty(mAutoCompleteResult) || !mAutoCompleteResult.equals(text)) {
-            mAwesomeTabs.filter(text, useHandler ? this : null);
-            mAutoCompletePrefix = text;
-
-            if (reuseAutocomplete) {
-                onAutocomplete(mAutoCompleteResult);
-            }
-        }
-
-        // If the AwesomeBar has a composition string, don't call updateGoButton().
-        // That method resets IME and composition state will be broken.
-        if (!hasCompositionString(s) ||
-            InputMethods.isGestureKeyboard(mText.getContext())) {
-            updateGoButton(text);
-        }
-    }
-
-    @Override
-    public void beforeTextChanged(CharSequence s, int start, int count,
-                                  int after) {
-        // do nothing
-    }
-
-    @Override
-    public void onTextChanged(CharSequence s, int start, int before,
-                              int count) {
-        // do nothing
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/AwesomeBarTabs.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import android.content.Context;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.StateListDrawable;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TabHost;
-import android.widget.TabWidget;
-
-public class AwesomeBarTabs extends TabHost
-                            implements LightweightTheme.OnChangeListener { 
-    private static final String LOGTAG = "GeckoAwesomeBarTabs";
-
-    private Context mContext;
-    private GeckoActivity mActivity;
-
-    private boolean mInflated;
-    private LayoutInflater mInflater;
-    private OnUrlOpenListener mUrlOpenListener;
-    private View.OnTouchListener mListTouchListener;
-    private boolean mSearching = false;
-    private String mTarget;
-    private ViewPager mViewPager;
-    private AwesomePagerAdapter mPagerAdapter;
-
-    private AwesomeBarTab mTabs[];
-
-    public interface OnUrlOpenListener {
-        public void onUrlOpen(String url, String title);
-        public void onSearch(SearchEngine engine, String text);
-        public void onEditSuggestion(String suggestion);
-        public void onSwitchToTab(final int tabId);
-    }
-
-    private class AwesomePagerAdapter extends PagerAdapter {
-        public AwesomePagerAdapter() {
-            super();
-        }
-
-        @Override
-        public Object instantiateItem(ViewGroup group, int index) {
-            AwesomeBarTab tab = mTabs[index];
-            group.addView(tab.getView());
-            return tab;
-        }
-
-        @Override
-        public void destroyItem(ViewGroup group, int index, Object obj) {
-            AwesomeBarTab tab = (AwesomeBarTab)obj;
-            group.removeView(tab.getView());
-        }
-
-        @Override
-        public int getCount() {
-            if (mSearching)
-                return 1;
-            return mTabs.length;
-        }
-
-        @Override
-        public boolean isViewFromObject(View view, Object object) {
-            return getAwesomeBarTabForView(view) == object;
-        }
-    }
-
-    private AwesomeBarTab getCurrentAwesomeBarTab() {
-        int index = mViewPager.getCurrentItem();
-        return mTabs[index];
-    }
-
-    public AwesomeBarTab getAwesomeBarTabForView(View view) {
-        String tag = (String)view.getTag();
-        return getAwesomeBarTabForTag(tag);
-    }
-
-    public AwesomeBarTab getAwesomeBarTabForTag(String tag) {
-        for (AwesomeBarTab tab : mTabs) {
-            if (tag.equals(tab.getTag())) {
-                return tab;
-            }
-        }
-        return null;
-    }
-
-    public boolean onBackPressed() {
-        AwesomeBarTab tab = getCurrentAwesomeBarTab();
-        if (tab == null)
-             return false;
-        return tab.onBackPressed();
-    }
-
-    public AwesomeBarTabs(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        Log.d(LOGTAG, "Creating AwesomeBarTabs");
-
-        mContext = context;
-        mActivity = (GeckoActivity) context;
-
-        mInflated = false;
-        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        // HACK: Without this, the onFinishInflate is called twice
-        // This issue is due to a bug when Android inflates a layout with a
-        // parent. Fixed in Honeycomb
-        if (mInflated)
-            return;
-
-        mInflated = true;
-
-        // This should be called before adding any tabs
-        // to the TabHost.
-        setup();
-
-        mListTouchListener = new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View view, MotionEvent event) {
-                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
-                    // take focus away from awesome bar to hide the keyboard
-                    requestFocus();
-                }
-                return false;
-            }
-        };
-
-        mTabs = new AwesomeBarTab[] {
-            new AllPagesTab(mContext),
-            new BookmarksTab(mContext),
-            new HistoryTab(mContext)
-        };
-
-        final TabWidget tabWidget = (TabWidget) findViewById(android.R.id.tabs);
-        // hide the strip since we aren't using the TabHost...
-        tabWidget.setStripEnabled(false);
-
-        mViewPager = (ViewPager) findViewById(R.id.tabviewpager);
-        mPagerAdapter = new AwesomePagerAdapter();
-        mViewPager.setAdapter(mPagerAdapter);
-
-        mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
-            @Override
-            public void onPageScrollStateChanged(int state) { }
-            @Override
-            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
-            @Override
-            public void onPageSelected(int position) {
-                tabWidget.setCurrentTab(position);
-                styleSelectedTab();
-                // take focus away from awesome bar to hide the keyboard
-                requestFocus();
-             }
-         });
-
-        for (int i = 0; i < mTabs.length; i++) {
-            mTabs[i].setListTouchListener(mListTouchListener);
-            addAwesomeTab(mTabs[i].getTag(),
-                          mTabs[i].getTitleStringId(),
-                          i);
-        }
-
-        // Initialize "All Pages" list with no filter
-        filter("", null);
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mActivity.getLightweightTheme().addListener(this);
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mActivity.getLightweightTheme().removeListener(this);
-    }
-
-    @Override
-    public void onLightweightThemeChanged() {
-        styleSelectedTab();
-    }
-
-    @Override
-    public void onLightweightThemeReset() {
-        styleSelectedTab();
-    }
-
-    public void setCurrentItemByTag(String tag) {
-        mViewPager.setCurrentItem(getTabIdByTag(tag));
-    }
-
-    public int getTabIdByTag(String tag) {
-        for (int i = 0; i < mTabs.length; i++) {
-            if (tag.equals(mTabs[i].getTag())) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    private void styleSelectedTab() {
-        int selIndex = mViewPager.getCurrentItem();
-        TabWidget tabWidget = getTabWidget();
-        boolean isPrivate = false;
-
-        if (mTarget != null && mTarget.equals(AwesomeBar.Target.CURRENT_TAB.name())) {
-            Tab tab = Tabs.getInstance().getSelectedTab();
-            if (tab != null)
-                isPrivate = tab.isPrivate();
-        }
-
-        for (int i = 0; i < tabWidget.getTabCount(); i++) {
-            GeckoTextView view = (GeckoTextView) tabWidget.getChildTabViewAt(i);
-            if (isPrivate) {
-                view.resetTheme();
-                view.setPrivateMode((i == selIndex) ? false : true);
-            } else {
-                if (i == selIndex)
-                    view.resetTheme();
-                else if (mActivity.getLightweightTheme().isEnabled())
-                    view.setTheme(mActivity.getLightweightTheme().isLightTheme());
-                else
-                    view.resetTheme();
-            }
-
-            if (i < (selIndex - 1))
-                view.getBackground().setLevel(3);
-            else if (i == (selIndex - 1))
-                view.getBackground().setLevel(1);
-            else if (i == (selIndex + 1))
-                view.getBackground().setLevel(2);
-            else if (i > (selIndex + 1))
-                view.getBackground().setLevel(4);
-        }
-
-        if (selIndex == 0)
-            findViewById(R.id.tab_widget_left).getBackground().setLevel(1);
-        else
-            findViewById(R.id.tab_widget_left).getBackground().setLevel(0);
-
-        if (selIndex == (tabWidget.getTabCount() - 1))
-            findViewById(R.id.tab_widget_right).getBackground().setLevel(2);
-        else
-            findViewById(R.id.tab_widget_right).getBackground().setLevel(0);
-    }
-
-
-    private View addAwesomeTab(String id, int titleId, final int contentId) {
-        GeckoTextView indicatorView = (GeckoTextView) mInflater.inflate(R.layout.awesomebar_tab_indicator, null);
-        indicatorView.setText(titleId);
-
-        getTabWidget().addView(indicatorView);
-
-        // this MUST be done after tw.addView to overwrite the listener added by tabWidget
-        // which delegates to TabHost (which we don't have)
-        indicatorView.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mViewPager.setCurrentItem(contentId, true);
-            }
-        });
-
-        return indicatorView;
-    }
-
-    public void setOnUrlOpenListener(OnUrlOpenListener listener) {
-        mUrlOpenListener = listener;
-        for (AwesomeBarTab tab : mTabs) {
-            tab.setUrlListener(listener);
-        }
-    }
-
-    public void destroy() {
-        for (AwesomeBarTab tab : mTabs) {
-            tab.destroy();
-        }
-    }
-
-    public AllPagesTab getAllPagesTab() {
-        return (AllPagesTab)getAwesomeBarTabForTag("allPages");
-    }
-
-    public BookmarksTab getBookmarksTab() {
-        return (BookmarksTab)getAwesomeBarTabForTag("bookmarks");
-    }
-
-    public HistoryTab getHistoryTab() {
-        return (HistoryTab)getAwesomeBarTabForTag("history");
-    }
-
-    public void filter(String searchTerm, AutocompleteHandler handler) {
-
-        // If searching, disable left / right tab swipes
-        mSearching = searchTerm.length() != 0;
-
-        // reset the pager adapter to force repopulating the cache
-        mViewPager.setAdapter(mPagerAdapter);
-
-        // Ensure the 'All Pages' tab is selected
-        AllPagesTab allPages = getAllPagesTab();
-        getTabWidget().setCurrentTab(getTabIdByTag(allPages.getTag()));
-        styleSelectedTab();
-
-        // Perform the actual search
-        allPages.filter(searchTerm, handler);
-
-        // If searching, hide the tabs bar
-        findViewById(R.id.tab_widget_container).setVisibility(mSearching ? View.GONE : View.VISIBLE);
-    }
-
-    public boolean isInReadingList() {
-        return getBookmarksTab().isInReadingList();
-    }
-
-    public void setTarget(String target) {
-        mTarget = target;
-        styleSelectedTab();
-        if (mTarget.equals(AwesomeBar.Target.CURRENT_TAB.name())) {
-            Tab tab = Tabs.getInstance().getSelectedTab();
-            if (tab != null && tab.isPrivate())
-                ((BackgroundLayout) findViewById(R.id.tab_widget_container)).setPrivateMode(true);
-        }
-    }
-
-    public static class BackgroundLayout extends GeckoLinearLayout {
-        private GeckoActivity mActivity;
-
-        public BackgroundLayout(Context context, AttributeSet attrs) {
-            super(context, attrs);
-            mActivity = (GeckoActivity) context;
-        }
-
-        @Override
-        public void onLightweightThemeChanged() {
-            LightweightThemeDrawable drawable = mActivity.getLightweightTheme().getColorDrawable(this);
-            if (drawable == null)
-                return;
-
-            drawable.setAlpha(255, 0);
-
-            StateListDrawable stateList = new StateListDrawable();
-            stateList.addState(new int[] { R.attr.state_private }, new ColorDrawable(mActivity.getResources().getColor(R.color.background_private)));
-            stateList.addState(new int[] {}, drawable);
-
-            int[] padding =  new int[] { getPaddingLeft(),
-                                         getPaddingTop(),
-                                         getPaddingRight(),
-                                         getPaddingBottom()
-                                       };
-            setBackgroundDrawable(stateList);
-            setPadding(padding[0], padding[1], padding[2], padding[3]);
-        }
-
-        @Override
-        public void onLightweightThemeReset() {
-            int[] padding =  new int[] { getPaddingLeft(),
-                                         getPaddingTop(),
-                                         getPaddingRight(),
-                                         getPaddingBottom()
-                                       };
-            setBackgroundResource(R.drawable.address_bar_bg);
-            setPadding(padding[0], padding[1], padding[2], padding[3]);
-        }
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/AwesomebarResultHandler.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.util.ActivityResultHandler;
-
-import android.content.Intent;
-import android.util.Log;
-
-class AwesomebarResultHandler implements ActivityResultHandler {
-    private static final String LOGTAG = "GeckoAwesomebarResultHandler";
-
-    @Override
-    public void onActivityResult(int resultCode, Intent data) {
-        if (data != null) {
-            String tab = data.getStringExtra(AwesomeBar.TAB_KEY);
-            if (tab != null) {
-                Tabs.getInstance().selectTab(Integer.parseInt(tab));
-                return;
-            }
-
-            String url = data.getStringExtra(AwesomeBar.URL_KEY);
-            AwesomeBar.Target target = AwesomeBar.Target.valueOf(data.getStringExtra(AwesomeBar.TARGET_KEY));
-            String searchEngine = data.getStringExtra(AwesomeBar.SEARCH_KEY);
-            if (url != null && url.length() > 0) {
-                int flags = Tabs.LOADURL_NONE;
-                if (target == AwesomeBar.Target.NEW_TAB) {
-                    flags |= Tabs.LOADURL_NEW_TAB;
-                }
-                if (data.getBooleanExtra(AwesomeBar.USER_ENTERED_KEY, false)) {
-                    flags |= Tabs.LOADURL_USER_ENTERED;
-                }
-                Tabs.getInstance().loadUrl(url, searchEngine, -1, flags);
-            }
-        }
-    }
-}
--- a/mobile/android/base/BackButton.java
+++ b/mobile/android/base/BackButton.java
@@ -68,17 +68,17 @@ public class BackButton extends ShapedBu
     @Override
     public void draw(Canvas canvas) {
         mCanvasDelegate.draw(canvas, mPath, getWidth(), getHeight());
 
         // Draw the border on top.
         canvas.drawPath(mBorderPath, isPrivateMode() ? mBorderPrivatePaint : mBorderPaint);
     }
 
-    // The drawable is constructed as per @drawable/address_bar_nav_button.
+    // The drawable is constructed as per @drawable/url_bar_nav_button.
     @Override
     public void onLightweightThemeChanged() {
         Drawable drawable = mActivity.getLightweightTheme().getDrawable(this);
         if (drawable == null)
             return;
 
         Resources resources = getContext().getResources();
         StateListDrawable stateList = new StateListDrawable();
@@ -90,11 +90,11 @@ public class BackButton extends ShapedBu
         stateList.addState(new int[] { R.attr.state_private }, new ColorDrawable(resources.getColor(R.color.background_private)));
         stateList.addState(new int[] {}, drawable);
 
         setBackgroundDrawable(stateList);
     }
 
     @Override
     public void onLightweightThemeReset() {
-        setBackgroundResource(R.drawable.address_bar_nav_button);
+        setBackgroundResource(R.drawable.url_bar_nav_button);
     }
 }
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -9,24 +9,26 @@ import org.mozilla.gecko.animation.Prope
 import org.mozilla.gecko.db.BrowserContract.Combined;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.GeckoLayerClient;
 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PanZoomController;
 import org.mozilla.gecko.health.BrowserHealthReporter;
+import org.mozilla.gecko.home.BrowserSearch;
+import org.mozilla.gecko.home.HomePager;
+import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.util.Clipboard;
 import org.mozilla.gecko.util.FloatUtils;
 import org.mozilla.gecko.util.GamepadUtils;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.util.UiAsyncTask;
-import org.mozilla.gecko.widget.AboutHome;
 import org.mozilla.gecko.widget.GeckoActionProvider;
 import org.mozilla.gecko.widget.ButtonToast;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.app.Activity;
@@ -44,16 +46,18 @@ import android.graphics.drawable.BitmapD
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.nfc.NdefMessage;
 import android.nfc.NdefRecord;
 import android.nfc.NfcAdapter;
 import android.nfc.NfcEvent;
 import android.os.Build;
 import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -65,25 +69,28 @@ import android.view.animation.Interpolat
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 import android.widget.Toast;
 
 import java.io.File;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.EnumSet;
+import java.util.List;
 import java.util.Vector;
 
 abstract public class BrowserApp extends GeckoApp
                                  implements TabsPanel.TabsLayoutChangeListener,
                                             PropertyAnimator.PropertyAnimationListener,
                                             View.OnKeyListener,
                                             GeckoLayerClient.OnMetricsChangedListener,
-                                            AboutHome.UriLoadListener,
-                                            AboutHome.LoadCompleteListener {
+                                            BrowserSearch.OnSearchListener,
+                                            BrowserSearch.OnEditSuggestionListener,
+                                            HomePager.OnNewTabsListener,
+                                            OnUrlOpenListener {
     private static final String LOGTAG = "GeckoBrowserApp";
 
     private static final String PREF_CHROME_DYNAMICTOOLBAR = "browser.chrome.dynamictoolbar";
 
     private static final String ABOUT_HOME = "about:home";
 
     private static final int TABS_ANIMATION_DURATION = 450;
 
@@ -91,18 +98,23 @@ abstract public class BrowserApp extends
     private static final int READER_ADD_FAILED = 1;
     private static final int READER_ADD_DUPLICATE = 2;
 
     private static final String ADD_SHORTCUT_TOAST = "add_shortcut_toast";
 
     private static final String STATE_ABOUT_HOME_TOP_PADDING = "abouthome_top_padding";
     private static final String STATE_DYNAMIC_TOOLBAR_ENABLED = "dynamic_toolbar";
 
+    private static final String BROWSER_SEARCH_TAG = "browser_search";
+    private BrowserSearch mBrowserSearch;
+    private View mBrowserSearchContainer;
+
     public static BrowserToolbar mBrowserToolbar;
-    private AboutHome mAboutHome;
+    private HomePager mHomePager;
+    private View mHomePagerContainer;
     protected Telemetry.Timer mAboutHomeStartupTimer = null;
 
     // Set the default session restore value
     private int mSessionRestore = -1;
 
     private static final int GECKO_TOOLS_MENU = -1;
     private static final int ADDON_MENU_OFFSET = 1000;
     private class MenuItemInfo {
@@ -147,20 +159,16 @@ abstract public class BrowserApp extends
     private int mToolbarHeight = 0;
 
     // Stored value of whether the last metrics change allowed for toolbar
     // scrolling.
     private boolean mDynamicToolbarCanScroll = false;
 
     private Integer mPrefObserverId;
 
-    // Tag for the AboutHome fragment. The fragment is automatically attached
-    // after restoring from a saved state, so we use this tag to identify it.
-    private static final String ABOUTHOME_TAG = "abouthome";
-
     private SharedPreferencesHelper mSharedPreferencesHelper;
 
     private OrderedBroadcastHelper mOrderedBroadcastHelper;
 
     private BrowserHealthReporter mBrowserHealthReporter;
 
     private SiteIdentityPopup mSiteIdentityPopup;
 
@@ -177,24 +185,24 @@ abstract public class BrowserApp extends
             case LOCATION_CHANGE:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     maybeCancelFaviconLoad(tab);
                 }
                 // fall through
             case SELECTED:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     if (isAboutHome(tab)) {
-                        showAboutHome();
+                        showHomePager(tab.getAboutHomePage());
 
                         if (isDynamicToolbarEnabled()) {
                             // Show the toolbar.
                             mLayerView.getLayerMarginsAnimator().showMargins(false);
                         }
                     } else {
-                        hideAboutHome();
+                        hideHomePager();
                     }
 
                     if (mSiteIdentityPopup != null)
                         mSiteIdentityPopup.dismiss();
 
                     final TabsPanel.Panel panel = tab.isPrivate()
                                                 ? TabsPanel.Panel.PRIVATE_TABS
                                                 : TabsPanel.Panel.NORMAL_TABS;
@@ -238,37 +246,31 @@ abstract public class BrowserApp extends
                     loadFavicon(tab);
                 }
                 break;
         }
         super.onTabChanged(tab, msg, data);
     }
 
     @Override
-    void handleClearHistory() {
-        super.handleClearHistory();
-        updateAboutHomeTopSites();
-    }
-
-    @Override
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         // Global onKey handler. This is called if the focused UI doesn't
         // handle the key event, and before Gecko swallows the events.
         if (event.getAction() != KeyEvent.ACTION_DOWN) {
             return false;
         }
 
         // Gamepad support only exists in API-level >= 9
         if (Build.VERSION.SDK_INT >= 9 &&
             (event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
             switch (keyCode) {
                 case KeyEvent.KEYCODE_BUTTON_Y:
                     // Toggle/focus the address bar on gamepad-y button.
                     if (mBrowserToolbar.isVisible()) {
-                        if (isDynamicToolbarEnabled() && !mAboutHome.getUserVisibleHint()) {
+                        if (isDynamicToolbarEnabled() && !mHomePager.isVisible()) {
                             if (mLayerView != null) {
                                 mLayerView.getLayerMarginsAnimator().hideMargins(false);
                                 mLayerView.requestFocus();
                             }
                         } else {
                             // Just focus the address bar when about:home is visible
                             // or when the dynamic toolbar isn't enabled.
                             mBrowserToolbar.requestFocusFromTouch();
@@ -325,17 +327,21 @@ abstract public class BrowserApp extends
             }
         }
 
         return false;
     }
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (onKey(null, keyCode, event)) {
+        if (!mBrowserToolbar.isEditing() && onKey(null, keyCode, event)) {
+            return true;
+        }
+
+        if (mBrowserToolbar.onKey(keyCode, event)) {
             return true;
         }
 
         return super.onKeyDown(keyCode, event);
     }
 
     void handleReaderListCountRequest() {
         ThreadUtils.postToBackgroundThread(new Runnable() {
@@ -379,29 +385,16 @@ abstract public class BrowserApp extends
 
                 final int count = BrowserDB.getReadingListCount(getContentResolver());
                 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:ListCountUpdated", Integer.toString(count)));
             }
         });
     }
 
     @Override
-    void onStatePurged() {
-        ThreadUtils.postToUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (mAboutHome != null)
-                    mAboutHome.setLastTabsVisibility(false);
-            }
-        });
-
-        super.onStatePurged();
-    }
-
-    @Override
     protected int getSessionRestoreState(Bundle savedInstanceState) {
         if (mSessionRestore > -1) {
             return mSessionRestore;
         }
 
         return super.getSessionRestoreState(savedInstanceState);
     }
 
@@ -422,38 +415,59 @@ abstract public class BrowserApp extends
 
         ((GeckoApp.MainLayout) mMainLayout).setTouchEventInterceptor(new HideTabsTouchListener());
         ((GeckoApp.MainLayout) mMainLayout).setMotionEventInterceptor(new MotionEventInterceptor() {
             @Override
             public boolean onInterceptMotionEvent(View view, MotionEvent event) {
                 // If we get a gamepad panning MotionEvent while the focus is not on the layerview,
                 // put the focus on the layerview and carry on
                 if (mLayerView != null && !mLayerView.hasFocus() && GamepadUtils.isPanningControl(event)) {
-                    if (mAboutHome.getUserVisibleHint()) {
-                        mAboutHome.requestFocus();
+                    if (mHomePager.isVisible()) {
+                        mLayerView.requestFocus();
                     } else {
-                        mLayerView.requestFocus();
+                        mHomePager.requestFocus();
                     }
                 }
                 return false;
             }
         });
 
-        // Find the Fragment if it was already added from a restored instance state.
-        mAboutHome = (AboutHome) getSupportFragmentManager().findFragmentByTag(ABOUTHOME_TAG);
+        mHomePager = (HomePager) findViewById(R.id.home_pager);
+        mHomePagerContainer = findViewById(R.id.home_pager_container);
+
+        mBrowserSearchContainer = findViewById(R.id.search_container);
+        mBrowserSearch = (BrowserSearch) getSupportFragmentManager().findFragmentByTag(BROWSER_SEARCH_TAG);
+        if (mBrowserSearch == null) {
+            mBrowserSearch = BrowserSearch.newInstance();
+            mBrowserSearch.setUserVisibleHint(false);
+        }
+
+        mBrowserToolbar.setOnActivateListener(new BrowserToolbar.OnActivateListener() {
+            public void onActivate() {
+                enterEditingMode();
+            }
+        });
 
-        if (mAboutHome == null) {
-            // AboutHome will be dynamically attached and detached as
-            // about:home is shown. Adding/removing the fragment is not synchronous,
-            // so we can't use Fragment#isVisible() to determine whether the
-            // about:home is shown. Instead, we use Fragment#getUserVisibleHint()
-            // with the hint we set ourselves.
-            mAboutHome = AboutHome.newInstance();
-            mAboutHome.setUserVisibleHint(false);
-        }
+        mBrowserToolbar.setOnCommitListener(new BrowserToolbar.OnCommitListener() {
+            public void onCommit() {
+                commitEditingMode();
+            }
+        });
+
+        mBrowserToolbar.setOnDismissListener(new BrowserToolbar.OnDismissListener() {
+            public void onDismiss() {
+                dismissEditingMode();
+            }
+        });
+
+        mBrowserToolbar.setOnFilterListener(new BrowserToolbar.OnFilterListener() {
+            public void onFilter(String searchText, AutocompleteHandler handler) {
+                filterEditingMode(searchText, handler);
+            }
+        });
 
         // Intercept key events for gamepad shortcuts
         mBrowserToolbar.setOnKeyListener(this);
 
         if (mTabsPanel != null) {
             mTabsPanel.setTabsLayoutChangeListener(this);
             updateSideBarState();
         }
@@ -463,16 +477,17 @@ abstract public class BrowserApp extends
         registerEventListener("CharEncoding:Data");
         registerEventListener("CharEncoding:State");
         registerEventListener("Feedback:LastUrl");
         registerEventListener("Feedback:OpenPlayStore");
         registerEventListener("Feedback:MaybeLater");
         registerEventListener("Telemetry:Gather");
         registerEventListener("Settings:Show");
         registerEventListener("Updater:Launch");
+        registerEventListener("Reader:GoToReadingList");
 
         Distribution.init(this, getPackageResourcePath());
         JavaAddonManager.getInstance().init(getApplicationContext());
         mSharedPreferencesHelper = new SharedPreferencesHelper(getApplicationContext());
         mOrderedBroadcastHelper = new OrderedBroadcastHelper(getApplicationContext());
         mBrowserHealthReporter = new BrowserHealthReporter();
 
         if (AppConstants.MOZ_ANDROID_BEAM && Build.VERSION.SDK_INT >= 14) {
@@ -488,17 +503,17 @@ abstract public class BrowserApp extends
                         return new NdefMessage(new NdefRecord[] { NdefRecord.createUri(tab.getURL()) });
                     }
                 }, this);
             }
         }
 
         if (savedInstanceState != null) {
             mDynamicToolbarEnabled = savedInstanceState.getBoolean(STATE_DYNAMIC_TOOLBAR_ENABLED);
-            mAboutHome.setTopPadding(savedInstanceState.getInt(STATE_ABOUT_HOME_TOP_PADDING));
+            mHomePagerContainer.setPadding(0, savedInstanceState.getInt(STATE_ABOUT_HOME_TOP_PADDING), 0, 0);
         }
 
         // Listen to the dynamic toolbar pref
         mPrefObserverId = PrefsHelper.getPref(PREF_CHROME_DYNAMICTOOLBAR, new PrefsHelper.PrefHandlerBase() {
             @Override
             public void prefValue(String pref, boolean value) {
                 if (value == mDynamicToolbarEnabled) {
                     return;
@@ -522,30 +537,47 @@ abstract public class BrowserApp extends
                 // We want to be notified of changes to be able to switch mode
                 // without restarting.
                 return true;
             }
         });
     }
 
     @Override
+    public void onBackPressed() {
+        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
+            super.onBackPressed();
+            return;
+        }
+
+        if (dismissEditingMode()) {
+            return;
+        }
+
+        if (mSiteIdentityPopup != null && mSiteIdentityPopup.isShowing()) {
+            mSiteIdentityPopup.dismiss();
+            return;
+        }
+
+        super.onBackPressed();
+    }
+
+    @Override
     public void onResume() {
         super.onResume();
         unregisterEventListener("Prompt:ShowTop");
     }
 
     @Override
     public void onPause() {
         super.onPause();
         // Register for Prompt:ShowTop so we can foreground this activity even if it's hidden.
         registerEventListener("Prompt:ShowTop");
     }
 
-
-
     private void showBookmarkDialog() {
         final Tab tab = Tabs.getInstance().getSelectedTab();
         final Prompt ps = new Prompt(this, new Prompt.PromptCallback() {
             @Override
             public void onPromptFinished(String result) {
                 int itemId = -1;
                 try {
                   itemId = new JSONObject(result).getInt("button");
@@ -578,24 +610,24 @@ abstract public class BrowserApp extends
     }
 
     private void setDynamicToolbarEnabled(boolean enabled) {
         if (enabled) {
             if (mLayerView != null) {
                 mLayerView.getLayerClient().setOnMetricsChangedListener(this);
             }
             setToolbarMargin(0);
-            mAboutHome.setTopPadding(mBrowserToolbar.getHeight());
+            mHomePagerContainer.setPadding(0, mBrowserToolbar.getHeight(), 0, 0);
         } else {
             // Immediately show the toolbar when disabling the dynamic
             // toolbar.
             if (mLayerView != null) {
                 mLayerView.getLayerClient().setOnMetricsChangedListener(null);
             }
-            mAboutHome.setTopPadding(0);
+            mHomePagerContainer.setPadding(0, 0, 0, 0);
             if (mBrowserToolbar != null) {
                 mBrowserToolbar.scrollTo(0, 0);
             }
         }
 
         refreshToolbarHeight();
     }
 
@@ -604,17 +636,18 @@ abstract public class BrowserApp extends
     }
 
     private boolean isAboutHome(Tab tab) {
         return TextUtils.equals(ABOUT_HOME, tab.getURL());
     }
 
     @Override
     public boolean onSearchRequested() {
-        return showAwesomebar(AwesomeBar.Target.CURRENT_TAB);
+        enterEditingMode();
+        return true;
     }
 
     @Override
     public boolean onContextItemSelected(MenuItem item) {
         final int itemId = item.getItemId();
         if (itemId == R.id.pasteandgo) {
             String text = Clipboard.getText();
             if (!TextUtils.isEmpty(text)) {
@@ -626,17 +659,17 @@ abstract public class BrowserApp extends
         if (itemId == R.id.site_settings) {
             GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Permissions:Get", null));
             return true;
         }
 
         if (itemId == R.id.paste) {
             String text = Clipboard.getText();
             if (!TextUtils.isEmpty(text)) {
-                showAwesomebar(AwesomeBar.Target.CURRENT_TAB, text);
+                enterEditingMode(text);
             }
             return true;
         }
 
         if (itemId == R.id.share) {
             shareCurrentUrl();
             return true;
         }
@@ -685,51 +718,16 @@ abstract public class BrowserApp extends
                 });
             }
             return true;
         }
 
         return false;
     }
 
-    public boolean showAwesomebar(AwesomeBar.Target aTarget) {
-        return showAwesomebar(aTarget, null);
-    }
-
-    public boolean showAwesomebar(AwesomeBar.Target aTarget, String aUrl) {
-        Intent intent = new Intent(getBaseContext(), AwesomeBar.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
-        intent.putExtra(AwesomeBar.TARGET_KEY, aTarget.name());
-
-        // If we were passed in a URL, show it.
-        if (aUrl != null && !TextUtils.isEmpty(aUrl)) {
-            intent.putExtra(AwesomeBar.CURRENT_URL_KEY, aUrl);
-        } else if (aTarget == AwesomeBar.Target.CURRENT_TAB) {
-            // Otherwise, if we're editing the current tab, show its URL.
-            Tab tab = Tabs.getInstance().getSelectedTab();
-            if (tab != null) {
-                // Check to see if there's a user-entered search term, which we save
-                // whenever the user performs a search.
-                aUrl = tab.getUserSearch();
-                if (TextUtils.isEmpty(aUrl)) {
-                    aUrl = tab.getURL();
-                }
-                if (aUrl != null) {
-                    intent.putExtra(AwesomeBar.CURRENT_URL_KEY, aUrl);
-                }
-            }
-        }
-
-        int requestCode = GeckoAppShell.sActivityHelper.makeRequestCodeForAwesomebar();
-        startActivityForResult(intent, requestCode);
-        overridePendingTransition (R.anim.awesomebar_fade_in, R.anim.awesomebar_hold_still);
-        return true;
-    }
-
-
     @Override
     public void setAccessibilityEnabled(boolean enabled) {
         if (mAccessibilityEnabled == enabled) {
             return;
         }
 
         // Disable the dynamic toolbar when accessibility features are enabled,
         // and re-read the preference when they're disabled.
@@ -771,16 +769,17 @@ abstract public class BrowserApp extends
         unregisterEventListener("CharEncoding:Data");
         unregisterEventListener("CharEncoding:State");
         unregisterEventListener("Feedback:LastUrl");
         unregisterEventListener("Feedback:OpenPlayStore");
         unregisterEventListener("Feedback:MaybeLater");
         unregisterEventListener("Telemetry:Gather");
         unregisterEventListener("Settings:Show");
         unregisterEventListener("Updater:Launch");
+        unregisterEventListener("Reader:GoToReadingList");
 
         if (AppConstants.MOZ_ANDROID_BEAM && Build.VERSION.SDK_INT >= 14) {
             NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
             if (nfc != null) {
                 // null this out even though the docs say it's not needed,
                 // because the source code looks like it will only do this
                 // automatically on API 14+
                 nfc.setNdefPushMessageCallback(null, this);
@@ -838,17 +837,17 @@ abstract public class BrowserApp extends
 
     private void setToolbarMargin(int margin) {
         ((RelativeLayout.LayoutParams) mGeckoLayout.getLayoutParams()).topMargin = margin;
         mGeckoLayout.requestLayout();
     }
 
     @Override
     public void onMetricsChanged(ImmutableViewportMetrics aMetrics) {
-        if (mAboutHome.getUserVisibleHint() || mBrowserToolbar == null) {
+        if (mHomePager.isVisible() || mBrowserToolbar == null) {
             return;
         }
 
         // If the page has shrunk so that the toolbar no longer scrolls, make
         // sure the toolbar is visible.
         if (aMetrics.getPageHeight() <= aMetrics.getHeight()) {
             if (mDynamicToolbarCanScroll) {
                 mDynamicToolbarCanScroll = false;
@@ -873,17 +872,17 @@ abstract public class BrowserApp extends
         });
 
         if (mFormAssistPopup != null)
             mFormAssistPopup.onMetricsChanged(aMetrics);
     }
 
     @Override
     public void onPanZoomStopped() {
-        if (!isDynamicToolbarEnabled() || mAboutHome.getUserVisibleHint()) {
+        if (!isDynamicToolbarEnabled() || mHomePager.isVisible()) {
             return;
         }
 
         // Make sure the toolbar is fully hidden or fully shown when the user
         // lifts their finger. If the page is shorter than the viewport, the
         // toolbar is always shown.
         ImmutableViewportMetrics metrics = mLayerView.getViewportMetrics();
         if (metrics.getPageHeight() < metrics.getHeight()
@@ -895,22 +894,29 @@ abstract public class BrowserApp extends
     }
 
     public void refreshToolbarHeight() {
         int height = 0;
         if (mBrowserToolbar != null) {
             height = mBrowserToolbar.getHeight();
         }
 
-        if (!isDynamicToolbarEnabled()) {
+        if (!isDynamicToolbarEnabled() || mHomePager.isVisible()) {
             // Use aVisibleHeight here so that when the dynamic toolbar is
             // enabled, the padding will animate with the toolbar becoming
             // visible.
-            setToolbarMargin(height);
-            height = 0;
+            if (isDynamicToolbarEnabled()) {
+                // When the dynamic toolbar is enabled, set the padding on the
+                // about:home widget directly - this is to avoid resizing the
+                // LayerView, which can cause visible artifacts.
+                mHomePagerContainer.setPadding(0, height, 0, 0);
+            } else {
+                setToolbarMargin(height);
+                height = 0;
+            }
         } else {
             setToolbarMargin(0);
         }
 
         if (mLayerView != null && height != mToolbarHeight) {
             mToolbarHeight = height;
             mLayerView.getLayerMarginsAnimator().setMaxMargins(0, height, 0, 0);
             mLayerView.getLayerMarginsAnimator().showMargins(true);
@@ -952,47 +958,21 @@ abstract public class BrowserApp extends
         invalidateOptionsMenu();
         updateSideBarState();
         mTabsPanel.refresh();
         if (mSiteIdentityPopup != null) {
             mSiteIdentityPopup.dismiss();
         }
     }
 
-    @Override
-    public void onBackPressed() {
-        if (mSiteIdentityPopup != null && mSiteIdentityPopup.isShowing()) {
-            mSiteIdentityPopup.dismiss();
-            return;
-        }
-
-        super.onBackPressed();
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        String url = null;
-
-        // Don't update the url in the toolbar if the activity was cancelled.
-        if (resultCode == Activity.RESULT_OK && data != null) {
-            // Don't update the url if the activity was launched to pick a site.
-            String targetKey = data.getStringExtra(AwesomeBar.TARGET_KEY);
-            if (!AwesomeBar.Target.PICK_SITE.toString().equals(targetKey)) {
-                // Update the toolbar with the url that was just entered.
-                url = data.getStringExtra(AwesomeBar.URL_KEY);
-            }
-        }
-
-        // We always need to call fromAwesomeBarSearch to perform the toolbar animation.
-        mBrowserToolbar.fromAwesomeBarSearch(url);
-
-        // Trigger any tab-related events after we start restoring
-        // the toolbar state above to make ensure animations happen
-        // on the correct order.
-        super.onActivityResult(requestCode, resultCode, data);
+    public View getActionBarLayout() {
+        RelativeLayout actionBar = (RelativeLayout) LayoutInflater.from(this).inflate(R.layout.browser_toolbar, null);
+        actionBar.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
+                                                                  (int) getResources().getDimension(R.dimen.browser_toolbar_height)));
+        return actionBar;
     }
 
     @Override
     public boolean hasTabsSideBar() {
         return (mTabsPanel != null && mTabsPanel.isSideBar());
     }
 
     private void updateSideBarState() {
@@ -1150,33 +1130,35 @@ abstract public class BrowserApp extends
                 if (!message.isNull(GeckoPreferences.INTENT_EXTRA_RESOURCES)) {
                     resource = message.getString(GeckoPreferences.INTENT_EXTRA_RESOURCES);
                 }
                 Intent settingsIntent = new Intent(this, GeckoPreferences.class);
                 GeckoPreferences.setResourceToOpen(settingsIntent, resource);
                 startActivity(settingsIntent);
             } else if (event.equals("Updater:Launch")) {
                 handleUpdaterLaunch();
+            } else if (event.equals("Reader:GoToReadingList")) {
+                openReadingList();
             } else if (event.equals("Prompt:ShowTop")) {
                 // Bring this activity to front so the prompt is visible..
                 Intent bringToFrontIntent = new Intent();
                 bringToFrontIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.BROWSER_INTENT_CLASS);
                 bringToFrontIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                 startActivity(bringToFrontIntent);
             } else {
                 super.handleMessage(event, message);
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
     @Override
     public void addTab() {
-        showAwesomebar(AwesomeBar.Target.NEW_TAB);
+        Tabs.getInstance().loadUrl("about:home", Tabs.LOADURL_NEW_TAB);
     }
 
     @Override
     public void addPrivateTab() {
         Tabs.getInstance().loadUrl("about:privatebrowsing", Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_PRIVATE);
     }
 
     @Override
@@ -1229,17 +1211,17 @@ abstract public class BrowserApp extends
             mMainLayoutAnimator.stop(false);
         }
 
         if (areTabsShown()) {
             mTabsPanel.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
         }
 
         mMainLayoutAnimator = new PropertyAnimator(animationLength, sTabsInterpolator);
-        mMainLayoutAnimator.setPropertyAnimationListener(this);
+        mMainLayoutAnimator.addPropertyAnimationListener(this);
 
         if (hasTabsSideBar()) {
             mMainLayoutAnimator.attach(mMainLayout,
                                        PropertyAnimator.Property.SCROLL_X,
                                        -width);
         } else {
             mMainLayoutAnimator.attach(mMainLayout,
                                        PropertyAnimator.Property.SCROLL_Y,
@@ -1279,17 +1261,76 @@ abstract public class BrowserApp extends
         mMainLayoutAnimator = null;
     }
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
         mToast.onSaveInstanceState(outState);
         outState.putBoolean(STATE_DYNAMIC_TOOLBAR_ENABLED, mDynamicToolbarEnabled);
-        outState.putInt(STATE_ABOUT_HOME_TOP_PADDING, mAboutHome.getTopPadding());
+        outState.putInt(STATE_ABOUT_HOME_TOP_PADDING, mHomePagerContainer.getPaddingTop());
+    }
+
+    /**
+     * Attempts to switch to an open tab with the given URL.
+     *
+     * @return true if we successfully switched to a tab, false otherwise.
+     */
+    private boolean maybeSwitchToTab(String url, EnumSet<OnUrlOpenListener.Flags> flags) {
+        if (!flags.contains(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB)) {
+            return false;
+        }
+
+        final Tabs tabs = Tabs.getInstance();
+        final int tabId = tabs.getTabIdForUrl(url);
+        if (tabId < 0) {
+            return false;
+        }
+
+        // If this tab is already selected, just hide the home pager.
+        if (tabs.isSelectedTab(tabs.getTab(tabId))) {
+            hideHomePager();
+        } else {
+            tabs.selectTab(tabId);
+        }
+
+        hideBrowserSearch();
+        mBrowserToolbar.cancelEdit();
+
+        return true;
+    }
+
+    private void openUrl(String url) {
+        openUrl(url, null, false);
+    }
+
+    private void openUrl(String url, boolean newTab) {
+        openUrl(url, null, newTab);
+    }
+
+    private void openUrl(String url, String searchEngine) {
+        openUrl(url, searchEngine, false);
+    }
+
+    private void openUrl(String url, String searchEngine, boolean newTab) {
+        mBrowserToolbar.setProgressVisibility(true);
+
+        int flags = Tabs.LOADURL_NONE;
+        if (newTab) {
+            flags |= Tabs.LOADURL_NEW_TAB;
+        }
+
+        Tabs.getInstance().loadUrl(url, searchEngine, -1, flags);
+
+        hideBrowserSearch();
+        mBrowserToolbar.cancelEdit();
+    }
+
+    private void openReadingList() {
+        Tabs.getInstance().loadUrl(ABOUT_HOME, Tabs.LOADURL_READING_LIST);
     }
 
     /* Favicon methods */
     private void loadFavicon(final Tab tab) {
         maybeCancelFaviconLoad(tab);
 
         int flags = Favicons.FLAG_SCALE | ( (tab.isPrivate() || tab.getErrorType() != Tab.ErrorType.NONE) ? 0 : Favicons.FLAG_PERSIST);
         long id = Favicons.getInstance().loadFavicon(tab.getURL(), tab.getFaviconURL(), flags,
@@ -1325,67 +1366,157 @@ abstract public class BrowserApp extends
 
         // Cancel pending favicon load task
         Favicons.getInstance().cancelFaviconLoad(faviconLoadId);
 
         // Reset favicon load state
         tab.setFaviconLoadId(Favicons.NOT_LOADING);
     }
 
+    private void enterEditingMode() {
+        String url = null;
 
-    /* About:home UI */
-    void updateAboutHomeTopSites() {
-        mAboutHome.update(EnumSet.of(AboutHome.UpdateFlags.TOP_SITES));
+        final Tab tab = Tabs.getInstance().getSelectedTab();
+        if (tab != null) {
+            final String userSearch = tab.getUserSearch();
+
+            // Check to see if there's a user-entered search term,
+            // which we save whenever the user performs a search.
+            url = (TextUtils.isEmpty(userSearch) ? tab.getURL() : userSearch);
+        }
+
+        enterEditingMode(url);
+    }
+
+    /**
+     * Enters editing mode for the current tab. This method will
+     * always open the VISITED page on about:home.
+     */
+    private void enterEditingMode(String url) {
+        if (url == null) {
+            throw new IllegalArgumentException("Cannot handle null URLs in enterEditingMode");
+        }
+
+        final PropertyAnimator animator = new PropertyAnimator(250);
+        animator.setUseHardwareLayer(false);
+
+        mBrowserToolbar.startEditing(url, animator);
+        showHomePagerWithAnimator(HomePager.Page.HISTORY, animator);
+
+        animator.start();
     }
 
-    private void showAboutHome() {
-        if (mAboutHome.getUserVisibleHint()) {
+    void commitEditingMode() {
+        if (!mBrowserToolbar.isEditing()) {
+            return;
+        }
+
+        final String url = mBrowserToolbar.commitEdit();
+        animateHideHomePager();
+        hideBrowserSearch();
+
+        if (!TextUtils.isEmpty(url)) {
+            Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
+        }
+    }
+
+    boolean dismissEditingMode() {
+        if (!mBrowserToolbar.isEditing()) {
+            return false;
+        }
+
+        mBrowserToolbar.cancelEdit();
+        animateHideHomePager();
+        hideBrowserSearch();
+
+        return true;
+    }
+
+    void filterEditingMode(String searchTerm, AutocompleteHandler handler) {
+        if (TextUtils.isEmpty(searchTerm)) {
+            hideBrowserSearch();
+        } else {
+            showBrowserSearch();
+            mBrowserSearch.filter(searchTerm, handler);
+        }
+    }
+
+    private void showHomePager(HomePager.Page page) {
+        showHomePagerWithAnimator(page, null);
+    }
+
+    private void showHomePagerWithAnimator(HomePager.Page page, PropertyAnimator animator) {
+        if (mHomePager.isVisible()) {
             return;
         }
 
         // Refresh toolbar height to possibly restore the toolbar padding
         refreshToolbarHeight();
 
         // Show the toolbar before hiding about:home so the
         // onMetricsChanged callback still works.
         if (isDynamicToolbarEnabled() && mLayerView != null) {
             mLayerView.getLayerMarginsAnimator().showMargins(true);
         }
 
-        // We use commitAllowingStateLoss() instead of commit() here to avoid an
-        // IllegalStateException. showAboutHome() and hideAboutHome() are
-        // executed inside of tab's onChange() callback. Since that callback can
-        // be triggered asynchronously from Gecko, it's possible that this
-        // method can be called while Fennec is in the background. If that
-        // happens, using commit() would throw an IllegalStateException since
-        // it can't be used between the Activity's onSaveInstanceState() and
-        // onResume().
-        getSupportFragmentManager().beginTransaction()
-                .add(R.id.gecko_layout, mAboutHome, ABOUTHOME_TAG).commitAllowingStateLoss();
-        mAboutHome.setUserVisibleHint(true);
+        mHomePager.show(getSupportFragmentManager(), page, animator);
+    }
 
-        mBrowserToolbar.setNextFocusDownId(R.id.abouthome_content);
+    private void animateHideHomePager() {
+        hideHomePagerWithAnimation(true);
     }
 
-    private void hideAboutHome() {
-        if (!mAboutHome.getUserVisibleHint()) {
+    private void hideHomePager() {
+        hideHomePagerWithAnimation(false);
+    }
+
+    private void hideHomePagerWithAnimation(boolean animate) {
+        if (!mHomePager.isVisible()) {
             return;
         }
 
-        getSupportFragmentManager().beginTransaction()
-                .remove(mAboutHome).commitAllowingStateLoss();
-        mAboutHome.setUserVisibleHint(false);
+        final Tab tab = Tabs.getInstance().getSelectedTab();
+        if (tab != null && isAboutHome(tab)) {
+            return;
+        }
+
+        // FIXME: do animation if animate is true
+        mHomePager.hide();
 
         mBrowserToolbar.setShadowVisibility(true);
         mBrowserToolbar.setNextFocusDownId(R.id.layer_view);
 
         // Refresh toolbar height to possibly restore the toolbar padding
         refreshToolbarHeight();
     }
 
+    private void showBrowserSearch() {
+        if (mBrowserSearch.getUserVisibleHint()) {
+            return;
+        }
+
+        mBrowserSearchContainer.setVisibility(View.VISIBLE);
+
+        getSupportFragmentManager().beginTransaction()
+                .add(R.id.search_container, mBrowserSearch, BROWSER_SEARCH_TAG).commitAllowingStateLoss();
+        mBrowserSearch.setUserVisibleHint(true);
+    }
+
+    private void hideBrowserSearch() {
+        if (!mBrowserSearch.getUserVisibleHint()) {
+            return;
+        }
+
+        mBrowserSearchContainer.setVisibility(View.INVISIBLE);
+
+        getSupportFragmentManager().beginTransaction()
+                .remove(mBrowserSearch).commitAllowingStateLoss();
+        mBrowserSearch.setUserVisibleHint(false);
+    }
+
     private class HideTabsTouchListener implements TouchEventInterceptor {
         private boolean mIsHidingTabs = false;
 
         @Override
         public boolean onInterceptTouchEvent(View view, MotionEvent event) {
             // We need to account for scroll state for the touched view otherwise
             // tapping on an "empty" part of the view will still be considered a
             // valid touch event.
@@ -1989,25 +2120,42 @@ abstract public class BrowserApp extends
             public void onPostExecute(String url) {
                 // Don't bother sending a message if there is no URL.
                 if (url.length() > 0)
                     GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Feedback:LastUrl", url));
             }
         }).execute();
     }
 
+    // HomePager.OnNewTabsListener
     @Override
-    public void onAboutHomeUriLoad(String url) {
-        mBrowserToolbar.setProgressVisibility(true);
-        Tabs.getInstance().loadUrl(url);
+    public void onNewTabs(String[] urls) {
+        for (String url : urls) {
+            openUrl(url, true);
+        }
     }
 
+    // HomePager.OnUrlOpenListener
     @Override
-    public void onAboutHomeLoadComplete() {
-        mAboutHomeStartupTimer.stop();
+    public void onUrlOpen(String url, EnumSet<OnUrlOpenListener.Flags> flags) {
+        if (!maybeSwitchToTab(url, flags)) {
+            openUrl(url);
+        }
+    }
+
+    // BrowserSearch.OnSearchListener
+    @Override
+    public void onSearch(String engineId, String text) {
+        openUrl(text, engineId);
+    }
+
+    // BrowserSearch.OnEditSuggestionListener
+    @Override
+    public void onEditSuggestion(String suggestion) {
+        mBrowserToolbar.onEditSuggestion(suggestion);
     }
 
     @Override
     public int getLayout() { return R.layout.gecko_app; }
 
     @Override
     protected String getDefaultProfileName() {
         String profile = GeckoProfile.findDefaultProfile(this);
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.animation.PropertyAnimator;
 import org.mozilla.gecko.animation.ViewHelper;
 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
 import org.mozilla.gecko.gfx.LayerView;
+import org.mozilla.gecko.util.GamepadUtils;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.MenuPopup;
 import org.mozilla.gecko.PageActionLayout;
 import org.mozilla.gecko.PrefsHelper;
 import org.mozilla.gecko.util.Clipboard;
 import org.mozilla.gecko.util.StringUtils;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.ThreadUtils;
@@ -29,95 +30,135 @@ import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
 import android.os.Build;
 import android.os.SystemClock;
 import android.text.style.ForegroundColorSpan;
+import android.text.Editable;
+import android.text.InputType;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
+import android.text.Spanned;
 import android.text.TextUtils;
+import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.ContextMenu;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MenuInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.view.Window;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Interpolator;
 import android.view.animation.TranslateAnimation;
+import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
+import android.widget.EditText;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.PopupWindow;
 import android.widget.RelativeLayout;
 import android.widget.RelativeLayout.LayoutParams;
 import android.widget.ViewSwitcher;
 
 import java.util.Arrays;
 import java.util.List;
 
 public class BrowserToolbar extends GeckoRelativeLayout
-                            implements Tabs.OnTabsChangedListener,
+                            implements TextWatcher,
+                                       AutocompleteHandler,
+                                       Tabs.OnTabsChangedListener,
                                        GeckoMenu.ActionItemBarPresenter,
                                        Animation.AnimationListener,
                                        GeckoEventListener {
     private static final String LOGTAG = "GeckoToolbar";
     public static final String PREF_TITLEBAR_MODE = "browser.chrome.titlebarMode";
+
+    public interface OnActivateListener {
+        public void onActivate();
+    }
+
+    public interface OnCommitListener {
+        public void onCommit();
+    }
+
+    public interface OnDismissListener {
+        public void onDismiss();
+    }
+
+    public interface OnFilterListener {
+        public void onFilter(String searchText, AutocompleteHandler handler);
+    }
+
     private LayoutParams mAwesomeBarParams;
     private View mUrlDisplayContainer;
-    private View mAwesomeBarEntry;
-    private ImageView mAwesomeBarRightEdge;
-    private BrowserToolbarBackground mAddressBarBg;
+    private View mUrlEditContainer;
+    private CustomEditText mUrlEditText;
+    private View mUrlBarEntry;
+    private ImageView mUrlBarRightEdge;
+    private BrowserToolbarBackground mUrlBarBackground;
     private GeckoTextView mTitle;
     private int mTitlePadding;
     private boolean mSiteSecurityVisible;
     private boolean mSwitchingTabs;
     private ShapedButton mTabs;
     private ImageButton mBack;
     private ImageButton mForward;
     public ImageButton mFavicon;
     public ImageButton mStop;
     public ImageButton mSiteSecurity;
+    public ImageButton mGo;
     public PageActionLayout mPageActionLayout;
     private Animation mProgressSpinner;
     private TabCounter mTabsCounter;
     private ImageView mShadow;
     private GeckoImageButton mMenu;
     private GeckoImageView mMenuIcon;
     private LinearLayout mActionItemBar;
     private MenuPopup mMenuPopup;
     private List<? extends View> mFocusOrder;
+    private OnActivateListener mActivateListener;
+    private OnCommitListener mCommitListener;
+    private OnDismissListener mDismissListener;
+    private OnFilterListener mFilterListener;
 
     final private BrowserApp mActivity;
     private boolean mHasSoftMenuButton;
 
     private boolean mShowSiteSecurity;
     private boolean mShowReader;
     private boolean mSpinnerVisible;
 
+    private boolean mDelayRestartInput;
+    // The previous autocomplete result returned to us
+    private String mAutoCompleteResult = "";
+    // The user typed part of the autocomplete result
+    private String mAutoCompletePrefix = null;
+
+    private boolean mIsEditing;
     private boolean mAnimatingEntry;
 
     private AlphaAnimation mLockFadeIn;
     private TranslateAnimation mTitleSlideLeft;
     private TranslateAnimation mTitleSlideRight;
 
-    private int mAddressBarViewOffset;
+    private int mUrlBarViewOffset;
     private int mDefaultForwardMargin;
     private PropertyAnimator mForwardAnim = null;
 
     private int mFaviconSize;
 
     private PropertyAnimator mVisibilityAnimator;
     private static final Interpolator sButtonsInterpolator = new AccelerateInterpolator();
 
@@ -145,16 +186,17 @@ public class BrowserToolbar extends Geck
         mActivity = (BrowserApp) context;
 
         // Inflate the content.
         LayoutInflater.from(context).inflate(R.layout.browser_toolbar, this);
 
         Tabs.registerOnTabsChangedListener(this);
         mSwitchingTabs = true;
 
+        mIsEditing = false;
         mAnimatingEntry = false;
         mShowUrl = false;
 
         // listen to the title bar pref.
         mPrefObserverId = PrefsHelper.getPref(PREF_TITLEBAR_MODE, new PrefsHelper.PrefHandlerBase() {
             @Override
             public void prefValue(String pref, String str) {
                 int value = Integer.parseInt(str);
@@ -190,29 +232,32 @@ public class BrowserToolbar extends Geck
         registerEventListener("Reader:Click");
         registerEventListener("Reader:LongClick");
 
         mShowSiteSecurity = false;
         mShowReader = false;
 
         mAnimatingEntry = false;
 
-        mAddressBarBg = (BrowserToolbarBackground) findViewById(R.id.address_bar_bg);
-        mAddressBarViewOffset = res.getDimensionPixelSize(R.dimen.addressbar_offset_left);
+        mUrlBarBackground = (BrowserToolbarBackground) findViewById(R.id.url_bar_bg);
+        mUrlBarViewOffset = res.getDimensionPixelSize(R.dimen.url_bar_offset_left);
         mDefaultForwardMargin = res.getDimensionPixelSize(R.dimen.forward_default_offset);
-        mUrlDisplayContainer = findViewById(R.id.awesome_bar_display_container);
-        mAwesomeBarEntry = findViewById(R.id.awesome_bar_entry);
+        mUrlDisplayContainer = findViewById(R.id.url_display_container);
+        mUrlBarEntry = findViewById(R.id.url_bar_entry);
+
+        mUrlEditContainer = findViewById(R.id.url_edit_container);
+        mUrlEditText = (CustomEditText) findViewById(R.id.url_edit_text);
 
         // This will clip the right edge's image at half of its width
-        mAwesomeBarRightEdge = (ImageView) findViewById(R.id.awesome_bar_right_edge);
-        if (mAwesomeBarRightEdge != null) {
-            mAwesomeBarRightEdge.getDrawable().setLevel(5000);
+        mUrlBarRightEdge = (ImageView) findViewById(R.id.url_bar_right_edge);
+        if (mUrlBarRightEdge != null) {
+            mUrlBarRightEdge.getDrawable().setLevel(5000);
         }
 
-        mTitle = (GeckoTextView) findViewById(R.id.awesome_bar_title);
+        mTitle = (GeckoTextView) findViewById(R.id.url_bar_title);
         mTitlePadding = mTitle.getPaddingRight();
 
         mTabs = (ShapedButton) findViewById(R.id.tabs);
         mTabsCounter = (TabCounter) findViewById(R.id.tabs_counter);
         mBack = (ImageButton) findViewById(R.id.back);
         mForward = (ImageButton) findViewById(R.id.forward);
         mForward.setEnabled(false); // initialize the forward button to not be enabled
 
@@ -253,24 +298,30 @@ public class BrowserToolbar extends Geck
 
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         setOnClickListener(new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
-                mActivity.autoHideTabs();
-                onAwesomeBarSearch();
+                if (mActivateListener != null) {
+                    mActivateListener.onActivate();
+                }
             }
         });
 
         setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
             @Override
             public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+                // We don't the context menu while editing
+                if (isEditing()) {
+                    return;
+                }
+
                 MenuInflater inflater = mActivity.getMenuInflater();
                 inflater.inflate(R.menu.titlebar_contextmenu, menu);
 
                 String clipboard = Clipboard.getText();
                 if (TextUtils.isEmpty(clipboard)) {
                     menu.findItem(R.id.pasteandgo).setVisible(false);
                     menu.findItem(R.id.paste).setVisible(false);
                 }
@@ -291,16 +342,106 @@ public class BrowserToolbar extends Geck
                     menu.findItem(R.id.copyurl).setVisible(false);
                     menu.findItem(R.id.share).setVisible(false);
                     menu.findItem(R.id.add_to_launcher).setVisible(false);
                     menu.findItem(R.id.subscribe).setVisible(false);
                 }
             }
         });
 
+        mUrlEditText.addTextChangedListener(this);
+
+        mUrlEditText.setOnKeyPreImeListener(new CustomEditText.OnKeyPreImeListener() {
+            @Override
+            public boolean onKeyPreIme(View v, int keyCode, KeyEvent event) {
+                // We only want to process one event per tap
+                if (event.getAction() != KeyEvent.ACTION_DOWN)
+                    return false;
+
+                if (keyCode == KeyEvent.KEYCODE_ENTER) {
+                    // If the edit text has a composition string, don't submit the text yet.
+                    // ENTER is needed to commit the composition string.
+                    Editable content = mUrlEditText.getText();
+                    if (!hasCompositionString(content)) {
+                        if (mCommitListener != null) {
+                            mCommitListener.onCommit();
+                        }
+                        return true;
+                    }
+                }
+
+                if (keyCode == KeyEvent.KEYCODE_BACK) {
+                    clearFocus();
+                    return true;
+                }
+
+                return false;
+            }
+        });
+
+        mUrlEditText.setOnKeyListener(new View.OnKeyListener() {
+            @Override
+            public boolean onKey(View v, int keyCode, KeyEvent event) {
+                if (keyCode == KeyEvent.KEYCODE_ENTER || GamepadUtils.isActionKey(event)) {
+                    if (event.getAction() != KeyEvent.ACTION_DOWN)
+                        return true;
+
+                    if (mCommitListener != null) {
+                        mCommitListener.onCommit();
+                    }
+                    return true;
+                } else if (GamepadUtils.isBackKey(event)) {
+                    if (mDismissListener != null) {
+                        mDismissListener.onDismiss();
+                    }
+                    return true;
+                }
+
+                return false;
+            }
+        });
+
+        mUrlEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (v == null) {
+                    return;
+                }
+
+                setSelected(hasFocus);
+                if (hasFocus) {
+                    return;
+                }
+
+                InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+                try {
+                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
+                } catch (NullPointerException e) {
+                    Log.e(LOGTAG, "InputMethodManagerService, why are you throwing"
+                                  + " a NullPointerException? See bug 782096", e);
+                }
+            }
+        });
+
+        mUrlEditText.setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                if (Build.VERSION.SDK_INT >= 11) {
+                    CustomEditText text = (CustomEditText) v;
+
+                    if (text.getSelectionStart() == text.getSelectionEnd())
+                        return false;
+
+                    return false;
+                }
+
+                return false;
+            }
+        });
+
         mTabs.setOnClickListener(new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
                 toggleTabs();
             }
         });
         mTabs.setImageLevel(0);
 
@@ -355,16 +496,27 @@ public class BrowserToolbar extends Geck
             public void onClick(View v) {
                 Tab tab = Tabs.getInstance().getSelectedTab();
                 if (tab != null)
                     tab.doStop();
                 setProgressVisibility(false);
             }
         });
 
+        mGo = (ImageButton) findViewById(R.id.go);
+        mGo.setOnClickListener(new Button.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mCommitListener != null) {
+                    mCommitListener.onCommit();
+                }
+            }
+        });
+
+        mShadow = (ImageView) findViewById(R.id.shadow);
         mShadow.setOnClickListener(new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
             }
         });
 
         float slideWidth = getResources().getDimension(R.dimen.browser_toolbar_lock_width);
 
@@ -411,16 +563,64 @@ public class BrowserToolbar extends Geck
                     Rect bounds = new Rect(0, 0, tail, height);
                     TailTouchDelegate delegate = new TailTouchDelegate(bounds, mShadow);
                     mTabs.setTouchDelegate(delegate);
                 }
             });
         }
     }
 
+    public boolean onKey(int keyCode, KeyEvent event) {
+        if (event.getAction() != KeyEvent.ACTION_DOWN) {
+            return false;
+        }
+
+        // Galaxy Note sends key events for the stylus that are outside of the
+        // valid keyCode range (see bug 758427)
+        if (keyCode > KeyEvent.getMaxKeyCode()) {
+            return true;
+        }
+
+        // This method is called only if the key event was not handled
+        // by any of the views, which usually means the edit box lost focus
+        if (keyCode == KeyEvent.KEYCODE_BACK ||
+            keyCode == KeyEvent.KEYCODE_MENU ||
+            keyCode == KeyEvent.KEYCODE_DPAD_UP ||
+            keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
+            keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
+            keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
+            keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
+            keyCode == KeyEvent.KEYCODE_DEL ||
+            keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
+            keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+            return false;
+        } else if (isEditing()) {
+            final int prevSelStart = mUrlEditText.getSelectionStart();
+            final int prevSelEnd = mUrlEditText.getSelectionEnd();
+
+            // Manually dispatch the key event to the edit text. If selection changed as
+            // a result of the key event, then give focus back to mUrlEditText
+            mUrlEditText.dispatchKeyEvent(event);
+
+            final int curSelStart = mUrlEditText.getSelectionStart();
+            final int curSelEnd = mUrlEditText.getSelectionEnd();
+
+            if (prevSelStart != curSelStart || prevSelEnd != curSelEnd) {
+                mUrlEditText.requestFocusFromTouch();
+
+                // Restore the selection, which gets lost due to the focus switch
+                mUrlEditText.setSelection(curSelStart, curSelEnd);
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         // If the motion event has occured below the toolbar (due to the scroll
         // offset), let it pass through to the page.
         if (event != null && event.getY() > getHeight() - getScrollY()) {
             return false;
         }
 
@@ -510,16 +710,88 @@ public class BrowserToolbar extends Geck
             case READER_ENABLED:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
                 }
                 break;
         }
     }
 
+    // Return early if we're backspacing through the string, or
+    // have no autocomplete results
+    @Override
+    public void onAutocomplete(final String result) {
+        final String text = mUrlEditText.getText().toString();
+
+        if (result == null) {
+            mAutoCompleteResult = "";
+            return;
+        }
+
+        if (!result.startsWith(text) || text.equals(result)) {
+            return;
+        }
+
+        mAutoCompleteResult = result;
+        mUrlEditText.getText().append(result.substring(text.length()));
+        mUrlEditText.setSelection(text.length(), result.length());
+    }
+
+    @Override
+    public void afterTextChanged(final Editable s) {
+        final String text = s.toString();
+        boolean useHandler = false;
+        boolean reuseAutocomplete = false;
+        if (!hasCompositionString(s) && !StringUtils.isSearchQuery(text, false)) {
+            useHandler = true;
+
+            // If you're hitting backspace (the string is getting smaller
+            // or is unchanged), don't autocomplete.
+            if (mAutoCompletePrefix != null && (mAutoCompletePrefix.length() >= text.length())) {
+                useHandler = false;
+            } else if (mAutoCompleteResult != null && mAutoCompleteResult.startsWith(text)) {
+                // If this text already matches our autocomplete text, autocomplete likely
+                // won't change. Just reuse the old autocomplete value.
+                useHandler = false;
+                reuseAutocomplete = true;
+            }
+        }
+
+        // If this is the autocomplete text being set, don't run the filter.
+        if (TextUtils.isEmpty(mAutoCompleteResult) || !mAutoCompleteResult.equals(text)) {
+            if (isEditing() && mFilterListener != null) {
+                mFilterListener.onFilter(text, useHandler ? this : null);
+            }
+            mAutoCompletePrefix = text;
+
+            if (reuseAutocomplete) {
+                onAutocomplete(mAutoCompleteResult);
+            }
+        }
+
+        // If the edit text has a composition string, don't call updateGoButton().
+        // That method resets IME and composition state will be broken.
+        if (!hasCompositionString(s) ||
+            InputMethods.isGestureKeyboard(mUrlEditText.getContext())) {
+            updateGoButton(text);
+        }
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count,
+                                  int after) {
+        // do nothing
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before,
+                              int count) {
+        // do nothing
+    }
+
     public boolean isVisible() {
         return getScrollY() == 0;
     }
 
     public void setNextFocusDownId(int nextId) {
         super.setNextFocusDownId(nextId);
         mTabs.setNextFocusDownId(nextId);
         mBack.setNextFocusDownId(nextId);
@@ -554,200 +826,35 @@ public class BrowserToolbar extends Geck
 
     @Override
     public void onAnimationEnd(Animation animation) {
         if (animation.equals(mTitleSlideRight)) {
             mSiteSecurity.startAnimation(mLockFadeIn);
         }
     }
 
-    private int getAwesomeBarEntryTranslation() {
-        return getWidth() - mAwesomeBarEntry.getRight();
+    private int getUrlBarEntryTranslation() {
+        return getWidth() - mUrlBarEntry.getRight();
     }
 
-    private int getAwesomeBarCurveTranslation() {
+    private int getUrlBarCurveTranslation() {
         return getWidth() - mTabs.getLeft();
     }
 
-    public void fromAwesomeBarSearch(String url) {
-        // Update the title with the url that was just entered. Don't update the title if
-        // the AwesomeBar activity was cancelled, or if the user entered an empty string.
-        if (url != null && url.length() > 0) {
-            setTitle(url);
-        }
-
-        if (HardwareUtils.isTablet() || Build.VERSION.SDK_INT < 11) {
-            return;
-        }
-
-        // If the awesomebar entry is not selected at this point, this means that
-        // we had to reinflate the toolbar layout for some reason (device rotation
-        // while in awesome screen, activity was killed in background, etc). In this
-        // case, we have to ensure the toolbar is in the correct initial state to
-        // shrink back.
-        if (!isSelected()) {
-            // Keep the entry highlighted during the animation
-            setSelected(true);
-
-            final int entryTranslation = getAwesomeBarEntryTranslation();
-            final int curveTranslation = getAwesomeBarCurveTranslation();
-
-            if (mAwesomeBarRightEdge != null) {
-                ViewHelper.setTranslationX(mAwesomeBarRightEdge, entryTranslation);
-            }
-
-            ViewHelper.setTranslationX(mTabs, curveTranslation);
-            ViewHelper.setTranslationX(mTabsCounter, curveTranslation);
-            ViewHelper.setTranslationX(mActionItemBar, curveTranslation);
-
-            if (mHasSoftMenuButton) {
-                ViewHelper.setTranslationX(mMenu, curveTranslation);
-                ViewHelper.setTranslationX(mMenuIcon, curveTranslation);
-            }
-
-            ViewHelper.setAlpha(mPageActionLayout, 0);
-            ViewHelper.setAlpha(mStop, 0);
-        }
-
-        final PropertyAnimator contentAnimator = new PropertyAnimator(250);
-        contentAnimator.setUseHardwareLayer(false);
-
-        // Shrink the awesome entry back to its original size
-
-        if (mAwesomeBarRightEdge != null) {
-            contentAnimator.attach(mAwesomeBarRightEdge,
-                                   PropertyAnimator.Property.TRANSLATION_X,
-                                   0);
-        }
-
-        contentAnimator.attach(mTabs,
-                               PropertyAnimator.Property.TRANSLATION_X,
-                               0);
-        contentAnimator.attach(mTabsCounter,
-                               PropertyAnimator.Property.TRANSLATION_X,
-                               0);
-        contentAnimator.attach(mActionItemBar,
-                               PropertyAnimator.Property.TRANSLATION_X,
-                               0);
-
-        if (mHasSoftMenuButton) {
-            contentAnimator.attach(mMenu,
-                                   PropertyAnimator.Property.TRANSLATION_X,
-                                   0);
-            contentAnimator.attach(mMenuIcon,
-                                   PropertyAnimator.Property.TRANSLATION_X,
-                                   0);
-        }
-
-        contentAnimator.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
-            @Override
-            public void onPropertyAnimationStart() {
+    private static boolean hasCompositionString(Editable content) {
+        Object[] spans = content.getSpans(0, content.length(), Object.class);
+        if (spans != null) {
+            for (Object span : spans) {
+                if ((content.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
+                    // Found composition string.
+                    return true;
+                }
             }
-
-            @Override
-            public void onPropertyAnimationEnd() {
-                // Turn off selected state on the entry
-                setSelected(false);
-
-                PropertyAnimator buttonsAnimator = new PropertyAnimator(300);
-
-                // Fade toolbar buttons (reader, stop) after the entry
-                // is schrunk back to its original size.
-                buttonsAnimator.attach(mPageActionLayout,
-                                       PropertyAnimator.Property.ALPHA,
-                                       1);
-                buttonsAnimator.attach(mStop,
-                                       PropertyAnimator.Property.ALPHA,
-                                       1);
-
-                buttonsAnimator.start();
-
-                mAnimatingEntry = false;
-
-                // Trigger animation to update the tabs counter once the
-                // tabs button is back on screen.
-                updateTabCount(Tabs.getInstance().getDisplayCount());
-            }
-        });
-
-        mAnimatingEntry = true;
-
-        postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                contentAnimator.start();
-            }
-        }, 500);
-    }
-
-    private void onAwesomeBarSearch() {
-        // This animation doesn't make much sense in a sidebar UI
-        if (HardwareUtils.isTablet() || Build.VERSION.SDK_INT < 11) {
-            mActivity.onSearchRequested();
-            return;
         }
-
-        if (mAnimatingEntry)
-            return;
-
-        final PropertyAnimator contentAnimator = new PropertyAnimator(250);
-        contentAnimator.setUseHardwareLayer(false);
-
-        final int entryTranslation = getAwesomeBarEntryTranslation();
-        final int curveTranslation = getAwesomeBarCurveTranslation();
-
-        // Keep the entry highlighted during the animation
-        setSelected(true);
-
-        // Hide stop/reader buttons immediately
-        ViewHelper.setAlpha(mPageActionLayout, 0);
-        ViewHelper.setAlpha(mStop, 0);
-
-        // Slide the right side elements of the toolbar
-
-        if (mAwesomeBarRightEdge != null) {
-            contentAnimator.attach(mAwesomeBarRightEdge,
-                                   PropertyAnimator.Property.TRANSLATION_X,
-                                   entryTranslation);
-        }
-
-        contentAnimator.attach(mTabs,
-                               PropertyAnimator.Property.TRANSLATION_X,
-                               curveTranslation);
-        contentAnimator.attach(mTabsCounter,
-                               PropertyAnimator.Property.TRANSLATION_X,
-                               curveTranslation);
-        contentAnimator.attach(mActionItemBar,
-                               PropertyAnimator.Property.TRANSLATION_X,
-                               curveTranslation);
-
-        if (mHasSoftMenuButton) {
-            contentAnimator.attach(mMenu,
-                                   PropertyAnimator.Property.TRANSLATION_X,
-                                   curveTranslation);
-            contentAnimator.attach(mMenuIcon,
-                                   PropertyAnimator.Property.TRANSLATION_X,
-                                   curveTranslation);
-        }
-
-        contentAnimator.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
-            @Override
-            public void onPropertyAnimationStart() {
-            }
-
-            @Override
-            public void onPropertyAnimationEnd() {
-                // Once the entry is fully expanded, start awesome screen
-                mActivity.onSearchRequested();
-                mAnimatingEntry = false;
-            }
-        });
-
-        mAnimatingEntry = true;
-        contentAnimator.start();
+        return false;
     }
 
     private void addTab() {
         mActivity.addTab();
     }
 
     private void toggleTabs() {
         if (mActivity.areTabsShown()) {
@@ -764,22 +871,42 @@ public class BrowserToolbar extends Geck
                 if (!tab.isPrivate())
                     mActivity.showNormalTabs();
                 else
                     mActivity.showPrivateTabs();
             }
         }
     }
 
-    public void updateTabCount(int count) {
-        // If toolbar is selected, this means the entry is expanded and the
+    public void updateTabCountAndAnimate(int count) {
+        // Don't animate if the toolbar is hidden.
+        if (!isVisible()) {
+            updateTabCount(count);
+            return;
+        }
+
+        // If toolbar is in edit mode, this means the entry is expanded and the
         // tabs button is translated offscreen. Don't trigger tabs counter
         // updates until the tabs button is back on screen.
-        // See fromAwesomeBarSearch()
-        if (isSelected()) {
+        // See stopEditing()
+        if (!isEditing()) {
+            mTabsCounter.setCount(count);
+
+            mTabs.setContentDescription((count > 1) ?
+                                        mActivity.getString(R.string.num_tabs, count) :
+                                        mActivity.getString(R.string.one_tab));
+        }
+    }
+
+    public void updateTabCount(int count) {
+        // If toolbar is in edit mode, this means the entry is expanded and the
+        // tabs button is translated offscreen. Don't trigger tabs counter
+        // updates until the tabs button is back on screen.
+        // See stopEditing()
+        if (isEditing()) {
             return;
         }
 
         // Set TabCounter based on visibility
         if (isVisible() && ViewHelper.getAlpha(mTabsCounter) != 0) {
             mTabsCounter.setCountWithAnimation(count);
         } else {
             mTabsCounter.setCount(count);
@@ -914,39 +1041,57 @@ public class BrowserToolbar extends Geck
     public void setShadowVisibility(boolean visible) {
         Tab tab = Tabs.getInstance().getSelectedTab();
         if (tab == null) {
             return;
         }
 
         String url = tab.getURL();
 
-        // Only set shadow to visible when not on about screens except about:blank.
-        visible &= !(url == null || (url.startsWith("about:") &&
-                     !url.equals("about:blank")));
+        // Only set shadow to visible when not on about screens (except about:blank)
+        // and when not in editing mode.
+        visible &= !(url == null || (url.startsWith("about:") && 
+                     !url.equals("about:blank"))) && !isEditing();
 
         if ((mShadow.getVisibility() == View.VISIBLE) != visible) {
             mShadow.setVisibility(visible ? View.VISIBLE : View.GONE);
         }
     }
 
+    public void onEditSuggestion(String suggestion) {
+        if (!isEditing()) {
+            return;
+        }
+
+        mUrlEditText.setText(suggestion);
+        mUrlEditText.setSelection(mUrlEditText.getText().length());
+        mUrlEditText.requestFocus();
+
+        showSoftInput();
+    }
+
     private void setTitle(CharSequence title) {
         mTitle.setText(title);
         setContentDescription(title != null ? title : mTitle.getHint());
     }
 
     // Sets the toolbar title according to the selected tab, obeying the mShowUrl prference.
     private void updateTitle() {
         Tab tab = Tabs.getInstance().getSelectedTab();
         // Keep the title unchanged if there's no selected tab, or if the tab is entering reader mode.
         if (tab == null || tab.isEnteringReaderMode()) {
             return;
         }
 
         String url = tab.getURL();
+
+        if (!isEditing()) {
+            mUrlEditText.setText(url);
+        }
+
         // Setting a null title will ensure we just see the "Enter Search or Address" placeholder text.
         if ("about:home".equals(url) || "about:privatebrowsing".equals(url)) {
             setTitle(null);
             return;
         }
 
         // Show the about:blocked page title in red, regardless of prefs
         if (tab.getErrorType() == Tab.ErrorType.BLOCKED) {
@@ -1022,16 +1167,401 @@ public class BrowserToolbar extends Geck
 
         ViewHelper.setAlpha(mTabsCounter, 0.0f);
 
         if (mHasSoftMenuButton && !HardwareUtils.isTablet()) {
             ViewHelper.setAlpha(mMenuIcon, 0.0f);
         }
     }
 
+    public void finishTabsAnimation(boolean tabsAreShown) {
+        if (tabsAreShown) {
+            return;
+        }
+
+        PropertyAnimator animator = new PropertyAnimator(150);
+
+        animator.attach(mTabsCounter,
+                        PropertyAnimator.Property.ALPHA,
+                        1.0f);
+
+        if (mHasSoftMenuButton && !HardwareUtils.isTablet()) {
+            animator.attach(mMenuIcon,
+                            PropertyAnimator.Property.ALPHA,
+                            1.0f);
+        }
+
+        animator.start();
+    }
+
+    public void setOnActivateListener(OnActivateListener listener) {
+        mActivateListener = listener;
+    }
+
+    public void setOnCommitListener(OnCommitListener listener) {
+        mCommitListener = listener;
+    }
+
+    public void setOnDismissListener(OnDismissListener listener) {
+        mDismissListener = listener;
+    }
+
+    public void setOnFilterListener(OnFilterListener listener) {
+        mFilterListener = listener;
+    }
+
+    private void showSoftInput() {
+        InputMethodManager imm =
+               (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.showSoftInput(mUrlEditText, InputMethodManager.SHOW_IMPLICIT);
+    }
+
+    private void showUrlEditContainer() {
+        setUrlEditContainerVisibility(true, null);
+    }
+
+    private void showUrlEditContainer(PropertyAnimator animator) {
+        setUrlEditContainerVisibility(true, animator);
+    }
+
+    private void hideUrlEditContainer() {
+        setUrlEditContainerVisibility(false, null);
+    }
+
+    private void hideUrlEditContainer(PropertyAnimator animator) {
+        setUrlEditContainerVisibility(false, animator);
+    }
+
+    private void setUrlEditContainerVisibility(final boolean showEditContainer, PropertyAnimator animator) {
+        final View viewToShow = (showEditContainer ? mUrlEditContainer : mUrlDisplayContainer);
+        final View viewToHide = (showEditContainer ? mUrlDisplayContainer : mUrlEditContainer);
+
+        if (animator == null) {
+            viewToHide.setVisibility(View.GONE);
+            viewToShow.setVisibility(View.VISIBLE);
+
+            if (showEditContainer) {
+                mUrlEditText.requestFocus();
+                showSoftInput();
+            }
+
+            return;
+        }
+
+        ViewHelper.setAlpha(viewToShow, 0.0f);
+        animator.attach(viewToShow,
+                        PropertyAnimator.Property.ALPHA,
+                        1.0f);
+
+        animator.attach(viewToHide,
+                        PropertyAnimator.Property.ALPHA,
+                        0.0f);
+
+        animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+            @Override
+            public void onPropertyAnimationStart() {
+                viewToShow.setVisibility(View.VISIBLE);
+
+                if (showEditContainer) {
+                    ViewHelper.setAlpha(mGo, 0.0f);
+                    mUrlEditText.requestFocus();
+                }
+            }
+
+            @Override
+            public void onPropertyAnimationEnd() {
+                viewToHide.setVisibility(View.GONE);
+                ViewHelper.setAlpha(viewToHide, 1.0f);
+
+                if (showEditContainer) {
+                    ViewHelper.setAlpha(mGo, 1.0f);
+                    showSoftInput();
+                }
+            }
+        });
+    }
+
+    /**
+     * Returns whether or not the URL bar is in editing mode (url bar is expanded, hiding the new
+     * tab button). Note that selection state is independent of editing mode.
+     */
+    public boolean isEditing() {
+        return mIsEditing;
+    }
+
+    public void startEditing(String url, PropertyAnimator animator) {
+        if (isEditing()) {
+            return;
+        }
+
+        mUrlEditText.setText(url != null ? url : "");
+        mIsEditing = true;
+
+        final int entryTranslation = getUrlBarEntryTranslation();
+        final int curveTranslation = getUrlBarCurveTranslation();
+
+        // This animation doesn't make much sense in a sidebar UI
+        if (HardwareUtils.isTablet() || Build.VERSION.SDK_INT < 11) {
+            showUrlEditContainer();
+
+            if (!HardwareUtils.isTablet()) {
+                if (mUrlBarRightEdge != null) {
+                    ViewHelper.setTranslationX(mUrlBarRightEdge, entryTranslation);
+                }
+
+                ViewHelper.setTranslationX(mTabs, curveTranslation);
+                ViewHelper.setTranslationX(mTabsCounter, curveTranslation);
+                ViewHelper.setTranslationX(mActionItemBar, curveTranslation);
+
+                if (mHasSoftMenuButton) {
+                    ViewHelper.setTranslationX(mMenu, curveTranslation);
+                    ViewHelper.setTranslationX(mMenuIcon, curveTranslation);
+                }
+            }
+
+            return;
+        }
+
+        if (mAnimatingEntry)
+            return;
+
+        // Highlight the toolbar from the start of the animation.
+        setSelected(true);
+
+        // Hide page actions/stop buttons immediately
+        ViewHelper.setAlpha(mPageActionLayout, 0);
+        ViewHelper.setAlpha(mStop, 0);
+
+        // Slide the right side elements of the toolbar
+
+        if (mUrlBarRightEdge != null) {
+            animator.attach(mUrlBarRightEdge,
+                            PropertyAnimator.Property.TRANSLATION_X,
+                            entryTranslation);
+        }
+
+        animator.attach(mTabs,
+                        PropertyAnimator.Property.TRANSLATION_X,
+                        curveTranslation);
+        animator.attach(mTabsCounter,
+                        PropertyAnimator.Property.TRANSLATION_X,
+                        curveTranslation);
+        animator.attach(mActionItemBar,
+                        PropertyAnimator.Property.TRANSLATION_X,
+                        curveTranslation);
+
+        if (mHasSoftMenuButton) {
+            animator.attach(mMenu,
+                            PropertyAnimator.Property.TRANSLATION_X,
+                            curveTranslation);
+
+            animator.attach(mMenuIcon,
+                            PropertyAnimator.Property.TRANSLATION_X,
+                            curveTranslation);
+        }
+
+        showUrlEditContainer(animator);
+
+        animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+            @Override
+            public void onPropertyAnimationStart() {
+            }
+
+            @Override
+            public void onPropertyAnimationEnd() {
+                mAnimatingEntry = false;
+            }
+        });
+
+        mAnimatingEntry = true;
+    }
+
+    /**
+     * Exits edit mode without updating the toolbar title.
+     *
+     * @return the url that was entered
+     */
+    public String cancelEdit() {
+        return stopEditing();
+    }
+
+    /**
+     * Exits edit mode, updating the toolbar title with the url that was just entered.
+     *
+     * @return the url that was entered
+     */
+    public String commitEdit() {
+        final String url = stopEditing();
+        if (!TextUtils.isEmpty(url)) {
+            setTitle(url);
+        }
+        return url;
+    }
+
+    private String stopEditing() {
+        final String url = mUrlEditText.getText().toString();
+        if (!isEditing()) {
+            return url;
+        }
+        mIsEditing = false;
+
+        if (HardwareUtils.isTablet() || Build.VERSION.SDK_INT < 11) {
+            hideUrlEditContainer();
+            updateTabCountAndAnimate(Tabs.getInstance().getDisplayCount());
+
+            if (!HardwareUtils.isTablet()) {
+                if (mUrlBarRightEdge != null) {
+                    ViewHelper.setTranslationX(mUrlBarRightEdge, 0);
+                }
+
+                ViewHelper.setTranslationX(mTabs, 0);
+                ViewHelper.setTranslationX(mTabsCounter, 0);
+                ViewHelper.setTranslationX(mActionItemBar, 0);
+
+                if (mHasSoftMenuButton) {
+                    ViewHelper.setTranslationX(mMenu, 0);
+                    ViewHelper.setTranslationX(mMenuIcon, 0);
+                }
+            }
+
+            return url;
+        }
+
+        final PropertyAnimator contentAnimator = new PropertyAnimator(250);
+        contentAnimator.setUseHardwareLayer(false);
+
+        // Shrink the urlbar entry back to its original size
+
+        if (mUrlBarRightEdge != null) {
+            contentAnimator.attach(mUrlBarRightEdge,
+                                   PropertyAnimator.Property.TRANSLATION_X,
+                                   0);
+        }
+
+        contentAnimator.attach(mTabs,
+                               PropertyAnimator.Property.TRANSLATION_X,
+                               0);
+        contentAnimator.attach(mTabsCounter,
+                               PropertyAnimator.Property.TRANSLATION_X,
+                               0);
+        contentAnimator.attach(mActionItemBar,
+                               PropertyAnimator.Property.TRANSLATION_X,
+                               0);
+
+        if (mHasSoftMenuButton) {
+            contentAnimator.attach(mMenu,
+                                   PropertyAnimator.Property.TRANSLATION_X,
+                                   0);
+
+            contentAnimator.attach(mMenuIcon,
+                                   PropertyAnimator.Property.TRANSLATION_X,
+                                   0);
+        }
+
+        hideUrlEditContainer(contentAnimator);
+
+        contentAnimator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+            @Override
+            public void onPropertyAnimationStart() {
+            }
+
+            @Override
+            public void onPropertyAnimationEnd() {
+                setShadowVisibility(true);
+
+                PropertyAnimator buttonsAnimator = new PropertyAnimator(300);
+
+                // Fade toolbar buttons (page actions, stop) after the entry
+                // is schrunk back to its original size.
+                buttonsAnimator.attach(mPageActionLayout,
+                                       PropertyAnimator.Property.ALPHA,
+                                       1);
+                buttonsAnimator.attach(mStop,
+                                       PropertyAnimator.Property.ALPHA,
+                                       1);
+
+                buttonsAnimator.start();
+
+                mAnimatingEntry = false;
+
+                // Trigger animation to update the tabs counter once the
+                // tabs button is back on screen.
+                updateTabCountAndAnimate(Tabs.getInstance().getDisplayCount());
+            }
+        });
+
+        mAnimatingEntry = true;
+        contentAnimator.start();
+
+        return url;
+    }
+
+    private void updateGoButton(String text) {
+        if (text.length() == 0) {
+            mGo.setVisibility(View.GONE);
+            return;
+        }
+
+        mGo.setVisibility(View.VISIBLE);
+
+        int imageResource = R.drawable.ic_url_bar_go;
+        String contentDescription = mActivity.getString(R.string.go);
+        int imeAction = EditorInfo.IME_ACTION_GO;
+
+        int actionBits = mUrlEditText.getImeOptions() & EditorInfo.IME_MASK_ACTION;
+        if (StringUtils.isSearchQuery(text, actionBits == EditorInfo.IME_ACTION_SEARCH)) {
+            imageResource = R.drawable.ic_url_bar_search;
+            contentDescription = mActivity.getString(R.string.search);
+            imeAction = EditorInfo.IME_ACTION_SEARCH;
+        }
+
+        InputMethodManager imm = InputMethods.getInputMethodManager(mUrlEditText.getContext());
+        if (imm == null) {
+            return;
+        }
+        boolean restartInput = false;
+        if (actionBits != imeAction) {
+            int optionBits = mUrlEditText.getImeOptions() & ~EditorInfo.IME_MASK_ACTION;
+            mUrlEditText.setImeOptions(optionBits | imeAction);
+
+            mDelayRestartInput = (imeAction == EditorInfo.IME_ACTION_GO) &&
+                                 (InputMethods.shouldDelayUrlBarUpdate(mUrlEditText.getContext()));
+            if (!mDelayRestartInput) {
+                restartInput = true;
+            }
+        } else if (mDelayRestartInput) {
+            // Only call delayed restartInput when actionBits == imeAction
+            // so if there are two restarts in a row, the first restarts will
+            // be discarded and the second restart will be properly delayed
+            mDelayRestartInput = false;
+            restartInput = true;
+        }
+        if (restartInput) {
+            updateKeyboardInputType();
+            imm.restartInput(mUrlEditText);
+            mGo.setImageResource(imageResource);
+            mGo.setContentDescription(contentDescription);
+        }
+    }
+
+    private void updateKeyboardInputType() {
+        // If the user enters a space, then we know they are entering search terms, not a URL.
+        // We can then switch to text mode so,
+        // 1) the IME auto-inserts spaces between words
+        // 2) the IME doesn't reset input keyboard to Latin keyboard.
+        String text = mUrlEditText.getText().toString();
+        int currentInputType = mUrlEditText.getInputType();
+        int newInputType = StringUtils.isSearchQuery(text, false)
+                           ? (currentInputType & ~InputType.TYPE_TEXT_VARIATION_URI) // Text mode
+                           : (currentInputType | InputType.TYPE_TEXT_VARIATION_URI); // URL mode
+        if (newInputType != currentInputType) {
+            mUrlEditText.setRawInputType(newInputType);
+        }
+    }
+
     public void updateBackButton(boolean enabled) {
          Drawable drawable = mBack.getDrawable();
          if (drawable != null)
              drawable.setAlpha(enabled ? 255 : 77);
 
          mBack.setEnabled(enabled);
     }
 
@@ -1045,50 +1575,58 @@ public class BrowserToolbar extends Geck
 
         if (mForward.getVisibility() != View.VISIBLE)
             return;
 
         // We want the forward button to show immediately when switching tabs
         mForwardAnim = new PropertyAnimator(mSwitchingTabs ? 10 : FORWARD_ANIMATION_DURATION);
         final int width = mForward.getWidth() / 2;
 
-        mForwardAnim.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+        mForwardAnim.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
             @Override
             public void onPropertyAnimationStart() {
                 if (!enabled) {
                     // Set the margin before the transition when hiding the forward button. We
                     // have to do this so that the favicon isn't clipped during the transition
                     ViewGroup.MarginLayoutParams layoutParams =
                         (ViewGroup.MarginLayoutParams)mUrlDisplayContainer.getLayoutParams();
                     layoutParams.leftMargin = 0;
-                    mUrlDisplayContainer.requestLayout();
+
+                    // Do the same on the URL edit container
+                    layoutParams = (ViewGroup.MarginLayoutParams)mUrlEditContainer.getLayoutParams();
+                    layoutParams.leftMargin = 0;
+
+                    requestLayout();
                     // Note, we already translated the favicon, site security, and text field
                     // in prepareForwardAnimation, so they should appear to have not moved at
                     // all at this point.
                 }
             }
 
             @Override
             public void onPropertyAnimationEnd() {
                 if (enabled) {
                     ViewGroup.MarginLayoutParams layoutParams =
                         (ViewGroup.MarginLayoutParams)mUrlDisplayContainer.getLayoutParams();
-                    layoutParams.leftMargin = mAddressBarViewOffset;
+                    layoutParams.leftMargin = mUrlBarViewOffset;
+
+                    layoutParams = (ViewGroup.MarginLayoutParams)mUrlEditContainer.getLayoutParams();
+                    layoutParams.leftMargin = mUrlBarViewOffset;
 
                     ViewHelper.setTranslationX(mTitle, 0);
                     ViewHelper.setTranslationX(mFavicon, 0);
                     ViewHelper.setTranslationX(mSiteSecurity, 0);
                 }
 
                 ViewGroup.MarginLayoutParams layoutParams =
                     (ViewGroup.MarginLayoutParams)mForward.getLayoutParams();
                 layoutParams.leftMargin = mDefaultForwardMargin + (mForward.isEnabled() ? width : 0);
                 ViewHelper.setTranslationX(mForward, 0);
 
-                mUrlDisplayContainer.requestLayout();
+                requestLayout();
                 mForwardAnim = null;
             }
         });
 
         prepareForwardAnimation(mForwardAnim, enabled, width);
         mForwardAnim.start();
     }
 
@@ -1108,35 +1646,35 @@ public class BrowserToolbar extends Geck
                       0);
             anim.attach(mSiteSecurity,
                       PropertyAnimator.Property.TRANSLATION_X,
                       0);
 
             // We're hiding the forward button. We're going to reset the margin before
             // the animation starts, so we shift these items to the right so that they don't
             // appear to move initially.
-            ViewHelper.setTranslationX(mTitle, mAddressBarViewOffset);
-            ViewHelper.setTranslationX(mFavicon, mAddressBarViewOffset);
-            ViewHelper.setTranslationX(mSiteSecurity, mAddressBarViewOffset);
+            ViewHelper.setTranslationX(mTitle, mUrlBarViewOffset);
+            ViewHelper.setTranslationX(mFavicon, mUrlBarViewOffset);
+            ViewHelper.setTranslationX(mSiteSecurity, mUrlBarViewOffset);
         } else {
             anim.attach(mForward,
                       PropertyAnimator.Property.TRANSLATION_X,
                       width);
             anim.attach(mForward,
                       PropertyAnimator.Property.ALPHA,
                       1);
             anim.attach(mTitle,
                       PropertyAnimator.Property.TRANSLATION_X,
-                      mAddressBarViewOffset);
+                      mUrlBarViewOffset);
             anim.attach(mFavicon,
                       PropertyAnimator.Property.TRANSLATION_X,
-                      mAddressBarViewOffset);
+                      mUrlBarViewOffset);
             anim.attach(mSiteSecurity,
                       PropertyAnimator.Property.TRANSLATION_X,
-                      mAddressBarViewOffset);
+                      mUrlBarViewOffset);
         }
     }
 
     @Override
     public void addActionItem(View actionItem) {
         mActionItemBar.addView(actionItem);
     }
 
@@ -1161,22 +1699,23 @@ public class BrowserToolbar extends Geck
             setProgressVisibility(tab.getState() == Tab.STATE_LOADING);
             setSecurityMode(tab.getSecurityMode());
             setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
             setShadowVisibility(true);
             updateBackButton(tab.canDoBack());
             updateForwardButton(tab.canDoForward());
 
             final boolean isPrivate = tab.isPrivate();
-            mAddressBarBg.setPrivateMode(isPrivate);
+            mUrlBarBackground.setPrivateMode(isPrivate);
             setPrivateMode(isPrivate);
             mTabs.setPrivateMode(isPrivate);
             mTitle.setPrivateMode(isPrivate);
             mMenu.setPrivateMode(isPrivate);
             mMenuIcon.setPrivateMode(isPrivate);
+            mUrlEditText.setPrivateMode(isPrivate);
 
             if (mBack instanceof BackButton)
                 ((BackButton) mBack).setPrivateMode(isPrivate);
 
             if (mForward instanceof ForwardButton)
                 ((ForwardButton) mForward).setPrivateMode(isPrivate);
         }
     }
--- a/mobile/android/base/BrowserToolbarBackground.java
+++ b/mobile/android/base/BrowserToolbarBackground.java
@@ -32,11 +32,11 @@ public class BrowserToolbarBackground ex
         stateList.addState(new int[] { R.attr.state_private }, new ColorDrawable(mActivity.getResources().getColor(R.color.background_private)));
         stateList.addState(new int[] {}, drawable);
 
         setBackgroundDrawable(stateList);
     }
 
     @Override
     public void onLightweightThemeReset() {
-        setBackgroundResource(R.drawable.address_bar_bg);
+        setBackgroundResource(R.drawable.url_bar_bg);
     }
 }
--- a/mobile/android/base/Favicons.java
+++ b/mobile/android/base/Favicons.java
@@ -238,20 +238,20 @@ public class Favicons {
         color = BitmapUtils.getDominantColor(image);
         mColorCache.put(key, color);
         return color;
     }
 
     public void attachToContext(Context context) {
         mContext = context;
         if (sFaviconSmallSize < 0) {
-            sFaviconSmallSize = Math.round(mContext.getResources().getDimension(R.dimen.awesomebar_row_favicon_size_small));
+            sFaviconSmallSize = Math.round(mContext.getResources().getDimension(R.dimen.favicon_size_small));
         }
         if (sFaviconLargeSize < 0) {
-            sFaviconLargeSize = Math.round(mContext.getResources().getDimension(R.dimen.awesomebar_row_favicon_size_large));
+            sFaviconLargeSize = Math.round(mContext.getResources().getDimension(R.dimen.favicon_size_large));
         }
     }
 
     private class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
         private long mId;
         private String mPageUrl;
         private String mFaviconUrl;
         private OnFaviconLoadedListener mListener;
--- a/mobile/android/base/ForwardButton.java
+++ b/mobile/android/base/ForwardButton.java
@@ -61,17 +61,17 @@ public class ForwardButton extends Shape
     @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
 
         // Draw the border on top.
         canvas.drawPath(mBorderPath, isPrivateMode() ? mBorderPrivatePaint : mBorderPaint);
     }
 
-    // The drawable is constructed as per @drawable/address_bar_nav_button.
+    // The drawable is constructed as per @drawable/url_bar_nav_button.
     @Override
     public void onLightweightThemeChanged() {
         Drawable drawable = mActivity.getLightweightTheme().getDrawable(this);
         if (drawable == null)
             return;
 
         Resources resources = getContext().getResources();
         StateListDrawable stateList = new StateListDrawable();
@@ -83,11 +83,11 @@ public class ForwardButton extends Shape
         stateList.addState(new int[] { R.attr.state_private }, new ColorDrawable(resources.getColor(R.color.background_private)));
         stateList.addState(new int[] {}, drawable);
 
         setBackgroundDrawable(stateList);
     }
 
     @Override
     public void onLightweightThemeReset() {
-        setBackgroundResource(R.drawable.address_bar_nav_button);
+        setBackgroundResource(R.drawable.url_bar_nav_button);
     }
 }
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -562,18 +562,16 @@ abstract public class GeckoApp
                 }
             } else if (event.equals("log")) {
                 // generic log listener
                 final String msg = message.getString("msg");
                 Log.d(LOGTAG, "Log: " + msg);
             } else if (event.equals("Reader:FaviconRequest")) {
                 final String url = message.getString("url");
                 handleFaviconRequest(url);
-            } else if (event.equals("Reader:GoToReadingList")) {
-                showReadingList();
             } else if (event.equals("Gecko:Ready")) {
                 mGeckoReadyStartupTimer.stop();
                 geckoConnected();
 
                 // This method is already running on the background thread, so we
                 // know that mHealthRecorder will exist. That doesn't stop us being
                 // paranoid.
                 // This method is cheap, so don't spawn a new runnable.
@@ -1474,17 +1472,16 @@ abstract public class GeckoApp
 
         //register for events
         registerEventListener("log");
         registerEventListener("Reader:ListCountRequest");
         registerEventListener("Reader:Added");
         registerEventListener("Reader:Removed");
         registerEventListener("Reader:Share");
         registerEventListener("Reader:FaviconRequest");
-        registerEventListener("Reader:GoToReadingList");
         registerEventListener("onCameraCapture");
         registerEventListener("Menu:Add");
         registerEventListener("Menu:Remove");
         registerEventListener("Menu:Update");
         registerEventListener("Gecko:Ready");
         registerEventListener("Toast:Show");
         registerEventListener("DOMFullScreen:Start");
         registerEventListener("DOMFullScreen:Stop");
@@ -2023,17 +2020,16 @@ abstract public class GeckoApp
     public void onDestroy()
     {
         unregisterEventListener("log");
         unregisterEventListener("Reader:ListCountRequest");
         unregisterEventListener("Reader:Added");
         unregisterEventListener("Reader:Removed");
         unregisterEventListener("Reader:Share");
         unregisterEventListener("Reader:FaviconRequest");
-        unregisterEventListener("Reader:GoToReadingList");
         unregisterEventListener("onCameraCapture");
         unregisterEventListener("Menu:Add");
         unregisterEventListener("Menu:Remove");
         unregisterEventListener("Menu:Update");
         unregisterEventListener("Gecko:Ready");
         unregisterEventListener("Toast:Show");
         unregisterEventListener("DOMFullScreen:Start");
         unregisterEventListener("DOMFullScreen:Stop");
@@ -2256,28 +2252,23 @@ abstract public class GeckoApp
             }
         }
     }
 
     public PromptService getPromptService() {
         return mPromptService;
     }
 
-    public void showReadingList() {
-        Intent intent = new Intent(getBaseContext(), AwesomeBar.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
-        intent.putExtra(AwesomeBar.TARGET_KEY, AwesomeBar.Target.CURRENT_TAB.toString());
-        intent.putExtra(AwesomeBar.READING_LIST_KEY, true);
-
-        int requestCode = GeckoAppShell.sActivityHelper.makeRequestCodeForAwesomebar();
-        startActivityForResult(intent, requestCode);
-    }
-
     @Override
     public void onBackPressed() {
+        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
+            super.onBackPressed();
+            return;
+        }
+
         if (autoHideTabs()) {
             return;
         }
 
         if (mDoorHangerPopup != null && mDoorHangerPopup.isShowing()) {
             mDoorHangerPopup.dismiss();
             return;
         }
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -692,18 +692,18 @@ public class GeckoAppShell
     static void createShortcut(String aTitle, String aURI, String aIconData, String aType) {
         if ("webapp".equals(aType)) {
             Log.w(LOGTAG, "createShortcut with no unique URI should not be used for aType = webapp!");
         }
 
         createShortcut(aTitle, aURI, aURI, aIconData, aType);
     }
 
-    // internal, for non-webapps
-    static void createShortcut(String aTitle, String aURI, Bitmap aBitmap, String aType) {
+    // for non-webapps
+    public static void createShortcut(String aTitle, String aURI, Bitmap aBitmap, String aType) {
         createShortcut(aTitle, aURI, aURI, aBitmap, aType);
     }
 
     // internal, for webapps
     static void createShortcut(String aTitle, String aURI, String aUniqueURI, String aIconData, String aType) {
         createShortcut(aTitle, aURI, aUniqueURI, BitmapUtils.getBitmapFromDataURI(aIconData), aType);
     }
 
@@ -1064,22 +1064,22 @@ public class GeckoAppShell
      *
      * @param targetURI the string spec of the URI to open.
      * @param mimeType an optional MIME type string.
      * @param action an Android action specifier, such as
      *               <code>Intent.ACTION_SEND</code>.
      * @param title the title to use in <code>ACTION_SEND</code> intents.
      * @return true if the activity started successfully; false otherwise.
      */
-    static boolean openUriExternal(String targetURI,
-                                   String mimeType,
-                                   String packageName,
-                                   String className,
-                                   String action,
-                                   String title) {
+    public static boolean openUriExternal(String targetURI,
+                                          String mimeType,
+                                          String packageName,
+                                          String className,
+                                          String action,
+                                          String title) {
         final Context context = getContext();
         final Intent intent = getOpenURIIntent(context, targetURI,
                                                mimeType, action, title);
 
         if (intent == null) {
             return false;
         }
 
--- a/mobile/android/base/InputMethods.java
+++ b/mobile/android/base/InputMethods.java
@@ -56,17 +56,17 @@ final class InputMethods {
         return Build.VERSION.SDK_INT >= 17 && (METHOD_ANDROID_LATINIME.equals(inputMethod) ||
                                                METHOD_GOOGLE_LATINIME.equals(inputMethod));
     }
 
     public static boolean shouldCommitCharAsKey(String inputMethod) {
         return METHOD_HTC_TOUCH_INPUT.equals(inputMethod);
     }
 
-    public static boolean shouldDelayAwesomebarUpdate(Context context) {
+    public static boolean shouldDelayUrlBarUpdate(Context context) {
         String inputMethod = getCurrentInputMethod(context);
         return METHOD_SAMSUNG.equals(inputMethod) ||
                METHOD_SWIFTKEY.equals(inputMethod);
     }
 
     public static boolean isGestureKeyboard(Context context) {
         // SwiftKey is a gesture keyboard, but it doesn't seem to need any special-casing
         // to do AwesomeBar auto-spacing.
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -49,28 +49,22 @@ FENNEC_JAVA_FILES = \
   ActivityHandlerHelper.java \
   AlertNotification.java \
   AlignRightLinkPreference.java \
   AllCapsTextView.java \
   AndroidImport.java \
   AndroidImportPreference.java \
   AnimatedHeightLayout.java \
   AppNotificationClient.java \
-  AwesomeBar.java \
-  AwesomebarResultHandler.java \
-  AwesomeBarTabs.java \
+  AutocompleteHandler.java \
   animation/AnimatorProxy.java \
   animation/HeightChangeAnimation.java \
   animation/PropertyAnimator.java \
   animation/Rotate3DAnimation.java \
   animation/ViewHelper.java \
-  awesomebar/AwesomeBarTab.java \
-  awesomebar/AllPagesTab.java \
-  awesomebar/BookmarksTab.java \
-  awesomebar/HistoryTab.java \
   BackButton.java \
   BrowserApp.java \
   BrowserToolbar.java \
   BrowserToolbarBackground.java \
   CameraImageResultHandler.java \
   CameraVideoResultHandler.java \
   CanvasDelegate.java \
   CheckableLinearLayout.java \
@@ -133,33 +127,30 @@ FENNEC_JAVA_FILES = \
   PageActionLayout.java \
   PrefsHelper.java \
   PrivateDataPreference.java \
   PrivateTab.java \
   Prompt.java \
   PromptInput.java \
   PromptService.java \
   Restarter.java \
-  SearchEngine.java \
   sqlite/ByteBufferInputStream.java \
   sqlite/MatrixBlobCursor.java \
   sqlite/SQLiteBridge.java \
   sqlite/SQLiteBridgeException.java \
   ReaderModeUtils.java \
   RemoteTabs.java \
   RobocopAPI.java \
-  SearchEngineRow.java \
   ServiceNotificationClient.java \
   ScrollAnimator.java \
   SessionParser.java \
   ShapedButton.java \
   SharedPreferencesHelper.java \
   SiteIdentityPopup.java \
   SmsManager.java \
-  SuggestClient.java \
   SurfaceBits.java \
   SyncPreference.java \
   Tab.java \
   TabCounter.java \
   Tabs.java \
   TabsPanel.java \
   TabsTray.java \
   TabsAccessor.java \
@@ -219,45 +210,66 @@ FENNEC_JAVA_FILES = \
   gfx/SubdocumentScrollHelper.java \
   gfx/TextLayer.java \
   gfx/TextureGenerator.java \
   gfx/TextureReaper.java \
   gfx/TileLayer.java \
   gfx/TouchEventHandler.java \
   gfx/ViewTransform.java \
   gfx/VirtualLayer.java \
+  home/BookmarksListAdapter.java \
+  home/BookmarksListView.java \
+  home/BookmarksPage.java \
+  home/BookmarkFolderView.java \
+  home/BookmarkThumbnailView.java \
+  home/BrowserSearch.java \
+  home/HistoryPage.java \
+  home/HomeCursorLoaderCallbacks.java \
+  home/HomeFragment.java \
+  home/HomeListView.java \
+  home/HomePager.java \
+  home/HomePagerTabStrip.java \
+  home/FadedTextView.java \
+  home/FaviconsLoader.java \
+  home/LastTabsPage.java \
+  home/MostRecentPage.java \
+  home/MostVisitedPage.java \
+  home/MultiTypeCursorAdapter.java \
+  home/PinBookmarkDialog.java \
+  home/ReadingListPage.java \
+  home/SearchEngine.java \
+  home/SearchEngineRow.java \
+  home/SearchLoader.java \
+  home/SimpleCursorLoader.java \
+  home/SuggestClient.java \
+  home/TabMenuStrip.java \
+  home/TopBookmarkItemView.java \
+  home/TopBookmarksAdapter.java \
+  home/TopBookmarksView.java \
+  home/TwoLinePageRow.java \
   menu/GeckoMenu.java \
   menu/GeckoMenuInflater.java \
   menu/GeckoMenuItem.java \
   menu/GeckoSubMenu.java \
   menu/MenuItemActionBar.java \
   menu/MenuItemActionView.java \
   menu/MenuItemDefault.java \
   menu/MenuPanel.java \
   menu/MenuPopup.java \
   preferences/SearchPreferenceCategory.java \
   preferences/SearchEnginePreference.java \
-  widget/AboutHome.java \
-  widget/AboutHomeView.java \
-  widget/AboutHomeSection.java \
   widget/ActivityChooserModel.java \
-  widget/AddonsSection.java \
   widget/ButtonToast.java \
   widget/ArrowPopup.java \
   widget/DateTimePicker.java \
   widget/Divider.java \
   widget/FaviconView.java \
   widget/GeckoPopupMenu.java \
   widget/GeckoActionProvider.java \
   widget/IconTabWidget.java \
-  widget/LastTabsSection.java \
-  widget/LinkTextView.java \
-  widget/PromoBox.java \
-  widget/RemoteTabsSection.java \
-  widget/TopSitesView.java \
   widget/TabRow.java \
   widget/ThumbnailView.java \
   widget/TwoWayView.java \
   GeckoNetworkManager.java \
   GeckoScreenOrientationListener.java \
   UpdateService.java \
   GeckoUpdateReceiver.java \
   ReferrerReceiver.java \
@@ -436,100 +448,109 @@ ifdef MOZ_ANDROID_SHARED_ID
 DEFINES += -DMOZ_ANDROID_SHARED_ID="$(MOZ_ANDROID_SHARED_ID)"
 endif
 ifdef MOZ_ANDROID_SHARED_ACCOUNT_TYPE
 DEFINES += -DMOZ_ANDROID_SHARED_ACCOUNT_TYPE="$(MOZ_ANDROID_SHARED_ACCOUNT_TYPE)"
 endif
 
 RES_LAYOUT = \
   $(SYNC_RES_LAYOUT) \
-  res/layout/abouthome_content.xml \
   res/layout/arrow_popup.xml \
   res/layout/autocomplete_list.xml \
   res/layout/autocomplete_list_item.xml \
-  res/layout/awesomebar.xml \
-  res/layout/awesomebar_folder_row.xml \
-  res/layout/awesomebar_header_row.xml \
-  res/layout/awesomebar_allpages_list.xml \
-  res/layout/awesomebar_row.xml \
-  res/layout/awesomebar_search.xml \
-  res/layout/awesomebar_suggestion_prompt.xml \
-  res/layout/awesomebar_tab_indicator.xml \
-  res/layout/awesomebar_tabs.xml \
   res/layout/bookmark_edit.xml \
+  res/layout/bookmark_folder_row.xml \
+  res/layout/bookmark_item_row.xml \
+  res/layout/browser_search.xml \
   res/layout/browser_toolbar.xml \
   res/layout/datetime_picker.xml \
   res/layout/doorhanger.xml \
   res/layout/doorhanger_button.xml \
   res/layout/find_in_page_content.xml \
   res/layout/font_size_preference.xml \
   res/layout/gecko_app.xml \
+  res/layout/home_bookmarks_page.xml \
+  res/layout/home_empty_page.xml \
+  res/layout/home_empty_reading_page.xml \
+  res/layout/home_item_row.xml \
+  res/layout/home_header_row.xml \
+  res/layout/home_history_page.xml \
+  res/layout/home_history_tabs_indicator.xml \
+  res/layout/home_last_tabs_page.xml \
+  res/layout/home_history_list.xml \
+  res/layout/home_most_recent_page.xml \
+  res/layout/home_most_visited_page.xml \
+  res/layout/home_pager.xml \
+  res/layout/home_reading_list_page.xml \
   res/layout/home_search_item_row.xml \
+  res/layout/home_suggestion_prompt.xml \
   res/layout/web_app.xml \
   res/layout/launch_app_list.xml \
   res/layout/launch_app_listitem.xml \
   res/layout/menu_action_bar.xml \
   res/layout/menu_item_action_view.xml \
   res/layout/menu_popup.xml \
   res/layout/notification_icon_text.xml \
   res/layout/notification_progress.xml \
   res/layout/notification_progress_text.xml \
+  res/layout/pin_bookmark_dialog.xml \
   res/layout/preference_rightalign_icon.xml \
   res/layout/preference_search_tip.xml \
   res/layout/search_engine_row.xml \
   res/layout/site_setting_item.xml \
   res/layout/site_setting_title.xml \
   res/layout/shared_ui_components.xml \
   res/layout/site_identity.xml \
   res/layout/suggestion_item.xml \
   res/layout/remote_tabs_child.xml \
   res/layout/remote_tabs_group.xml \
+  res/layout/search_engine_row.xml \
+  res/layout/tab_menu_strip.xml \
   res/layout/tabs_panel.xml \
   res/layout/tabs_counter.xml \
   res/layout/tabs_panel_header.xml \
   res/layout/tabs_panel_indicator.xml \
   res/layout/tabs_item_cell.xml \
   res/layout/tabs_item_row.xml \
   res/layout/text_selection_handles.xml \
+  res/layout/top_bookmark_item_view.xml \
+  res/layout/two_line_page_row.xml \
   res/layout/list_item_header.xml \
   res/layout/select_dialog_list.xml \
   res/layout/select_dialog_multichoice.xml \
   res/layout/select_dialog_singlechoice.xml \
   res/layout/simple_dropdown_item_1line.xml \
-  res/layout/abouthome_addon_row.xml \
-  res/layout/abouthome_last_tabs_row.xml \
-  res/layout/abouthome_section.xml \
-  res/layout/abouthome_remote_tab_row.xml \
-  res/layout/abouthome_topsite_item.xml \
+  res/layout/suggestion_item.xml \
   res/layout/validation_message.xml \
   res/layout/videoplayer.xml \
   $(NULL)
 
 RES_LAYOUT_LARGE_V11 = \
-  res/layout-large-v11/awesomebar_search.xml \
   res/layout-large-v11/browser_toolbar.xml \
+  res/layout-large-v11/home_pager.xml \
   $(NULL)
 
 RES_LAYOUT_LARGE_LAND_V11 = \
+  res/layout-large-land-v11/home_history_page.xml \
+  res/layout-large-land-v11/home_history_tabs_indicator.xml \
+  res/layout-large-land-v11/home_history_list.xml \
   res/layout-large-land-v11/tabs_panel.xml \
   res/layout-large-land-v11/tabs_panel_header.xml \
   res/layout-large-land-v11/tabs_panel_footer.xml \
   $(NULL)
 
 RES_LAYOUT_XLARGE_V11 = \
-  res/layout-xlarge-v11/awesomebar_search.xml \
   res/layout-xlarge-v11/font_size_preference.xml \
+  res/layout-xlarge-v11/home_history_page.xml \
+  res/layout-xlarge-v11/home_history_tabs_indicator.xml \
+  res/layout-xlarge-v11/home_history_list.xml \
   res/layout-xlarge-v11/remote_tabs_child.xml \
   res/layout-xlarge-v11/remote_tabs_group.xml \
   $(NULL)
 
-RES_LAYOUT_XLARGE_LAND_V11 = \
-  res/layout-xlarge-land-v11/abouthome_content.xml \
-  $(NULL)
-
 RES_VALUES = \
   $(SYNC_RES_VALUES) \
   res/values/attrs.xml \
   res/values/arrays.xml \
   res/values/colors.xml \
   res/values/dimens.xml \
   res/values/integers.xml \
   res/values/layout.xml \
@@ -555,29 +576,39 @@ RES_VALUES_LARGE_V11 = \
   $(SYNC_RES_VALUES_LARGE_V11) \
   res/values-large-v11/dimens.xml \
   res/values-large-v11/layout.xml \
   res/values-large-v11/styles.xml \
   res/values-large-v11/themes.xml \
   $(NULL)
 
 RES_VALUES_LARGE_LAND_V11 = \
+  res/values-large-land-v11/dimens.xml \
   res/values-large-land-v11/styles.xml \
   $(NULL)
 
 RES_VALUES_XLARGE_V11 = \
   res/values-xlarge-v11/dimens.xml \
   res/values-xlarge-v11/integers.xml \
   res/values-xlarge-v11/styles.xml \
   $(NULL)
 
+RES_VALUES_XLARGE_LAND_V11 = \
+  res/values-xlarge-land-v11/dimens.xml \
+  res/values-xlarge-land-v11/styles.xml \
+  $(NULL)
+
 RES_VALUES_V14 = \
   res/values-v14/styles.xml \
   $(NULL)
 
+RES_VALUES_V16 = \
+  res/values-v16/styles.xml \
+  $(NULL)
+
 RES_XML = \
   res/xml/preferences_display.xml \
   res/xml/preferences_search.xml \
   res/xml/preferences_privacy.xml \
   res/xml/preferences_vendor.xml \
   res/xml/preferences_devtools.xml \
   $(SYNC_RES_XML) \
   $(NULL)
@@ -585,98 +616,90 @@ RES_XML = \
 RES_XML_V11 = \
   res/xml-v11/preferences_customize.xml \
   res/xml-v11/preference_headers.xml \
   res/xml-v11/preferences_customize_tablet.xml \
   res/xml-v11/preferences.xml \
   $(NULL)
 
 RES_ANIM = \
-  res/anim/awesomebar_fade_in.xml \
   res/anim/popup_show.xml \
   res/anim/popup_hide.xml \
-  res/anim/awesomebar_fade_out.xml \
-  res/anim/awesomebar_hold_still.xml \
   res/anim/grow_fade_in.xml \
   res/anim/grow_fade_in_center.xml \
   res/anim/progress_spinner.xml \
   res/anim/shrink_fade_out.xml \
   $(NULL)
 
 RES_DRAWABLE_MDPI = \
   $(SYNC_RES_DRAWABLE_MDPI) \
   res/drawable-mdpi/blank.png \
   res/drawable-mdpi/favicon.png \
   res/drawable-mdpi/folder.png \
-  res/drawable-mdpi/abouthome_icon.png \
-  res/drawable-mdpi/abouthome_logo_dark.png \
-  res/drawable-mdpi/abouthome_logo_light.png \
-  res/drawable-mdpi/abouthome_promo_box_bg.9.png \
-  res/drawable-mdpi/abouthome_promo_box_pressed_bg.9.png \
-  res/drawable-mdpi/abouthome_promo_logo_apps.png \
-  res/drawable-mdpi/abouthome_promo_logo_sync.png \
   res/drawable-mdpi/abouthome_thumbnail.png \
-  res/drawable-mdpi/abouthome_thumbnail_bg.png \
-  res/drawable-mdpi/abouthome_thumbnail_add.png \
-  res/drawable-mdpi/address_bar_bg_shadow.png \
   res/drawable-mdpi/alert_addon.png \
   res/drawable-mdpi/alert_app.png \
   res/drawable-mdpi/alert_download.png \
   res/drawable-mdpi/alert_camera.png \
   res/drawable-mdpi/alert_mic.png \
   res/drawable-mdpi/alert_mic_camera.png \
   res/drawable-mdpi/arrow_popup_bg.9.png \
   res/drawable-mdpi/autocomplete_list_bg.9.png \
-  res/drawable-mdpi/awesomebar_tab_center.9.png \
-  res/drawable-mdpi/awesomebar_tab_left.9.png \
-  res/drawable-mdpi/awesomebar_tab_right.9.png \
-  res/drawable-mdpi/awesomebar_sep_left.9.png \
-  res/drawable-mdpi/awesomebar_sep_right.9.png \
+  res/drawable-mdpi/bookmark_folder_closed.png \
+  res/drawable-mdpi/bookmark_folder_opened.png \
   res/drawable-mdpi/desktop_notification.png \
-  res/drawable-mdpi/ic_addons_empty.png \
-  res/drawable-mdpi/ic_awesomebar_go.png \
-  res/drawable-mdpi/ic_awesomebar_reader.png \
-  res/drawable-mdpi/ic_awesomebar_search.png \
-  res/drawable-mdpi/ic_awesomebar_star.png \
-  res/drawable-mdpi/ic_awesomebar_tab.png \
+  res/drawable-mdpi/home_tab_menu_strip.9.png \
   res/drawable-mdpi/ic_menu_addons_filler.png \
   res/drawable-mdpi/ic_menu_bookmark_add.png \
   res/drawable-mdpi/ic_menu_bookmark_remove.png \
   res/drawable-mdpi/ic_menu_character_encoding.png \
   res/drawable-mdpi/ic_menu_close_all_tabs.png \
   res/drawable-mdpi/ic_menu_forward.png \
   res/drawable-mdpi/ic_menu_guest.png \
   res/drawable-mdpi/ic_menu_new_private_tab.png \
   res/drawable-mdpi/ic_menu_new_tab.png \
   res/drawable-mdpi/ic_menu_reload.png \
   res/drawable-mdpi/ic_status_logo.png \
+  res/drawable-mdpi/ic_url_bar_go.png \
+  res/drawable-mdpi/ic_url_bar_reader.png \
+  res/drawable-mdpi/ic_url_bar_search.png \
+  res/drawable-mdpi/ic_url_bar_star.png \
+  res/drawable-mdpi/ic_url_bar_tab.png \
+  res/drawable-mdpi/icon_last_tabs.png \
+  res/drawable-mdpi/icon_last_tabs_empty.png \
+  res/drawable-mdpi/icon_most_recent.png \
+  res/drawable-mdpi/icon_most_recent_empty.png \
+  res/drawable-mdpi/icon_most_visited.png \
+  res/drawable-mdpi/icon_most_visited_empty.png \
   res/drawable-mdpi/icon_pageaction.png \
+  res/drawable-mdpi/icon_reading_list_empty.png \
   res/drawable-mdpi/progress_spinner.png \
   res/drawable-mdpi/tab_indicator_divider.9.png \
   res/drawable-mdpi/tab_indicator_selected.9.png \
   res/drawable-mdpi/tab_indicator_selected_focused.9.png \
   res/drawable-mdpi/spinner_default.9.png \
   res/drawable-mdpi/spinner_focused.9.png \
   res/drawable-mdpi/spinner_pressed.9.png \
   res/drawable-mdpi/tab_new.png \
   res/drawable-mdpi/tab_new_pb.png \
   res/drawable-mdpi/tab_close.png \
   res/drawable-mdpi/tab_thumbnail_default.png \
   res/drawable-mdpi/tab_thumbnail_shadow.png \
   res/drawable-mdpi/tabs_count.png \
   res/drawable-mdpi/tabs_count_foreground.png \
+  res/drawable-mdpi/url_bar_bg_shadow.png \
+  res/drawable-mdpi/url_bar_entry_default.9.png \
+  res/drawable-mdpi/url_bar_entry_default_pb.9.png \
+  res/drawable-mdpi/url_bar_entry_pressed.9.png \
+  res/drawable-mdpi/url_bar_entry_pressed_pb.9.png \
   res/drawable-mdpi/tip_addsearch.png \
   res/drawable-mdpi/toast.9.png \
   res/drawable-mdpi/toast_button_focused.9.png \
   res/drawable-mdpi/toast_button_pressed.9.png \
   res/drawable-mdpi/toast_divider.9.png \
-  res/drawable-mdpi/address_bar_url_default.9.png \
-  res/drawable-mdpi/address_bar_url_default_pb.9.png \
-  res/drawable-mdpi/address_bar_url_pressed.9.png \
-  res/drawable-mdpi/address_bar_url_pressed_pb.9.png \
   res/drawable-mdpi/find_close.png \
   res/drawable-mdpi/find_next.png \
   res/drawable-mdpi/find_prev.png \
   res/drawable-mdpi/larry.png \
   res/drawable-mdpi/lock_identified.png \
   res/drawable-mdpi/lock_verified.png \
   res/drawable-mdpi/menu.png \
   res/drawable-mdpi/menu_pb.png \
@@ -687,106 +710,104 @@ RES_DRAWABLE_MDPI = \
   res/drawable-mdpi/menu_item_check.png \
   res/drawable-mdpi/menu_item_more.png \
   res/drawable-mdpi/menu_item_uncheck.png \
   res/drawable-mdpi/shield.png \
   res/drawable-mdpi/shield_doorhanger.png \
   res/drawable-mdpi/tabs_normal.png \
   res/drawable-mdpi/tabs_private.png \
   res/drawable-mdpi/tabs_synced.png \
+  res/drawable-mdpi/top_bookmark_add.png \
   res/drawable-mdpi/urlbar_stop.png \
   res/drawable-mdpi/reader.png \
+  res/drawable-mdpi/reader_cropped.png \
   res/drawable-mdpi/reader_active.png \
   res/drawable-mdpi/reading_list.png \
   res/drawable-mdpi/validation_arrow.png \
   res/drawable-mdpi/validation_arrow_inverted.png \
   res/drawable-mdpi/validation_bg.9.png \
   res/drawable-mdpi/bookmarkdefaults_favicon_support.png \
   res/drawable-mdpi/bookmarkdefaults_favicon_addons.png \
   res/drawable-mdpi/handle_end.png \
   res/drawable-mdpi/handle_middle.png \
   res/drawable-mdpi/handle_start.png \
   res/drawable-mdpi/scrollbar.png \
   res/drawable-mdpi/shadow.png \
   res/drawable-mdpi/start.png \
   res/drawable-mdpi/marketplace.png \
+  res/drawable-mdpi/history_tabs_indicator_selected.9.png \
   res/drawable-mdpi/warning.png \
   res/drawable-mdpi/warning_doorhanger.png \
   $(NULL)
 
 RES_DRAWABLE_LDPI = \
   $(SYNC_RES_DRAWABLE_LDPI) \
   $(NULL)
 
 RES_DRAWABLE_HDPI = \
   $(SYNC_RES_DRAWABLE_HDPI) \
   res/drawable-hdpi/blank.png \
   res/drawable-hdpi/favicon.png \
   res/drawable-hdpi/folder.png \
   res/drawable-hdpi/home_bg.png \
   res/drawable-hdpi/home_star.png \
-  res/drawable-hdpi/abouthome_icon.png \
-  res/drawable-hdpi/abouthome_logo_dark.png \
-  res/drawable-hdpi/abouthome_logo_light.png \
-  res/drawable-hdpi/abouthome_promo_box_bg.9.png \
-  res/drawable-hdpi/abouthome_promo_box_pressed_bg.9.png \
-  res/drawable-hdpi/abouthome_promo_logo_apps.png \
-  res/drawable-hdpi/abouthome_promo_logo_sync.png \
   res/drawable-hdpi/abouthome_thumbnail.png \
-  res/drawable-hdpi/abouthome_thumbnail_bg.png \
-  res/drawable-hdpi/abouthome_thumbnail_add.png \
-  res/drawable-hdpi/address_bar_bg_shadow.png \
   res/drawable-hdpi/alert_addon.png \
   res/drawable-hdpi/alert_app.png \
   res/drawable-hdpi/alert_download.png \
+  res/drawable-hdpi/bookmark_folder_closed.png \
+  res/drawable-hdpi/bookmark_folder_opened.png \
   res/drawable-hdpi/alert_camera.png \
   res/drawable-hdpi/alert_mic.png \
   res/drawable-hdpi/alert_mic_camera.png \
   res/drawable-hdpi/arrow_popup_bg.9.png \
-  res/drawable-hdpi/awesomebar_tab_center.9.png \
-  res/drawable-hdpi/awesomebar_tab_left.9.png \
-  res/drawable-hdpi/awesomebar_tab_right.9.png \
-  res/drawable-hdpi/awesomebar_sep_left.9.png \
-  res/drawable-hdpi/awesomebar_sep_right.9.png \
-  res/drawable-hdpi/ic_addons_empty.png \
-  res/drawable-hdpi/ic_awesomebar_go.png \
-  res/drawable-hdpi/ic_awesomebar_reader.png \
-  res/drawable-hdpi/ic_awesomebar_search.png \
-  res/drawable-hdpi/ic_awesomebar_star.png \
-  res/drawable-hdpi/ic_awesomebar_tab.png \
+  res/drawable-hdpi/home_tab_menu_strip.9.png \
   res/drawable-hdpi/ic_menu_addons_filler.png \
   res/drawable-hdpi/ic_menu_bookmark_add.png \
   res/drawable-hdpi/ic_menu_bookmark_remove.png \
   res/drawable-hdpi/ic_menu_character_encoding.png \
   res/drawable-hdpi/ic_menu_close_all_tabs.png \
   res/drawable-hdpi/ic_menu_forward.png \
   res/drawable-hdpi/ic_menu_guest.png \
   res/drawable-hdpi/ic_menu_new_private_tab.png \
   res/drawable-hdpi/ic_menu_new_tab.png \
   res/drawable-hdpi/ic_menu_reload.png \
   res/drawable-hdpi/ic_status_logo.png \
+  res/drawable-hdpi/ic_url_bar_go.png \
+  res/drawable-hdpi/ic_url_bar_reader.png \
+  res/drawable-hdpi/ic_url_bar_search.png \
+  res/drawable-hdpi/ic_url_bar_star.png \
+  res/drawable-hdpi/ic_url_bar_tab.png \
+  res/drawable-hdpi/icon_last_tabs.png \
+  res/drawable-hdpi/icon_last_tabs_empty.png \
+  res/drawable-hdpi/icon_most_recent.png \
+  res/drawable-hdpi/icon_most_recent_empty.png \
+  res/drawable-hdpi/icon_most_visited.png \
+  res/drawable-hdpi/icon_most_visited_empty.png \
   res/drawable-hdpi/icon_pageaction.png \
+  res/drawable-hdpi/icon_reading_list_empty.png \
   res/drawable-hdpi/tab_indicator_divider.9.png \
   res/drawable-hdpi/tab_indicator_selected.9.png \
   res/drawable-hdpi/tab_indicator_selected_focused.9.png \
   res/drawable-hdpi/spinner_default.9.png \
   res/drawable-hdpi/spinner_focused.9.png \
   res/drawable-hdpi/spinner_pressed.9.png \
   res/drawable-hdpi/tab_new.png \
   res/drawable-hdpi/tab_new_pb.png \
   res/drawable-hdpi/tab_close.png \
   res/drawable-hdpi/tab_thumbnail_default.png \
   res/drawable-hdpi/tab_thumbnail_shadow.png \
   res/drawable-hdpi/tabs_count.png \
   res/drawable-hdpi/tabs_count_foreground.png \
+  res/drawable-hdpi/url_bar_bg_shadow.png \
+  res/drawable-hdpi/url_bar_entry_default.9.png \
+  res/drawable-hdpi/url_bar_entry_default_pb.9.png \
+  res/drawable-hdpi/url_bar_entry_pressed.9.png \
+  res/drawable-hdpi/url_bar_entry_pressed_pb.9.png \
   res/drawable-hdpi/tip_addsearch.png \
-  res/drawable-hdpi/address_bar_url_default.9.png \
-  res/drawable-hdpi/address_bar_url_default_pb.9.png \
-  res/drawable-hdpi/address_bar_url_pressed.9.png \
-  res/drawable-hdpi/address_bar_url_pressed_pb.9.png \
   res/drawable-hdpi/find_close.png \
   res/drawable-hdpi/find_next.png \
   res/drawable-hdpi/find_prev.png \
   res/drawable-hdpi/larry.png \
   res/drawable-hdpi/lock_identified.png \
   res/drawable-hdpi/lock_verified.png \
   res/drawable-hdpi/menu.png \
   res/drawable-hdpi/menu_pb.png \
@@ -797,95 +818,95 @@ RES_DRAWABLE_HDPI = \
   res/drawable-hdpi/menu_item_check.png \
   res/drawable-hdpi/menu_item_more.png \
   res/drawable-hdpi/menu_item_uncheck.png \
   res/drawable-hdpi/shield.png \
   res/drawable-hdpi/shield_doorhanger.png \
   res/drawable-hdpi/tabs_normal.png \
   res/drawable-hdpi/tabs_private.png \
   res/drawable-hdpi/tabs_synced.png \
+  res/drawable-hdpi/top_bookmark_add.png \
   res/drawable-hdpi/urlbar_stop.png \
   res/drawable-hdpi/reader.png \
+  res/drawable-hdpi/reader_cropped.png \
   res/drawable-hdpi/reader_active.png \
   res/drawable-hdpi/reading_list.png \
   res/drawable-hdpi/validation_arrow.png \
   res/drawable-hdpi/validation_arrow_inverted.png \
   res/drawable-hdpi/validation_bg.9.png \
   res/drawable-hdpi/handle_end.png \
   res/drawable-hdpi/handle_middle.png \
   res/drawable-hdpi/handle_start.png \
+  res/drawable-hdpi/history_tabs_indicator_selected.9.png \
   res/drawable-hdpi/warning.png \
   res/drawable-hdpi/warning_doorhanger.png \
   $(NULL)
 
 RES_DRAWABLE_XHDPI = \
   res/drawable-xhdpi/blank.png \
   res/drawable-xhdpi/favicon.png \
   res/drawable-xhdpi/folder.png \
-  res/drawable-xhdpi/abouthome_icon.png \
-  res/drawable-xhdpi/abouthome_logo_dark.png \
-  res/drawable-xhdpi/abouthome_logo_light.png \
-  res/drawable-xhdpi/abouthome_promo_box_bg.9.png \
-  res/drawable-xhdpi/abouthome_promo_box_pressed_bg.9.png \
-  res/drawable-xhdpi/abouthome_promo_logo_apps.png \
-  res/drawable-xhdpi/abouthome_promo_logo_sync.png \
   res/drawable-xhdpi/abouthome_thumbnail.png \
-  res/drawable-xhdpi/abouthome_thumbnail_bg.png \
-  res/drawable-xhdpi/abouthome_thumbnail_add.png \
-  res/drawable-xhdpi/address_bar_bg_shadow.png \
-  res/drawable-xhdpi/address_bar_url_default.9.png \
-  res/drawable-xhdpi/address_bar_url_default_pb.9.png \
-  res/drawable-xhdpi/address_bar_url_pressed.9.png \
-  res/drawable-xhdpi/address_bar_url_pressed_pb.9.png \
+  res/drawable-xhdpi/url_bar_bg_shadow.png \
+  res/drawable-xhdpi/url_bar_entry_default.9.png \
+  res/drawable-xhdpi/url_bar_entry_default_pb.9.png \
+  res/drawable-xhdpi/url_bar_entry_pressed.9.png \
+  res/drawable-xhdpi/url_bar_entry_pressed_pb.9.png \
   res/drawable-xhdpi/alert_addon.png \
   res/drawable-xhdpi/alert_app.png \
   res/drawable-xhdpi/alert_download.png \
+  res/drawable-xhdpi/bookmark_folder_closed.png \
+  res/drawable-xhdpi/bookmark_folder_opened.png \
   res/drawable-xhdpi/alert_camera.png \
   res/drawable-xhdpi/alert_mic.png \
   res/drawable-xhdpi/alert_mic_camera.png \
   res/drawable-xhdpi/arrow_popup_bg.9.png \
-  res/drawable-xhdpi/awesomebar_tab_center.9.png \
-  res/drawable-xhdpi/awesomebar_tab_left.9.png \
-  res/drawable-xhdpi/awesomebar_tab_right.9.png \
-  res/drawable-xhdpi/awesomebar_sep_left.9.png \
-  res/drawable-xhdpi/awesomebar_sep_right.9.png \
-  res/drawable-xhdpi/ic_addons_empty.png \
-  res/drawable-xhdpi/ic_awesomebar_go.png \
-  res/drawable-xhdpi/ic_awesomebar_reader.png \
-  res/drawable-xhdpi/ic_awesomebar_search.png \
-  res/drawable-xhdpi/ic_awesomebar_star.png \
-  res/drawable-xhdpi/ic_awesomebar_tab.png \
+  res/drawable-xhdpi/home_tab_menu_strip.9.png \
   res/drawable-xhdpi/ic_menu_addons_filler.png \
   res/drawable-xhdpi/ic_menu_bookmark_add.png \
   res/drawable-xhdpi/ic_menu_bookmark_remove.png \
   res/drawable-xhdpi/ic_menu_close_all_tabs.png \
   res/drawable-xhdpi/ic_menu_character_encoding.png \
   res/drawable-xhdpi/ic_menu_forward.png \
   res/drawable-xhdpi/ic_menu_guest.png \
   res/drawable-xhdpi/ic_menu_new_private_tab.png \
   res/drawable-xhdpi/ic_menu_new_tab.png \
   res/drawable-xhdpi/ic_menu_reload.png \
   res/drawable-xhdpi/ic_status_logo.png \
+  res/drawable-xhdpi/ic_url_bar_go.png \
+  res/drawable-xhdpi/ic_url_bar_reader.png \
+  res/drawable-xhdpi/ic_url_bar_search.png \
+  res/drawable-xhdpi/ic_url_bar_star.png \
+  res/drawable-xhdpi/ic_url_bar_tab.png \
+  res/drawable-xhdpi/icon_last_tabs.png \
+  res/drawable-xhdpi/icon_last_tabs_empty.png \
+  res/drawable-xhdpi/icon_most_recent.png \
+  res/drawable-xhdpi/icon_most_recent_empty.png \
+  res/drawable-xhdpi/icon_most_visited.png \
+  res/drawable-xhdpi/icon_most_visited_empty.png \
   res/drawable-xhdpi/icon_pageaction.png \
+  res/drawable-xhdpi/icon_reading_list_empty.png \
   res/drawable-xhdpi/spinner_default.9.png \
   res/drawable-xhdpi/spinner_focused.9.png \
   res/drawable-xhdpi/spinner_pressed.9.png \
   res/drawable-xhdpi/tab_new.png \
   res/drawable-xhdpi/tab_new_pb.png \
   res/drawable-xhdpi/tab_close.png \
   res/drawable-xhdpi/tab_thumbnail_default.png \
   res/drawable-xhdpi/tab_thumbnail_shadow.png \
   res/drawable-xhdpi/tabs_count.png \
   res/drawable-xhdpi/tabs_count_foreground.png \
   res/drawable-xhdpi/tip_addsearch.png \
   res/drawable-xhdpi/find_close.png \
   res/drawable-xhdpi/find_next.png \
   res/drawable-xhdpi/find_prev.png \
+  res/drawable-xhdpi/top_bookmark_add.png \
   res/drawable-xhdpi/urlbar_stop.png \
   res/drawable-xhdpi/reader.png \
+  res/drawable-xhdpi/reader_cropped.png \
   res/drawable-xhdpi/reader_active.png \
   res/drawable-xhdpi/reading_list.png \
   res/drawable-xhdpi/larry.png \
   res/drawable-xhdpi/lock_identified.png \
   res/drawable-xhdpi/lock_verified.png \
   res/drawable-xhdpi/menu.png \
   res/drawable-xhdpi/menu_pb.png \
   res/drawable-xhdpi/menu_panel_bg.9.png \
@@ -904,16 +925,17 @@ RES_DRAWABLE_XHDPI = \
   res/drawable-xhdpi/tabs_private.png \
   res/drawable-xhdpi/tabs_synced.png \
   res/drawable-xhdpi/validation_arrow.png \
   res/drawable-xhdpi/validation_arrow_inverted.png \
   res/drawable-xhdpi/validation_bg.9.png \
   res/drawable-xhdpi/handle_end.png \
   res/drawable-xhdpi/handle_middle.png \
   res/drawable-xhdpi/handle_start.png \
+  res/drawable-xhdpi/history_tabs_indicator_selected.9.png \
   res/drawable-xhdpi/warning.png \
   res/drawable-xhdpi/warning_doorhanger.png \
   $(NULL)
 
 RES_DRAWABLE_MDPI_V11 = \
   res/drawable-mdpi-v11/alert_addon.png \
   res/drawable-mdpi-v11/alert_app.png \
   res/drawable-mdpi-v11/alert_download.png \
@@ -995,16 +1017,20 @@ RES_DRAWABLE_XHDPI_V11 = \
   res/drawable-xhdpi-v11/ic_menu_save_as_pdf.png \
   res/drawable-xhdpi-v11/ic_menu_settings.png \
   res/drawable-xhdpi-v11/ic_menu_share.png \
   res/drawable-xhdpi-v11/ic_menu_tools.png \
   res/drawable-xhdpi-v11/ic_menu_quit.png \
   res/drawable-xhdpi-v11/ic_status_logo.png \
   $(NULL)
 
+RES_DRAWABLE_LARGE_LAND_V11 = \
+  res/drawable-large-land-v11/home_history_tabs_indicator.xml \
+  $(NULL)
+
 RES_DRAWABLE_LARGE_MDPI_V11 = \
   res/drawable-large-mdpi-v11/arrow_popup_bg.9.png \
   res/drawable-large-mdpi-v11/ic_menu_reload.png \
   res/drawable-large-mdpi-v11/ic_menu_forward.png \
   res/drawable-large-mdpi-v11/menu.png \
   $(NULL)
 
 RES_DRAWABLE_LARGE_HDPI_V11 = \
@@ -1016,100 +1042,85 @@ RES_DRAWABLE_LARGE_HDPI_V11 = \
 
 RES_DRAWABLE_LARGE_XHDPI_V11 = \
   res/drawable-large-xhdpi-v11/arrow_popup_bg.9.png \
   res/drawable-large-xhdpi-v11/ic_menu_reload.png \
   res/drawable-large-xhdpi-v11/ic_menu_forward.png \
   res/drawable-large-xhdpi-v11/menu.png \
   $(NULL)
 
+RES_DRAWABLE_XLARGE_V11 = \
+  res/drawable-xlarge-v11/home_history_tabs_indicator.xml \
+  $(NULL)
+
 RES_DRAWABLE_XLARGE_MDPI_V11 = \
-  res/drawable-xlarge-mdpi-v11/awesomebar_tab_center.9.png \
-  res/drawable-xlarge-mdpi-v11/awesomebar_tab_left.9.png \
-  res/drawable-xlarge-mdpi-v11/awesomebar_tab_right.9.png \
-  res/drawable-xlarge-mdpi-v11/awesomebar_sep_left.9.png \
-  res/drawable-xlarge-mdpi-v11/awesomebar_sep_right.9.png \
   res/drawable-xlarge-mdpi-v11/ic_menu_bookmark_add.png \
   res/drawable-xlarge-mdpi-v11/ic_menu_bookmark_remove.png \
   $(NULL)
 
 RES_DRAWABLE_XLARGE_HDPI_V11 = \
-  res/drawable-xlarge-hdpi-v11/awesomebar_tab_center.9.png \
-  res/drawable-xlarge-hdpi-v11/awesomebar_tab_left.9.png \
-  res/drawable-xlarge-hdpi-v11/awesomebar_tab_right.9.png \
-  res/drawable-xlarge-hdpi-v11/awesomebar_sep_left.9.png \
-  res/drawable-xlarge-hdpi-v11/awesomebar_sep_right.9.png \
   res/drawable-xlarge-hdpi-v11/ic_menu_bookmark_add.png \
   res/drawable-xlarge-hdpi-v11/ic_menu_bookmark_remove.png \
   $(NULL)
 
 RES_DRAWABLE_XLARGE_XHDPI_V11 = \
-  res/drawable-xlarge-xhdpi-v11/awesomebar_tab_center.9.png \
-  res/drawable-xlarge-xhdpi-v11/awesomebar_tab_left.9.png \
-  res/drawable-xlarge-xhdpi-v11/awesomebar_tab_right.9.png \
-  res/drawable-xlarge-xhdpi-v11/awesomebar_sep_left.9.png \
-  res/drawable-xlarge-xhdpi-v11/awesomebar_sep_right.9.png \
   res/drawable-xlarge-xhdpi-v11/ic_menu_bookmark_add.png \
   res/drawable-xlarge-xhdpi-v11/ic_menu_bookmark_remove.png \
   $(NULL)
 
 RES_COLOR = \
-  res/color/abouthome_section_more_text.xml \
-  res/color/abouthome_section_subtitle.xml \
-  res/color/abouthome_section_title.xml \
-  res/color/awesome_bar_title.xml \
-  res/color/awesome_bar_title_hint.xml \
   res/color/primary_text.xml \
   res/color/primary_text_inverse.xml \
   res/color/secondary_text.xml \
   res/color/secondary_text_inverse.xml \
   res/color/select_item_multichoice.xml \
   res/color/tertiary_text.xml \
   res/color/tertiary_text_inverse.xml \
+  res/color/top_bookmark_item_title.xml \
+  res/color/url_bar_title.xml \
+  res/color/url_bar_title_hint.xml \
   $(NULL)
 
 RES_MENU = \
-  res/menu/abouthome_topsites_contextmenu.xml \
-  res/menu/awesomebar_contextmenu.xml \
   res/menu/browser_app_menu.xml \
   res/menu/gecko_app_menu.xml \
+  res/menu/home_contextmenu.xml \
   res/menu/titlebar_contextmenu.xml \
+  res/menu/top_bookmarks_contextmenu.xml \
   res/menu-large-v11/browser_app_menu.xml \
   res/menu-v11/browser_app_menu.xml \
   res/menu-xlarge-v11/browser_app_menu.xml \
   $(NULL)
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
 
 ifdef MOZ_CRASHREPORTER
 FENNEC_JAVA_FILES += CrashReporter.java
 RES_DRAWABLE_MDPI += res/drawable-mdpi/crash_reporter.png
 RES_LAYOUT += res/layout/crash_reporter.xml
 endif
 
 RES_DRAWABLE += \
-  $(SYNC_RES_DRAWABLE)                                                          \
-  res/drawable/abouthome_logo.xml                     \
-  res/drawable/abouthome_promo_box.xml                \
+  $(SYNC_RES_DRAWABLE)                                \
   res/drawable/action_bar_button.xml                  \
   res/drawable/action_bar_button_inverse.xml          \
-  res/drawable/address_bar_bg.xml                     \
-  res/drawable/address_bar_bg_shadow_repeat.xml       \
-  res/drawable/address_bar_nav_button.xml             \
-  res/drawable/address_bar_right_edge.xml             \
-  res/drawable/address_bar_url.xml                    \
-  res/drawable/awesomebar_listview_divider.xml        \
-  res/drawable/awesomebar_header_row.xml              \
-  res/drawable/awesomebar_tab_indicator.xml           \
-  res/drawable/awesomebar_tab_selected.xml            \
-  res/drawable/awesomebar_tab_unselected.xml          \
+  res/drawable/bookmark_thumbnail_bg.xml              \
+  res/drawable/url_bar_bg.xml                         \
+  res/drawable/url_bar_bg_shadow_repeat.xml           \
+  res/drawable/url_bar_entry.xml                      \
+  res/drawable/url_bar_nav_button.xml                 \
+  res/drawable/url_bar_right_edge.xml                 \
+  res/drawable/bookmark_folder.xml                    \
+  res/drawable/divider_horizontal.xml                 \
   res/drawable/divider_vertical.xml                   \
   res/drawable/favicon_bg.xml                         \
   res/drawable/handle_end_level.xml                   \
   res/drawable/handle_start_level.xml                 \
+  res/drawable/home_history_tabs_indicator.xml        \
+  res/drawable/home_page_title_background.xml         \
   res/drawable/ic_menu_back.xml                       \
   res/drawable/ic_menu_desktop_mode_off.xml           \
   res/drawable/ic_menu_desktop_mode_on.xml            \
   res/drawable/ic_menu_quit.xml                       \
   res/drawable/menu_item_state.xml                    \
   res/drawable/menu_level.xml                         \
   res/drawable/remote_tabs_child_divider.xml          \
   res/drawable/shaped_button.xml                      \
@@ -1126,70 +1137,77 @@ RES_DRAWABLE += \
   $(NULL)
 
 RESOURCES = \
   $(RES_ANIM) \
   $(RES_COLOR) \
   $(RES_DRAWABLE) \
   $(RES_DRAWABLE_HDPI) \
   $(RES_DRAWABLE_HDPI_V11) \
+  $(RES_DRAWABLE_LARGE_LAND_V11) \
   $(RES_DRAWABLE_LARGE_HDPI_V11) \
   $(RES_DRAWABLE_LARGE_MDPI_V11) \
   $(RES_DRAWABLE_LARGE_XHDPI_V11) \
   $(RES_DRAWABLE_LDPI) \
   $(RES_DRAWABLE_MDPI) \
   $(RES_DRAWABLE_MDPI_V11) \
   $(RES_DRAWABLE_XHDPI) \
   $(RES_DRAWABLE_XHDPI_V11) \
+  $(RES_DRAWABLE_XLARGE_V11) \
   $(RES_DRAWABLE_XLARGE_HDPI_V11) \
   $(RES_DRAWABLE_XLARGE_MDPI_V11) \
   $(RES_DRAWABLE_XLARGE_XHDPI_V11) \
   $(RES_LAYOUT) \
   $(RES_LAYOUT_LARGE_LAND_V11) \
   $(RES_LAYOUT_LARGE_V11) \
   $(RES_LAYOUT_XLARGE_LAND_V11) \
   $(RES_LAYOUT_XLARGE_V11) \
   $(RES_MENU) \
   $(RES_VALUES) \
   $(RES_VALUES_LAND) \
   $(RES_VALUES_LAND_V14) \
   $(RES_VALUES_LARGE_LAND_V11) \
   $(RES_VALUES_LARGE_V11) \
   $(RES_VALUES_V11) \
   $(RES_VALUES_V14) \
+  $(RES_VALUES_V16) \
+  $(RES_VALUES_XLARGE_LAND_V11) \
   $(RES_VALUES_XLARGE_V11) \
   $(RES_XML) \
   $(RES_XML_V11) \
   $(NULL)
 
 RES_DIRS= \
   res/layout                    \
   res/layout-large-v11          \
   res/layout-large-land-v11     \
   res/layout-xlarge-v11         \
-  res/layout-xlarge-land-v11    \
   res/values                    \
   res/values-v11                \
   res/values-large-v11          \
+  res/values-xlarge-land-v11    \
   res/values-xlarge-v11         \
-  res/values-land-v14           \
+  res/values-v14                \
+  res/values-v16                \
   res/xml                       \
   res/xml-v11                   \
   res/anim                      \
   res/drawable-ldpi             \
   res/drawable-mdpi             \
   res/drawable-hdpi             \
   res/drawable-xhdpi            \
   res/drawable                  \
   res/drawable-mdpi-v11         \
   res/drawable-hdpi-v11         \
   res/drawable-xhdpi-v11        \
+  res/drawable-large-land-v11   \
   res/drawable-large-mdpi-v11   \
   res/drawable-large-hdpi-v11   \
   res/drawable-large-xhdpi-v11  \
+  res/drawable-xlarge-v11       \
   res/drawable-xlarge-mdpi-v11  \
   res/drawable-xlarge-hdpi-v11  \
   res/drawable-xlarge-xhdpi-v11 \
   res/color                     \
   res/menu                      \
   res/menu-v11                  \
   res/menu-large-v11            \
   res/menu-xlarge-v11           \
--- a/mobile/android/base/PageActionLayout.java
+++ b/mobile/android/base/PageActionLayout.java
@@ -141,17 +141,17 @@ public class PageActionLayout extends Li
                 mPageActionList.remove(i);
                 refreshPageActionIcons();
                 return;
             }
         }
     }
 
     private ImageButton createImageButton() {
-        ImageButton imageButton = new ImageButton(mContext, null, R.style.AddressBar_ImageButton_Icon);
+        ImageButton imageButton = new ImageButton(mContext, null, R.style.UrlBar_ImageButton_Icon);
         imageButton.setLayoutParams(new LayoutParams(mContext.getResources().getDimensionPixelSize(R.dimen.page_action_button_width), LayoutParams.MATCH_PARENT));
         imageButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
         imageButton.setOnClickListener(this);
         imageButton.setOnLongClickListener(this);
         return imageButton;
     }
 
     @Override
deleted file mode 100644
--- a/mobile/android/base/SearchEngineRow.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.AwesomeBarTabs.OnUrlOpenListener;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.StringUtils;
-import org.mozilla.gecko.widget.FaviconView;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
-import android.view.animation.AlphaAnimation;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-class SearchEngineRow extends AnimatedHeightLayout {
-    // Duration for fade-in animation
-    private static final int ANIMATION_DURATION = 250;
-
-    // Inner views
-    private final FlowLayout mSuggestionView;
-    private final FaviconView mIconView;
-    private final LinearLayout mUserEnteredView;
-    private final TextView mUserEnteredTextView;
-
-    // Inflater used when updating from suggestions
-    private final LayoutInflater mInflater;
-
-    // Search engine associated with this view
-    private SearchEngine mSearchEngine;
-
-    // Selected suggestion view
-    private int mSelectedView = 0;
-
-    // Event listeners for suggestion views
-    private final OnClickListener mClickListener;
-    private final OnLongClickListener mLongClickListener;
-
-    // On URL open listener
-    private OnUrlOpenListener mUrlOpenListener;
-
-    public SearchEngineRow(Context context) {
-        this(context, null);
-    }
-
-    public SearchEngineRow(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SearchEngineRow(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        mClickListener = new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                final String suggestion = getSuggestionTextFromView(v);
-
-                // If we're not clicking the user-entered view (the first suggestion item)
-                // and the search matches a URL pattern, go to that URL. Otherwise, do a
-                // search for the term.
-                if (mUrlOpenListener != null) {
-                    if (v != mUserEnteredView && !StringUtils.isSearchQuery(suggestion, false)) {
-                        mUrlOpenListener.onUrlOpen(suggestion, null);
-                    } else {
-                        mUrlOpenListener.onSearch(mSearchEngine, suggestion);
-                    }
-                }
-            }
-        };
-
-        mLongClickListener = new OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                if (mUrlOpenListener != null) {
-                    final String suggestion = getSuggestionTextFromView(v);
-                    mUrlOpenListener.onEditSuggestion(suggestion);
-                    return true;
-                }
-
-                return false;
-            }
-        };
-
-        mInflater = LayoutInflater.from(context);
-        mInflater.inflate(R.layout.search_engine_row, this);
-
-        mSuggestionView = (FlowLayout) findViewById(R.id.suggestion_layout);
-        mIconView = (FaviconView) findViewById(R.id.suggestion_icon);
-
-        // User-entered search term is first suggestion
-        mUserEnteredView = (LinearLayout) findViewById(R.id.suggestion_user_entered);
-        mUserEnteredView.setOnClickListener(mClickListener);
-
-        mUserEnteredTextView = (TextView) findViewById(R.id.suggestion_text);
-    }
-
-    private String getSuggestionTextFromView(View v) {
-        final TextView suggestionText = (TextView) v.findViewById(R.id.suggestion_text);
-        return suggestionText.getText().toString();
-    }
-
-    private void setSuggestionOnView(View v, String suggestion) {
-        final TextView suggestionText = (TextView) v.findViewById(R.id.suggestion_text);
-        suggestionText.setText(suggestion);
-    }
-
-    public void setSearchTerm(String searchTerm) {
-        mUserEnteredTextView.setText(searchTerm);
-    }
-
-    public void setOnUrlOpenListener(OnUrlOpenListener listener) {
-        mUrlOpenListener = listener;
-    }
-
-    public void updateFromSearchEngine(SearchEngine searchEngine, boolean doAnimation) {
-        // Update search engine reference
-        mSearchEngine = searchEngine;
-
-        // Set the search engine icon (e.g., Google) for the row
-        mIconView.updateImage(mSearchEngine.icon, mSearchEngine.name);
-
-        // Add additional suggestions given by this engine
-        final int recycledSuggestionCount = mSuggestionView.getChildCount();
-        final int suggestionCount = mSearchEngine.suggestions.size();
-
-        for (int i = 0; i < suggestionCount; i++) {
-            final View suggestionItem;
-
-            // Reuse suggestion views from recycled view, if possible
-            if (i + 1 < recycledSuggestionCount) {
-                suggestionItem = mSuggestionView.getChildAt(i + 1);
-                suggestionItem.setVisibility(View.VISIBLE);
-            } else {
-                suggestionItem = mInflater.inflate(R.layout.suggestion_item, null);
-
-                suggestionItem.setOnClickListener(mClickListener);
-                suggestionItem.setOnLongClickListener(mLongClickListener);
-
-                final ImageView magnifier =
-                        (ImageView) suggestionItem.findViewById(R.id.suggestion_magnifier);
-                magnifier.setVisibility(View.GONE);
-
-                mSuggestionView.addView(suggestionItem);
-            }
-
-            final String suggestion = mSearchEngine.suggestions.get(i);
-            setSuggestionOnView(suggestionItem, suggestion);
-
-            if (doAnimation) {
-                AlphaAnimation anim = new AlphaAnimation(0, 1);
-                anim.setDuration(ANIMATION_DURATION);
-                anim.setStartOffset(i * ANIMATION_DURATION);
-                suggestionItem.startAnimation(anim);
-            }
-        }
-
-        // Hide extra suggestions that have been recycled
-        for (int i = suggestionCount + 1; i < recycledSuggestionCount; i++) {
-            mSuggestionView.getChildAt(i).setVisibility(View.GONE);
-        }
-
-        // Make sure mSelectedView is still valid
-        if (mSelectedView >= mSuggestionView.getChildCount()) {
-            mSelectedView = mSuggestionView.getChildCount() - 1;
-        }
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
-        final View suggestion = mSuggestionView.getChildAt(mSelectedView);
-
-        if (event.getAction() != android.view.KeyEvent.ACTION_DOWN) {
-            return false;
-        }
-
-        switch (event.getKeyCode()) {
-        case KeyEvent.KEYCODE_DPAD_RIGHT:
-            final View nextSuggestion = mSuggestionView.getChildAt(mSelectedView + 1);
-            if (nextSuggestion != null) {
-                changeSelectedSuggestion(suggestion, nextSuggestion);
-                mSelectedView++;
-                return true;
-            }
-            break;
-
-        case KeyEvent.KEYCODE_DPAD_LEFT:
-            final View prevSuggestion = mSuggestionView.getChildAt(mSelectedView - 1);
-            if (prevSuggestion != null) {
-                changeSelectedSuggestion(suggestion, prevSuggestion);
-                mSelectedView--;
-                return true;
-            }
-            break;
-
-        case KeyEvent.KEYCODE_BUTTON_A:
-            // TODO: handle long pressing for editing suggestions
-            return suggestion.performClick();
-        }
-
-        return false;
-    }
-
-    private void changeSelectedSuggestion(View oldSuggestion, View newSuggestion) {
-        oldSuggestion.setDuplicateParentStateEnabled(false);
-        newSuggestion.setDuplicateParentStateEnabled(true);
-        oldSuggestion.refreshDrawableState();
-        newSuggestion.refreshDrawableState();
-    }
-
-    public void onSelected() {
-        mSelectedView = 0;
-        mUserEnteredView.setDuplicateParentStateEnabled(true);
-        mUserEnteredView.refreshDrawableState();
-    }
-
-    public void onDeselected() {
-        final View suggestion = mSuggestionView.getChildAt(mSelectedView);
-        suggestion.setDuplicateParentStateEnabled(false);
-        suggestion.refreshDrawableState();
-    }
-}
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.gfx.Layer;
+import org.mozilla.gecko.home.HomePager;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.ContentResolver;
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -44,16 +45,17 @@ public class Tab {
     private int mFaviconSize;
     private boolean mFeedsEnabled;
     private JSONObject mIdentityData;
     private boolean mReaderEnabled;
     private BitmapDrawable mThumbnail;
     private int mHistoryIndex;
     private int mHistorySize;
     private int mParentId;
+    private HomePager.Page mAboutHomePage;
     private boolean mExternal;
     private boolean mBookmark;
     private boolean mReadingListItem;
     private long mFaviconLoadId;
     private String mContentType;
     private boolean mHasTouchListeners;
     private ZoomConstraints mZoomConstraints;
     private boolean mIsRTL;
@@ -68,32 +70,35 @@ public class Tab {
     private ErrorType mErrorType = ErrorType.NONE;
     private static final int MAX_HISTORY_LIST_SIZE = 50;
 
     public static final int STATE_DELAYED = 0;
     public static final int STATE_LOADING = 1;
     public static final int STATE_SUCCESS = 2;
     public static final int STATE_ERROR = 3;
 
+    private static final int DEFAULT_BACKGROUND_COLOR = Color.WHITE;
+
     public enum ErrorType {
         CERT_ERROR,  // Pages with certificate problems
         BLOCKED,     // Pages blocked for phishing or malware warnings
-        NET_ERROR,       // All other types of error
+        NET_ERROR,   // All other types of error
         NONE         // Non error pages
     }
 
     public Tab(Context context, int id, String url, boolean external, int parentId, String title) {
         mAppContext = context.getApplicationContext();
         mId = id;
         mLastUsed = 0;
         mUrl = url;
         mBaseDomain = "";
         mUserSearch = "";
         mExternal = external;
         mParentId = parentId;
+        mAboutHomePage = HomePager.Page.BOOKMARKS;
         mTitle = title == null ? "" : title;
         mFavicon = null;
         mFaviconUrl = null;
         mFaviconSize = 0;
         mFeedsEnabled = false;
         mIdentityData = null;
         mReaderEnabled = false;
         mEnteringReaderMode = false;
@@ -107,17 +112,17 @@ public class Tab {
         mZoomConstraints = new ZoomConstraints(false);
         mPluginViews = new ArrayList<View>();
         mPluginLayers = new HashMap<Object, Layer>();
         mState = shouldShowProgress(url) ? STATE_SUCCESS : STATE_LOADING;
 
         // At startup, the background is set to a color specified by LayerView
         // when the LayerView is created. Shortly after, this background color
         // will be used before the tab's content is shown.
-        mBackgroundColor = getBackgroundColorForUrl(url);
+        mBackgroundColor = DEFAULT_BACKGROUND_COLOR;
     }
 
     private ContentResolver getContentResolver() {
         return mAppContext.getContentResolver();
     }
 
     public void onDestroy() {
         Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.CLOSED);
@@ -134,16 +139,25 @@ public class Tab {
     public synchronized long getLastUsed() {
         return mLastUsed;
     }
 
     public int getParentId() {
         return mParentId;
     }
 
+    public HomePager.Page getAboutHomePage() {
+        return mAboutHomePage;
+    }
+
+    private void setAboutHomePage(HomePager.Page page) {
+        mAboutHomePage = page;
+    }
+
+
     // may be null if user-entered query hasn't yet been resolved to a URI
     public synchronized String getURL() {
         return mUrl;
     }
 
     // mUserSearch should never be null, but it may be an empty string
     public synchronized String getUserSearch() {
         return mUserSearch;
@@ -602,33 +616,31 @@ public class Tab {
         setContentType(message.getString("contentType"));
         clearFavicon();
         setFeedsEnabled(false);
         updateTitle(null);
         updateIdentityData(null);
         setReaderEnabled(false);
         setZoomConstraints(new ZoomConstraints(true));
         setHasTouchListeners(false);
-        setBackgroundColor(getBackgroundColorForUrl(uri));
+        setBackgroundColor(DEFAULT_BACKGROUND_COLOR);
         setErrorType(ErrorType.NONE);
 
+        final String homePage = message.getString("aboutHomePage");
+        if (!TextUtils.isEmpty(homePage)) {
+            setAboutHomePage(HomePager.Page.valueOf(homePage));
+        }
+
         Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.LOCATION_CHANGE, uri);
     }
 
     private boolean shouldShowProgress(String url) {
         return "about:home".equals(url) || ReaderModeUtils.isAboutReader(url);
     }
 
-    private int getBackgroundColorForUrl(String url) {
-        if ("about:home".equals(url)) {
-            return mAppContext.getResources().getColor(R.color.background_normal);
-        }
-        return Color.WHITE;
-    }
-
     void handleDocumentStart(boolean showProgress, String url) {
         setState(shouldShowProgress(url) ? STATE_SUCCESS : STATE_LOADING);
         updateIdentityData(null);
         setReaderEnabled(false);
     }
 
     void handleDocumentStop(boolean success) {
         setState(success ? STATE_SUCCESS : STATE_ERROR);
--- a/mobile/android/base/Tabs.java
+++ b/mobile/android/base/Tabs.java
@@ -1,32 +1,35 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.db.BrowserDB;
+import org.mozilla.gecko.home.HomePager;
+import org.mozilla.gecko.ReaderModeUtils;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import org.json.JSONObject;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.OnAccountsUpdateListener;
 import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
 import android.graphics.Color;
 import android.net.Uri;
 import android.os.Handler;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -52,16 +55,17 @@ public class Tabs implements GeckoEventL
     public static final int LOADURL_NEW_TAB      = 1 << 0;
     public static final int LOADURL_USER_ENTERED = 1 << 1;
     public static final int LOADURL_PRIVATE      = 1 << 2;
     public static final int LOADURL_PINNED       = 1 << 3;
     public static final int LOADURL_DELAY_LOAD   = 1 << 4;
     public static final int LOADURL_DESKTOP      = 1 << 5;
     public static final int LOADURL_BACKGROUND   = 1 << 6;
     public static final int LOADURL_EXTERNAL     = 1 << 7;
+    public static final int LOADURL_READING_LIST = 1 << 8;
 
     private static final long PERSIST_TABS_AFTER_MILLISECONDS = 1000 * 5;
 
     private static AtomicInteger sTabId = new AtomicInteger(0);
     private volatile boolean mInitialTabsAdded;
 
     private Context mAppContext;
     private ContentObserver mContentObserver;
@@ -577,16 +581,32 @@ public class Tabs implements GeckoEventL
         backgroundHandler.postDelayed(mPersistTabsRunnable, PERSIST_TABS_AFTER_MILLISECONDS);
     }
 
     private void registerEventListener(String event) {
         GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
     }
 
     /**
+     * Looks for an open tab with the given URL.
+     *
+     * @return id of an open tab with the given URL; -1 if the tab doesn't exist.
+     */
+    public int getTabIdForUrl(String url) {
+        for (Tab tab : mOrder) {
+            if (TextUtils.equals(tab.getURL(), url) ||
+                TextUtils.equals(ReaderModeUtils.getUrlFromAboutReader(tab.getURL()), url)) {
+                return tab.getId();
+            }
+        }
+
+        return -1;
+    }
+
+    /**
      * Loads a tab with the given URL in the currently selected tab.
      *
      * @param url URL of page to load, or search term used if searchEngine is given
      */
     public void loadUrl(String url) {
         loadUrl(url, LOADURL_NONE);
     }
 
@@ -632,16 +652,17 @@ public class Tabs implements GeckoEventL
             args.put("parentId", parentId);
             args.put("userEntered", userEntered);
             args.put("newTab", (flags & LOADURL_NEW_TAB) != 0);
             args.put("isPrivate", isPrivate);
             args.put("pinned", (flags & LOADURL_PINNED) != 0);
             args.put("delayLoad", delayLoad);
             args.put("desktopMode", desktopMode);
             args.put("selected", !background);
+            args.put("aboutHomePage", (flags & LOADURL_READING_LIST) != 0 ? HomePager.Page.READING_LIST : "");
 
             if ((flags & LOADURL_NEW_TAB) != 0) {
                 int tabId = getNextTabId();
                 args.put("tabID", tabId);
 
                 // The URL is updated for the tab once Gecko responds with the
                 // Tab:Added message. We can preliminarily set the tab's URL as
                 // long as it's a valid URI.
--- a/mobile/android/base/TabsPanel.java
+++ b/mobile/android/base/TabsPanel.java
@@ -100,29 +100,21 @@ public class TabsPanel extends LinearLay
         mAddTab = (ImageButton) findViewById(R.id.add_tab);
         mAddTab.setOnClickListener(new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
                 TabsPanel.this.addTab();
             }
         });
 
-        ImageButton button;
-        Resources resources = getContext().getResources();
-
         mTabWidget = (IconTabWidget) findViewById(R.id.tab_widget);
 
-        button = mTabWidget.addTab(R.drawable.tabs_normal);
-        button.setContentDescription(resources.getString(R.string.tabs_normal));
-
-        button = mTabWidget.addTab(R.drawable.tabs_private);
-        button.setContentDescription(resources.getString(R.string.tabs_private));
-
-        button = mTabWidget.addTab(R.drawable.tabs_synced);
-        button.setContentDescription(resources.getString(R.string.tabs_synced));
+        mTabWidget.addTab(R.drawable.tabs_normal, R.string.tabs_normal);
+        mTabWidget.addTab(R.drawable.tabs_private, R.string.tabs_private);
+        mTabWidget.addTab(R.drawable.tabs_synced, R.string.tabs_synced);
 
         mTabWidget.setTabSelectionListener(this);
     }
 
     public void addTab() {
         if (mCurrentPanel == Panel.NORMAL_TABS)
            mActivity.addTab();
         else
--- a/mobile/android/base/TabsTray.java
+++ b/mobile/android/base/TabsTray.java
@@ -310,17 +310,17 @@ public class TabsTray extends TwoWayView
         if (isVertical())
             animator.attach(view, Property.TRANSLATION_X, pos);
         else
             animator.attach(view, Property.TRANSLATION_Y, pos);
 
         mCloseAnimationCount++;
         mPendingClosedTabs.add(view);
 
-        animator.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+        animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
             @Override
             public void onPropertyAnimationStart() { }
             @Override
             public void onPropertyAnimationEnd() {
                 mCloseAnimationCount--;
                 if (mCloseAnimationCount > 0)
                     return;
 
@@ -348,17 +348,17 @@ public class TabsTray extends TwoWayView
             animator.attach(view, Property.WIDTH, 1);
 
         TabRow tab = (TabRow)view.getTag();
         final int tabId = tab.id;
         // Caching this assumes that all rows are the same height
 	if (mOriginalSize == 0)
             mOriginalSize = (isVertical ? view.getHeight() : view.getWidth());
 
-        animator.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+        animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
             @Override
             public void onPropertyAnimationStart() { }
             @Override
             public void onPropertyAnimationEnd() {
                 Tabs tabs = Tabs.getInstance();
                 Tab tab = tabs.getTab(tabId);
                 tabs.closeTab(tab);
             }
@@ -372,17 +372,17 @@ public class TabsTray extends TwoWayView
         animator.attach(view, Property.ALPHA, 1);
 
         if (isVertical())
             animator.attach(view, Property.TRANSLATION_X, 0);
         else
             animator.attach(view, Property.TRANSLATION_Y, 0);
 
 
-        animator.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+        animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
             @Override
             public void onPropertyAnimationStart() { }
             @Override
             public void onPropertyAnimationEnd() {
                 TabRow tab = (TabRow) view.getTag();
                 tab.close.setVisibility(View.VISIBLE);
             }
         });
--- a/mobile/android/base/ThumbnailHelper.java
+++ b/mobile/android/base/ThumbnailHelper.java
@@ -24,17 +24,17 @@ import java.util.concurrent.atomic.Atomi
  * completion of the current thumbnail the next one is automatically processed.
  * Changes to the thumbnail width are stashed in mPendingWidth and the change is
  * applied between thumbnail processing. This allows a single thumbnail buffer to
  * be used for all thumbnails.
  */
 public final class ThumbnailHelper {
     private static final String LOGTAG = "GeckoThumbnailHelper";
 
-    public static final float THUMBNAIL_ASPECT_RATIO = 0.714f;  // this is a 5:7 ratio (as per UX decision)
+    public static final float THUMBNAIL_ASPECT_RATIO = 0.571f;  // this is a 4:7 ratio (as per UX decision)
 
     // static singleton stuff
 
     private static ThumbnailHelper sInstance;
 
     public static synchronized ThumbnailHelper getInstance() {
         if (sInstance == null) {
             sInstance = new ThumbnailHelper();
--- a/mobile/android/base/animation/PropertyAnimator.java
+++ b/mobile/android/base/animation/PropertyAnimator.java
@@ -6,16 +6,17 @@
 package org.mozilla.gecko.animation;
 
 import android.support.v4.view.ViewCompat;
 import android.os.Build;
 import android.os.Handler;
 import android.view.Choreographer;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class PropertyAnimator implements Runnable {
@@ -44,31 +45,32 @@ public class PropertyAnimator implements
         public void onPropertyAnimationEnd();
     }
 
     private Interpolator mInterpolator;
     private long mStartTime;
     private long mDuration;
     private float mDurationReciprocal;
     private List<ElementHolder> mElementsList;
-    private PropertyAnimationListener mListener;
+    private List<PropertyAnimationListener> mListeners;
     private FramePoster mFramePoster;
     private boolean mUseHardwareLayer;
 
     public PropertyAnimator(long duration) {
         this(duration, new DecelerateInterpolator());
     }
 
     public PropertyAnimator(long duration, Interpolator interpolator) {
         mDuration = duration;
         mDurationReciprocal = 1.0f / (float) mDuration;
         mInterpolator = interpolator;
         mElementsList = new ArrayList<ElementHolder>();
         mFramePoster = FramePoster.create(this);
         mUseHardwareLayer = true;
+        mListeners = null;
     }
 
     public void setUseHardwareLayer(boolean useHardwareLayer) {
         mUseHardwareLayer = useHardwareLayer;
     }
 
     public void attach(View view, Property property, float to) {
         ElementHolder element = new ElementHolder();
@@ -76,18 +78,22 @@ public class PropertyAnimator implements
         element.view = view;
         element.proxy = AnimatorProxy.create(view);
         element.property = property;
         element.to = to;
 
         mElementsList.add(element);
     }
 
-    public void setPropertyAnimationListener(PropertyAnimationListener listener) {
-        mListener = listener;
+    public void addPropertyAnimationListener(PropertyAnimationListener listener) {
+        if (mListeners == null) {
+            mListeners = new ArrayList<PropertyAnimationListener>();
+        }
+
+        mListeners.add(listener);
     }
 
     public long getDuration() {
         return mDuration;
     }
 
     public long getRemainingTime() {
         int timePassed = (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime);
@@ -139,20 +145,45 @@ public class PropertyAnimator implements
             ViewCompat.setHasTransientState(element.view, true);
 
             if (shouldEnableHardwareLayer(element))
                 element.view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
             else
                 element.view.setDrawingCacheEnabled(true);
         }
 
-        mFramePoster.postFirstAnimationFrame();
+        // Get ViewTreeObserver from any of the participant views
+        // in the animation.
+        final ViewTreeObserver treeObserver;
+        if (mElementsList.size() > 0) {
+            treeObserver = mElementsList.get(0).view.getViewTreeObserver();
+        } else {
+            treeObserver = null;
+        }
 
-        if (mListener != null)
-            mListener.onPropertyAnimationStart();
+        // Try to start animation after any on-going layout round
+        // in the current view tree.
+        if (treeObserver != null && treeObserver.isAlive()) {
+            treeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                @Override
+                public boolean onPreDraw() {
+                    treeObserver.removeOnPreDrawListener(this);
+                    mFramePoster.postFirstAnimationFrame();
+                    return true;
+                }
+            });
+        } else {
+            mFramePoster.postFirstAnimationFrame();
+        }
+
+        if (mListeners != null) {
+            for (PropertyAnimationListener listener : mListeners) {
+                listener.onPropertyAnimationStart();
+            }
+        }
     }
 
 
     /**
      * Stop the animation, optionally snapping to the end position.
      * onPropertyAnimationEnd is only called when snapping to the end position.
      */
     public void stop(boolean snapToEndPosition) {
@@ -168,20 +199,25 @@ public class PropertyAnimator implements
             if (shouldEnableHardwareLayer(element))
                 element.view.setLayerType(View.LAYER_TYPE_NONE, null);
             else
                 element.view.setDrawingCacheEnabled(false);
         }
 
         mElementsList.clear();
 
-        if (mListener != null) {
-            if (snapToEndPosition)
-                mListener.onPropertyAnimationEnd();
-            mListener = null;
+        if (mListeners != null) {
+            if (snapToEndPosition) {
+                for (PropertyAnimationListener listener : mListeners) {
+                    listener.onPropertyAnimationEnd();
+                }
+            }
+
+            mListeners.clear();
+            mListeners = null;
         }
     }
 
     public void stop() {
         stop(true);
     }
 
     private boolean shouldEnableHardwareLayer(ElementHolder element) {
deleted file mode 100644
--- a/mobile/android/base/awesomebar/AllPagesTab.java
+++ /dev/null
@@ -1,962 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.AwesomeBar.ContextMenuSubject;
-import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.BrowserDB.URLColumns;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.GeckoEventListener;
-import org.mozilla.gecko.util.StringUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.util.UiAsyncTask;
-import org.mozilla.gecko.widget.FaviconView;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.app.Activity;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.TranslateAnimation;
-import android.widget.AdapterView;
-import android.widget.FilterQueryProvider;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
-import android.widget.TextView;
-
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
-    public static final String LOGTAG = "GeckoAllPagesTab";
-    private static final String TAG = "allPages";
-
-    private static final int SUGGESTION_TIMEOUT = 3000;
-    private static final int SUGGESTION_MAX = 3;
-    private static final int ANIMATION_DURATION = 250;
-    // The maximum number of rows deep in a search we'll dig for an autocomplete result
-    private static final int MAX_AUTOCOMPLETE_SEARCH = 20;
-
-    private String mSearchTerm;
-    private ArrayList<SearchEngine> mSearchEngines;
-    private SuggestClient mSuggestClient;
-    private boolean mSuggestionsEnabled;
-    private AsyncTask<String, Void, ArrayList<String>> mSuggestTask;
-    private AwesomeBarCursorAdapter mCursorAdapter = null;
-    private boolean mTelemetrySent = false;
-    private LinearLayout mAllPagesView;
-    private boolean mAnimateSuggestions;
-    private View mSuggestionsOptInPrompt;
-    private Handler mHandler;
-    private ListView mListView;
-    private volatile AutocompleteHandler mAutocompleteHandler = null;
-
-    private static final int MESSAGE_LOAD_FAVICONS = 1;
-    private static final int MESSAGE_UPDATE_FAVICONS = 2;
-    private static final int DELAY_SHOW_THUMBNAILS = 550;
-
-    public AllPagesTab(Context context) {
-        super(context);
-        mSearchEngines = new ArrayList<SearchEngine>();
-
-        registerEventListener("SearchEngines:Data");
-        GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:GetVisible", null));
-
-        mHandler = new AllPagesHandler();
-    }
-
-    @Override
-    public boolean onBackPressed() {
-        return false;
-    }
-
-    @Override
-    public int getTitleStringId() {
-        return R.string.awesomebar_all_pages_title;
-    }
-
-    @Override
-    public String getTag() {
-        return TAG;
-    }
-
-    private ListView getListView() {
-        if (mListView == null && mView != null) {
-            mListView = (ListView) mView.findViewById(R.id.awesomebar_list);
-        }
-        return mListView;
-    }
-
-    @Override
-    public View getView() {
-        if (mView == null) {
-            mView = (LinearLayout) (LayoutInflater.from(mContext).inflate(R.layout.awesomebar_allpages_list, null));
-            mView.setTag(TAG);
-
-            final ListView list = getListView();
-            list.setTag(TAG);
-            ((Activity)mContext).registerForContextMenu(list);
-            list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-                @Override
-                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-                     handleItemClick(parent, view, position, id);
-                }
-            });
-
-            AwesomeBarCursorAdapter adapter = getCursorAdapter();
-            list.setAdapter(adapter);
-            list.setOnTouchListener(mListListener);
-
-            final ListSelectionListener listener = new ListSelectionListener();
-            list.setOnItemSelectedListener(listener);
-            list.setOnFocusChangeListener(listener);
-
-            list.setOnKeyListener(new View.OnKeyListener() {
-                @Override
-                public boolean onKey(View v, int keyCode, android.view.KeyEvent event) {
-                    View selected = list.getSelectedView();
-
-                    if (selected instanceof SearchEngineRow) {
-                        return ((SearchEngineRow) selected).onKeyDown(keyCode, event);
-                    }
-                    return false;
-                }
-            });
-
-        }
-
-        return mView;
-    }
-
-    @Override
-    public void destroy() {
-        super.destroy();
-
-        unregisterEventListener("SearchEngines:Data");
-
-        mHandler.removeMessages(MESSAGE_UPDATE_FAVICONS);
-        mHandler.removeMessages(MESSAGE_LOAD_FAVICONS);
-        mHandler = null;
-
-        // Can't use getters for adapter or listview. They will create them if null.
-        if (mCursorAdapter != null && mListView != null) {
-            mListView.setAdapter(null);
-            final Cursor cursor = mCursorAdapter.getCursor();
-            // Gingerbread locks the DB when closing a cursor, so do it in the
-            // background.
-            ThreadUtils.postToBackgroundThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (cursor != null && !cursor.isClosed())
-                        cursor.close();
-                }
-            });
-        }
-    }
-
-    public void filter(String searchTerm, AutocompleteHandler handler) {
-        mAutocompleteHandler = handler;
-
-        AwesomeBarCursorAdapter adapter = getCursorAdapter();
-        adapter.filter(searchTerm);
-
-        filterSuggestions(searchTerm);
-        if (mSuggestionsOptInPrompt != null) {
-            int visibility = TextUtils.isEmpty(searchTerm) ? View.GONE : View.VISIBLE;
-            if (mSuggestionsOptInPrompt.getVisibility() != visibility) {
-                mSuggestionsOptInPrompt.setVisibility(visibility);
-            }
-        }
-    }
-
-    private void findAutocompleteFor(String searchTerm, Cursor cursor) {
-        if (TextUtils.isEmpty(searchTerm) || cursor == null || mAutocompleteHandler == null)
-            return;
-
-        // avoid searching the path if we don't have to. Currently just decided by if there is
-        // a '/' character in the string
-        final String res = searchHosts(searchTerm, cursor, searchTerm.indexOf("/") > 0);
-
-        if (res != null) {
-            ThreadUtils.postToUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    // Its possible that mAutocompleteHandler has been destroyed
-                    if (mAutocompleteHandler != null) {
-                        mAutocompleteHandler.onAutocomplete(res);
-                        mAutocompleteHandler = null;
-                    }
-                }
-            });
-        }
-    }
-
-    private String searchHosts(String searchTerm, Cursor cursor, boolean searchPath) {
-        int i = 0;
-        if (cursor.moveToFirst()) {
-            int urlIndex = cursor.getColumnIndexOrThrow(URLColumns.URL);
-            do {
-                final Uri url = Uri.parse(cursor.getString(urlIndex));
-                String host = StringUtils.stripCommonSubdomains(url.getHost());
-                // host may be null for about pages
-                if (host == null)
-                    continue;
-
-                StringBuilder hostBuilder = new StringBuilder(host);
-               if (hostBuilder.indexOf(searchTerm) == 0) {
-                    return hostBuilder.append("/").toString();
-                }
-
-                if (searchPath) {
-                    List<String> path = url.getPathSegments();
-
-                    for (String seg : path) {
-                        hostBuilder.append("/").append(seg);
-                        if (hostBuilder.indexOf(searchTerm) == 0) {
-                            return hostBuilder.append("/").toString();
-                        }
-                    }
-                }
-
-                i++;
-            } while (i < MAX_AUTOCOMPLETE_SEARCH && cursor.moveToNext());
-        }
-        return null;
-    }
-
-    /**
-     * Query for suggestions, but don't show them yet.
-     */
-    private void primeSuggestions() {
-        ThreadUtils.postToBackgroundThread(new Runnable() {
-            @Override
-            public void run() {
-                mSuggestClient.query(mSearchTerm);
-            }
-        });
-    }
-
-    private void filterSuggestions(String searchTerm) {
-        // cancel previous query
-        if (mSuggestTask != null) {
-            mSuggestTask.cancel(true);
-        }
-
-        if (mSuggestClient != null && mSuggestionsEnabled) {
-            mSuggestTask = new AsyncTask<String, Void, ArrayList<String>>() {
-                @Override
-                protected ArrayList<String> doInBackground(String... query) {
-                    return mSuggestClient.query(query[0]);
-                }
-
-                @Override
-                protected void onPostExecute(ArrayList<String> suggestions) {
-                    setSuggestions(suggestions);
-                }
-            };
-            mSuggestTask.execute(searchTerm);
-        }
-    }
-
-    protected AwesomeBarCursorAdapter getCursorAdapter() {
-        if (mCursorAdapter == null) {
-            // Load the list using a custom adapter so we can create the bitmaps
-            mCursorAdapter = new AwesomeBarCursorAdapter(mContext);
-
-            mCursorAdapter.setFilterQueryProvider(new FilterQueryProvider() {
-                @Override
-                public Cursor runQuery(CharSequence constraint) {
-                    long start = SystemClock.uptimeMillis();
-
-                    Cursor c = BrowserDB.filter(getContentResolver(), constraint, MAX_RESULTS);
-                    c.getCount();
-
-                    postLoadFavicons();
-
-                    long end = SystemClock.uptimeMillis();
-                    if (!mTelemetrySent && TextUtils.isEmpty(constraint)) {
-                        int time = (int)(end - start);
-                        Telemetry.HistogramAdd("FENNEC_AWESOMEBAR_ALLPAGES_EMPTY_TIME", time);
-                        mTelemetrySent = true;
-                    }
-
-                    findAutocompleteFor(constraint.toString(), c);
-                    return c;
-                }
-            });
-        }
-        return mCursorAdapter;
-    }
-
-    private interface AwesomeBarItem {
-        public void onClick();
-        public ContextMenuSubject getSubject();
-    }
-
-    private class AwesomeBarCursorItem implements AwesomeBarItem {
-        private Cursor mCursor;
-
-        public AwesomeBarCursorItem(Cursor cursor) {
-            mCursor = cursor;
-        }
-
-        @Override
-        public void onClick() {
-            String url = mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.URL));
-            String title = mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.TITLE));
-            sendToListener(url, title);
-        }
-
-        @Override
-        public ContextMenuSubject getSubject() {
-            // Use the history id in order to allow removing history entries
-            int id = mCursor.getInt(mCursor.getColumnIndexOrThrow(Combined.HISTORY_ID));
-
-            String keyword = null;
-            int keywordCol = mCursor.getColumnIndex(URLColumns.KEYWORD);
-            if (keywordCol != -1)
-                keyword = mCursor.getString(keywordCol);
-
-            final String url = mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.URL));
-
-            Bitmap bitmap = Favicons.getInstance().getFaviconFromMemCache(url);
-            byte[] favicon = null;
-
-            if (bitmap != null) {
-                ByteArrayOutputStream stream = new ByteArrayOutputStream();
-                if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)) {
-                    favicon = stream.toByteArray();
-                } else {
-                    Log.w(LOGTAG, "Favicon compression failed.");
-                }
-            }
-
-            return new ContextMenuSubject(id, url, favicon,
-                                          mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.TITLE)),
-                                          keyword,
-                                          mCursor.getInt(mCursor.getColumnIndexOrThrow(Combined.DISPLAY)));
-        }
-    }
-
-    private class AwesomeBarSearchEngineItem implements AwesomeBarItem {
-        private SearchEngine mSearchEngine;
-
-        public AwesomeBarSearchEngineItem(SearchEngine searchEngine) {
-            mSearchEngine = searchEngine;
-        }
-
-        @Override
-        public void onClick() {
-            AwesomeBarTabs.OnUrlOpenListener listener = getUrlListener();
-            if (listener != null)
-                listener.onSearch(mSearchEngine, mSearchTerm);
-        }
-
-        @Override
-        public ContextMenuSubject getSubject() {
-            // Do not show context menu for search engine items
-            return null;
-        }
-    }
-
-    private class AwesomeBarCursorAdapter extends SimpleCursorAdapter {
-        private static final int ROW_SEARCH = 0;
-        private static final int ROW_STANDARD = 1;
-        private static final int ROW_SUGGEST = 2;
-
-        public AwesomeBarCursorAdapter(Context context) {
-            super(context, -1, null, new String[] {}, new int[] {});
-            mSearchTerm = "";
-        }
-
-        public void filter(String searchTerm) {
-            boolean changed = !mSearchTerm.equals(searchTerm);
-            mSearchTerm = searchTerm;
-
-            if (changed)
-                mCursorAdapter.notifyDataSetChanged();
-
-            getFilter().filter(searchTerm);
-        }
-
-        private int getSuggestEngineCount() {
-            return (mSearchTerm.length() == 0 || mSuggestClient == null || !mSuggestionsEnabled) ? 0 : 1;
-        }
-
-        // Add the search engines to the number of reported results.
-        @Override
-        public int getCount() {
-            final int resultCount = super.getCount();
-
-            // don't show search engines or suggestions if search field is empty
-            if (mSearchTerm.length() == 0)
-                return resultCount;
-
-            return resultCount + mSearchEngines.size();
-        }
-
-        // If an item is part of the cursor result set, return that entry.
-        // Otherwise, return the search engine data.
-        @Override
-        public Object getItem(int position) {
-            int engineIndex = getEngineIndex(position);
-
-            if (engineIndex == -1) {
-                // return awesomebar result
-                position -= getSuggestEngineCount();
-                return new AwesomeBarCursorItem((Cursor) super.getItem(position));
-            }
-
-            // return search engine
-            return new AwesomeBarSearchEngineItem(mSearchEngines.get(engineIndex));
-        }
-
-        private int getEngineIndex(int position) {
-            final int resultCount = super.getCount();
-            final int suggestEngineCount = getSuggestEngineCount();
-
-            // return suggest engine index
-            if (position < suggestEngineCount)
-                return position;
-
-            // not an engine
-            if (position - suggestEngineCount < resultCount)
-                return -1;
-
-            // return search engine index
-            return position - resultCount;
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            int engine = getEngineIndex(position);
-            if (engine == -1) {
-                return ROW_STANDARD;
-            } else if (engine == 0 && mSuggestionsEnabled) {
-                // Give suggestion views their own type to prevent them from
-                // sharing other recycled search engine views. Using other
-                // recycled views for the suggestion row can break animations
-                // (bug 815937).
-                return ROW_SUGGEST;
-            }
-            return ROW_SEARCH;
-        }
-
-        @Override
-        public int getViewTypeCount() {
-            // view can be either a standard awesomebar row, a search engine
-            // row, or a suggestion row
-            return 3;
-        }
-
-        @Override
-        public boolean isEnabled(int position) {
-            // If we're using a gamepad or keyboard, allow the row to be
-            // focused so it can pass the focus to its child suggestion views.
-            if (!getListView().isInTouchMode()) {
-                return true;
-            }
-
-            // If the suggestion row only contains one item (the user-entered
-            // query), allow the entire row to be clickable; clicking the row
-            // has the same effect as clicking the single suggestion. If the
-            // row contains multiple items, clicking the row will do nothing.
-            int index = getEngineIndex(position);
-            if (index != -1)
-                return mSearchEngines.get(index).suggestions.isEmpty();
-            return true;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            int type = getItemViewType(position);
-            if (type == ROW_SEARCH || type == ROW_SUGGEST) {
-                if (convertView == null || !(convertView instanceof SearchEngineRow)) {
-                    convertView = (SearchEngineRow) getInflater().inflate(R.layout.home_search_item_row, getListView(), false);
-                    ((SearchEngineRow) convertView).setOnUrlOpenListener(getUrlListener());
-                }
-
-                SearchEngineRow searchRow = (SearchEngineRow) convertView;
-                searchRow.setSearchTerm(mSearchTerm);
-
-                final SearchEngine engine = mSearchEngines.get(getEngineIndex(position));
-                final boolean doAnimation = (mAnimateSuggestions && engine.suggestions.size() > 0);
-                searchRow.updateFromSearchEngine(engine, doAnimation);
-                if (doAnimation) {
-                    // Only animate suggestions the first time they are shown
-                    mAnimateSuggestions = false;
-                }
-            } else {
-                AwesomeEntryViewHolder viewHolder = null;
-
-                if (convertView == null || !(convertView.getTag() instanceof AwesomeEntryViewHolder)) {
-                    convertView = getInflater().inflate(R.layout.awesomebar_row, null);
-
-                    viewHolder = new AwesomeEntryViewHolder();
-                    viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
-                    viewHolder.urlView = (TextView) convertView.findViewById(R.id.url);
-                    viewHolder.faviconView = (FaviconView) convertView.findViewById(R.id.favicon);
-                    viewHolder.bookmarkIconView = (ImageView) convertView.findViewById(R.id.bookmark_icon);
-
-                    convertView.setTag(viewHolder);
-                } else {
-                    viewHolder = (AwesomeEntryViewHolder) convertView.getTag();
-                }
-
-                position -= getSuggestEngineCount();
-                Cursor cursor = getCursor();
-                if (!cursor.moveToPosition(position))
-                    throw new IllegalStateException("Couldn't move cursor to position " + position);
-
-                updateTitle(viewHolder.titleView, cursor);
-                updateUrl(viewHolder, cursor);
-                updateBookmarkIcon(viewHolder.bookmarkIconView, cursor);
-                displayFavicon(viewHolder);
-            }
-
-            return convertView;
-        }
-    };
-
-    /**
-     * Sets suggestions associated with the current suggest engine.
-     * If there is no suggest engine, this does nothing.
-     */
-    private void setSuggestions(final ArrayList<String> suggestions) {
-        if (mSuggestClient != null) {
-            mSearchEngines.get(0).suggestions = suggestions;
-            getCursorAdapter().notifyDataSetChanged();
-        }
-    }
-
-    /**
-     * Sets search engines to be shown for user-entered queries.
-     */
-    private void setSearchEngines(JSONObject data) {
-        try {
-            JSONObject suggest = data.getJSONObject("suggest");
-            String suggestEngine = suggest.isNull("engine") ? null : suggest.getString("engine");
-            String suggestTemplate = suggest.isNull("template") ? null : suggest.getString("template");
-            mSuggestionsEnabled = suggest.getBoolean("enabled");
-            boolean suggestionsPrompted = suggest.getBoolean("prompted");
-            JSONArray engines = data.getJSONArray("searchEngines");
-
-            ArrayList<SearchEngine> searchEngines = new ArrayList<SearchEngine>();
-            for (int i = 0; i < engines.length(); i++) {
-                JSONObject engineJSON = engines.getJSONObject(i);
-                String name = engineJSON.getString("name");
-                String identifier = engineJSON.getString("identifier");
-                String iconURI = engineJSON.getString("iconURI");
-                Bitmap icon = BitmapUtils.getBitmapFromDataURI(iconURI);
-                if (name.equals(suggestEngine) && suggestTemplate != null) {
-                    // suggest engine should be at the front of the list
-                    searchEngines.add(0, new SearchEngine(name, identifier, icon));
-
-                    // The only time Tabs.getInstance().getSelectedTab() should
-                    // be null is when we're restoring after a crash. We should
-                    // never restore private tabs when that happens, so it
-                    // should be safe to assume that null means non-private.
-                    Tab tab = Tabs.getInstance().getSelectedTab();
-                    if (tab == null || !tab.isPrivate())
-                        mSuggestClient = new SuggestClient(getView().getContext(), suggestTemplate, SUGGESTION_TIMEOUT, SUGGESTION_MAX);
-                } else {
-                    searchEngines.add(new SearchEngine(name, identifier, icon));
-                }
-            }
-
-            mSearchEngines = searchEngines;
-            mCursorAdapter.notifyDataSetChanged();
-
-            // show suggestions opt-in if user hasn't been prompted
-            if (!suggestionsPrompted && mSuggestClient != null) {
-                showSuggestionsOptIn();
-            }
-        } catch (JSONException e) {
-            Log.e(LOGTAG, "Error getting search engine JSON", e);
-        }
-
-        filterSuggestions(mSearchTerm);
-    }
-
-    private void showSuggestionsOptIn() {
-        mSuggestionsOptInPrompt = LayoutInflater.from(mContext).inflate(R.layout.awesomebar_suggestion_prompt, (LinearLayout)getView(), false);
-        GeckoTextView promptText = (GeckoTextView) mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_title);
-        promptText.setText(getResources().getString(R.string.suggestions_prompt, mSearchEngines.get(0).name));
-        Tab tab = Tabs.getInstance().getSelectedTab();
-        if (tab != null)
-            promptText.setPrivateMode(tab.isPrivate());
-
-        final View yesButton = mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_yes);
-        final View noButton = mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_no);
-        OnClickListener listener = new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                // Prevent the buttons from being clicked multiple times (bug 816902)
-                yesButton.setOnClickListener(null);
-                noButton.setOnClickListener(null);
-
-                setSuggestionsEnabled(v == yesButton);
-            }
-        };
-        yesButton.setOnClickListener(listener);
-        noButton.setOnClickListener(listener);
-
-        // If the prompt container gains focus, automatically pass focus to the
-        // yes button in the prompt.
-        final View promptContainer = mSuggestionsOptInPrompt.findViewById(R.id.prompt_container);
-        promptContainer.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                if (hasFocus) {
-                    yesButton.requestFocus();
-                }
-            }
-        });
-
-        mSuggestionsOptInPrompt.setVisibility(View.GONE);
-        ((LinearLayout)getView()).addView(mSuggestionsOptInPrompt, 0);
-    }
-
-    private void setSuggestionsEnabled(final boolean enabled) {
-        // Clicking the yes/no buttons quickly can cause the click events be
-        // queued before the listeners are removed above, so it's possible
-        // setSuggestionsEnabled() can be called twice. mSuggestionsOptInPrompt
-        // can be null if this happens (bug 828480).
-        if (mSuggestionsOptInPrompt == null) {
-            return;
-        }
-
-        // Make suggestions appear immediately after the user opts in
-        primeSuggestions();
-
-        // Pref observer in gecko will also set prompted = true
-        PrefsHelper.setPref("browser.search.suggest.enabled", enabled);
-
-        TranslateAnimation anim1 = new TranslateAnimation(0, mSuggestionsOptInPrompt.getWidth(), 0, 0);
-        anim1.setDuration(ANIMATION_DURATION);
-        anim1.setInterpolator(new AccelerateInterpolator());
-        anim1.setFillAfter(true);
-        final View promptContainer = mSuggestionsOptInPrompt.findViewById(R.id.prompt_container);
-
-        TranslateAnimation anim2 = new TranslateAnimation(0, 0, 0, -1 * mSuggestionsOptInPrompt.getHeight());
-        anim2.setDuration(ANIMATION_DURATION);
-        anim2.setFillAfter(true);
-        anim2.setStartOffset(anim1.getDuration());
-        final LinearLayout view = (LinearLayout)getView();
-        anim2.setAnimationListener(new Animation.AnimationListener() {
-            @Override
-            public void onAnimationStart(Animation a) {
-                // Increase the height of the view so a gap isn't shown during animation
-                view.getLayoutParams().height = view.getHeight() +
-                        mSuggestionsOptInPrompt.getHeight();
-                view.requestLayout();
-            }
-            @Override
-            public void onAnimationRepeat(Animation a) {}
-            @Override
-            public void onAnimationEnd(Animation a) {
-                // Removing the view immediately results in a NPE in
-                // dispatchDraw(), possibly because this callback executes
-                // before drawing is finished. Posting this as a Runnable fixes
-                // the issue.
-                view.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        view.removeView(mSuggestionsOptInPrompt);
-                        getListView().clearAnimation();
-                        mSuggestionsOptInPrompt = null;
-
-                        if (enabled) {
-                            // Reset the view height
-                            view.getLayoutParams().height = LayoutParams.FILL_PARENT;
-
-                            mSuggestionsEnabled = enabled;
-                            mAnimateSuggestions = true;
-                            getCursorAdapter().notifyDataSetChanged();
-                            filterSuggestions(mSearchTerm);
-                        }
-                    }
-                });
-            }
-        });
-
-        promptContainer.startAnimation(anim1);
-        mSuggestionsOptInPrompt.startAnimation(anim2);
-        getListView().startAnimation(anim2);
-    }
-
-    @Override
-    public void handleMessage(String event, final JSONObject message) {
-        if (event.equals("SearchEngines:Data")) {
-            ThreadUtils.postToUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    setSearchEngines(message);
-                }
-            });
-        }
-    }
-
-    public void handleItemClick(AdapterView<?> parent, View view, int position, long id) {
-        ListView listview = getListView();
-        if (listview == null)
-            return;
-
-        AwesomeBarItem item = (AwesomeBarItem)listview.getItemAtPosition(position);
-        item.onClick();
-    }
-
-    protected void updateBookmarkIcon(ImageView bookmarkIconView, Cursor cursor) {
-        int bookmarkIdIndex = cursor.getColumnIndexOrThrow(Combined.BOOKMARK_ID);
-        long id = cursor.getLong(bookmarkIdIndex);
-
-        int displayIndex = cursor.getColumnIndexOrThrow(Combined.DISPLAY);
-        int display = cursor.getInt(displayIndex);
-
-        // The bookmark id will be 0 (null in database) when the url
-        // is not a bookmark.
-        int visibility = (id == 0 ? View.GONE : View.VISIBLE);
-        bookmarkIconView.setVisibility(visibility);
-
-        if (display == Combined.DISPLAY_READER) {
-            bookmarkIconView.setImageResource(R.drawable.ic_awesomebar_reader);
-        } else {
-            bookmarkIconView.setImageResource(R.drawable.ic_awesomebar_star);
-        }
-    }
-
-    @Override
-    public ContextMenuSubject getSubject(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
-        ContextMenuSubject subject = null;
-
-        if (!(menuInfo instanceof AdapterView.AdapterContextMenuInfo)) {
-            Log.e(LOGTAG, "menuInfo is not AdapterContextMenuInfo");
-            return subject;
-        }
-
-        ListView list = (ListView)view;
-        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
-        subject = ((AwesomeBarItem) list.getItemAtPosition(info.position)).getSubject();
-
-        if (subject == null)
-            return subject;
-
-        setupMenu(menu, subject);
-
-        menu.findItem(R.id.remove_bookmark).setVisible(false);
-        menu.findItem(R.id.edit_bookmark).setVisible(false);
-        menu.findItem(R.id.open_in_reader).setVisible(subject.display == Combined.DISPLAY_READER);
-
-        return subject;
-    }
-
-    private void registerEventListener(String event) {
-        GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
-    }
-
-    private void unregisterEventListener(String event) {
-        GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
-    }
-
-    private List<String> getUrlsWithoutFavicon() {
-        List<String> urls = new ArrayList<String>();
-
-        Cursor c = mCursorAdapter.getCursor();
-        if (c == null || !c.moveToFirst())
-            return urls;
-
-        do {
-            final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
-
-            // We only want to load favicons from DB if they are not in the
-            // memory cache yet.
-            if (Favicons.getInstance().getFaviconFromMemCache(url) != null)
-                continue;
-
-            urls.add(url);
-        } while (c.moveToNext());
-
-        return urls;
-    }
-
-    public void storeFaviconsInMemCache(Cursor c) {
-        if (c == null)
-            return;
-
-        try {
-            if (!c.moveToFirst())
-                return;
-
-            do {
-                final String url = c.getString(c.getColumnIndexOrThrow(Combined.URL));
-                final byte[] b = c.getBlob(c.getColumnIndexOrThrow(Combined.FAVICON));
-                if (b == null)
-                    continue;
-
-                Bitmap favicon = BitmapUtils.decodeByteArray(b);
-                if (favicon == null)
-                    continue;
-
-                favicon = Favicons.getInstance().scaleImage(favicon);
-                Favicons.getInstance().putFaviconInMemCache(url, favicon);
-            } while (c.moveToNext());
-        } finally {
-            c.close();
-        }
-    }
-
-    private void loadFaviconsForCurrentResults() {
-        final List<String> urls = getUrlsWithoutFavicon();
-        if (urls.size() == 0)
-            return;
-
-        (new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) {
-            @Override
-            public Void doInBackground(Void... params) {
-                Cursor cursor = BrowserDB.getFaviconsForUrls(getContentResolver(), urls);
-                storeFaviconsInMemCache(cursor);
-                return null;
-            }
-
-            @Override
-            public void onPostExecute(Void result) {
-                postUpdateFavicons();
-            }
-        }).execute();
-    }
-
-    private void displayFavicon(AwesomeEntryViewHolder viewHolder) {
-        final String url = viewHolder.url;
-        Bitmap bitmap = Favicons.getInstance().getFaviconFromMemCache(url);
-        updateFavicon(viewHolder.faviconView, bitmap, url);
-    }
-
-    private void updateFavicons() {
-        ListView listView = getListView();
-        AwesomeBarCursorAdapter adapter = getCursorAdapter();
-        Cursor cursor = adapter.getCursor();
-        if (cursor == null)
-            return;
-
-        for (int i = 0; i < listView.getChildCount(); i++) {
-            final View view = listView.getChildAt(i);
-            final Object tag = view.getTag();
-
-            if (tag == null || !(tag instanceof AwesomeEntryViewHolder))
-                continue;
-
-            final AwesomeEntryViewHolder viewHolder = (AwesomeEntryViewHolder) tag;
-            displayFavicon(viewHolder);
-        }
-
-        mView.invalidate();
-    }
-
-    private void postUpdateFavicons() {
-        if (mHandler == null)
-            return;
-
-        Message msg = mHandler.obtainMessage(MESSAGE_UPDATE_FAVICONS,
-                                             AllPagesTab.this);
-
-        mHandler.removeMessages(MESSAGE_UPDATE_FAVICONS);
-        mHandler.sendMessage(msg);
-    }
-
-    private void postLoadFavicons() {
-        if (mHandler == null)
-            return;
-
-        Message msg = mHandler.obtainMessage(MESSAGE_LOAD_FAVICONS,
-                                             AllPagesTab.this);
-
-        mHandler.removeMessages(MESSAGE_LOAD_FAVICONS);
-        mHandler.sendMessageDelayed(msg, 200);
-    }
-
-    private class AllPagesHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MESSAGE_LOAD_FAVICONS:
-                    loadFaviconsForCurrentResults();
-                    break;
-                case MESSAGE_UPDATE_FAVICONS:
-                    updateFavicons();
-                    break;
-            }
-        }
-    }
-
-    private static class ListSelectionListener implements View.OnFocusChangeListener,
-                                                          AdapterView.OnItemSelectedListener {
-        private SearchEngineRow mSelectedEngineRow;
-
-        @Override
-        public void onFocusChange(View v, boolean hasFocus) {
-            if (hasFocus) {
-                View selectedRow = ((ListView) v).getSelectedView();
-                if (selectedRow != null) {
-                    selectRow(selectedRow);
-                }
-            } else {
-                deselectRow();
-            }
-        }
-
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-            deselectRow();
-            selectRow(view);
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            deselectRow();
-        }
-
-        private void selectRow(View row) {
-            if (row instanceof SearchEngineRow) {
-                mSelectedEngineRow = (SearchEngineRow) row;
-                mSelectedEngineRow.onSelected();
-            }
-        }
-
-        private void deselectRow() {
-            if (mSelectedEngineRow != null) {
-                mSelectedEngineRow.onDeselected();
-                mSelectedEngineRow = null;
-            }
-        }
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/awesomebar/AwesomeBarTab.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.AwesomeBar.ContextMenuSubject;
-import org.mozilla.gecko.db.BrowserDB.URLColumns;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.widget.FaviconView;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.text.TextUtils;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.util.HashMap;
-
-abstract public class AwesomeBarTab {
-    abstract public String getTag();
-    abstract public int getTitleStringId();
-    abstract public boolean   onBackPressed();
-    abstract public ContextMenuSubject getSubject(ContextMenu menu, View view, ContextMenuInfo menuInfo);
-    abstract public View getView();
-
-    protected View mView = null;
-    protected View.OnTouchListener mListListener;
-    private AwesomeBarTabs.OnUrlOpenListener mListener;
-    private LayoutInflater mInflater = null;
-    private ContentResolver mContentResolver = null;
-    private Resources mResources;
-    // FIXME: This value should probably come from a prefs key
-    public static final int MAX_RESULTS = 100;
-    protected Context mContext = null;
-    public static HashMap<String, Integer> sOpenTabs;
-
-    public AwesomeBarTab(Context context) {
-        mContext = context;
-    }
-
-    public void destroy() {
-        sOpenTabs = null;
-    }
-
-    public void setListTouchListener(View.OnTouchListener listener) {
-        mListListener = listener;
-        if (mView != null)
-            mView.setOnTouchListener(mListListener);
-    }
-
-    protected class AwesomeEntryViewHolder {
-        public TextView titleView;
-        public String url;
-        public TextView urlView;
-        public FaviconView faviconView;
-        public ImageView bookmarkIconView;
-    }
-
-    protected LayoutInflater getInflater() {
-        if (mInflater == null) {
-            mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        }
-        return mInflater;
-    }
-
-    protected AwesomeBarTabs.OnUrlOpenListener getUrlListener() {
-        return mListener;
-    }
-
-    protected void setUrlListener(AwesomeBarTabs.OnUrlOpenListener listener) {
-        mListener = listener;
-    }
-
-    protected ContentResolver getContentResolver() {
-        if (mContentResolver == null) {
-            mContentResolver = mContext.getContentResolver();
-        }
-        return mContentResolver;
-    }
-
-    protected HashMap<String, Integer> getOpenTabs() {
-        if (sOpenTabs == null || sOpenTabs.isEmpty()) {
-            Iterable<Tab> tabs = Tabs.getInstance().getTabsInOrder();
-            sOpenTabs = new HashMap<String, Integer>();
-            for (Tab tab : tabs) {
-                sOpenTabs.put(tab.getURL(), tab.getId());
-            }
-        }
-        return sOpenTabs;
-    }
-
-    protected Resources getResources() {
-        if (mResources == null) {
-            mResources = mContext.getResources();
-        }
-        return mResources;
-    }
-
-    protected void setupMenu(ContextMenu menu, AwesomeBar.ContextMenuSubject subject) {
-        MenuInflater inflater = new MenuInflater(mContext);
-        inflater.inflate(R.menu.awesomebar_contextmenu, menu);
-
-        // Show Open Private Tab if we're in private mode, Open New Tab otherwise
-        boolean isPrivate = false;
-        Tab tab = Tabs.getInstance().getSelectedTab();
-        if (tab != null) {
-            isPrivate = tab.isPrivate();
-        }
-        menu.findItem(R.id.open_new_tab).setVisible(!isPrivate);
-        menu.findItem(R.id.open_private_tab).setVisible(isPrivate);
-
-        // Hide "Remove" item if there isn't a valid history ID
-        if (subject.id < 0) {
-            menu.findItem(R.id.remove_history).setVisible(false);
-        }
-        menu.setHeaderTitle(subject.title);
-    }
-
-    protected void updateFavicon(FaviconView faviconView, Bitmap bitmap, String key) {
-        faviconView.updateImage(bitmap, key);
-    }
-
-    protected void updateTitle(TextView titleView, Cursor cursor) {
-        int titleIndex = cursor.getColumnIndexOrThrow(URLColumns.TITLE);
-        String title = cursor.getString(titleIndex);
-        String url = "";
-
-        // Use the URL instead of an empty title for consistency with the normal URL
-        // bar view - this is the equivalent of getDisplayTitle() in Tab.java
-        if (TextUtils.isEmpty(title)) {
-            int urlIndex = cursor.getColumnIndexOrThrow(URLColumns.URL);
-            url = cursor.getString(urlIndex);
-        }
-
-        updateTitle(titleView, title, url);
-    }
-
-    protected void updateTitle(TextView titleView, String title, String url) {
-        if (TextUtils.isEmpty(title)) {
-            titleView.setText(url);
-        } else {
-            titleView.setText(title);
-        }
-    }
-
-    public void sendToListener(String url, String title) {
-        AwesomeBarTabs.OnUrlOpenListener listener = getUrlListener();
-        if (listener == null)
-            return;
-
-        Integer tabId = getOpenTabs().get(url);
-        if (tabId != null) {
-            listener.onSwitchToTab(tabId);
-        } else {
-            listener.onUrlOpen(url, title);
-        }
-    }
-
-    protected void updateUrl(AwesomeEntryViewHolder holder, Cursor cursor) {
-        int urlIndex = cursor.getColumnIndexOrThrow(URLColumns.URL);
-        String url = cursor.getString(urlIndex);
-        updateUrl(holder, url);
-    }
-    
-    protected void updateUrl(AwesomeEntryViewHolder holder, String url) {
-        Integer tabId = getOpenTabs().get(url);
-        holder.url = url;
-        if (tabId != null) {
-            holder.urlView.setText(R.string.awesomebar_switch_to_tab);
-            holder.urlView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_awesomebar_tab, 0, 0, 0);
-        } else {
-            holder.urlView.setText(url);
-            holder.urlView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
-        }
-    }
-
-    protected boolean hideSoftInput(View view) {
-        InputMethodManager imm =
-                (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
-
-        return imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/awesomebar/BookmarksTab.java
+++ /dev/null
@@ -1,470 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.AwesomeBar.ContextMenuSubject;
-import org.mozilla.gecko.db.BrowserContract.Bookmarks;
-import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.BrowserDB.URLColumns;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.widget.FaviconView;
-
-import android.app.Activity;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.os.AsyncTask;
-import android.util.Log;
-import android.util.Pair;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
-import android.widget.TextView;
-
-import java.util.LinkedList;
-
-public class BookmarksTab extends AwesomeBarTab {
-    public static final String LOGTAG = "BOOKMARKS_TAB";
-    public static final String TAG = "bookmarks";
-    private int mFolderId;
-    private String mFolderTitle;
-    private BookmarksListAdapter mCursorAdapter = null;
-    private BookmarksQueryTask mQueryTask = null;
-    private boolean mShowReadingList = false;
-
-    @Override
-    public int getTitleStringId() {
-        return R.string.awesomebar_bookmarks_title;
-    }
-
-    @Override
-    public String getTag() {
-        return TAG;
-    }
-
-    public BookmarksTab(Context context) {
-        super(context);
-    }
-
-    @Override
-    public View getView() {
-        if (mView == null) {
-            mView = new ListView(mContext, null);
-            ((Activity)mContext).registerForContextMenu(mView);
-            mView.setTag(TAG);
-            mView.setOnTouchListener(mListListener);
-
-            // We need to add the header before we set the adapter, hence make it null
-            ListView list = (ListView)mView;
-            list.setAdapter(null);
-            list.setAdapter(getCursorAdapter());
-            list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-                @Override
-                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-                    handleItemClick(parent, view, position, id);
-                }
-            });
-
-            if (mShowReadingList) {
-                String title = getResources().getString(R.string.bookmarks_folder_reading_list);
-                getCursorAdapter().moveToChildFolder(Bookmarks.FIXED_READING_LIST_ID, title);
-            } else {
-                BookmarksQueryTask task = getQueryTask();
-                task.execute();
-            }
-        }
-        return (ListView)mView;
-    }
-
-    public void setShowReadingList(boolean showReadingList) {
-        mShowReadingList = showReadingList;
-    }
-
-    @Override
-    public void destroy() {
-        super.destroy();
-        // Can't use getters for adapter. It will create one if null.
-        if (mCursorAdapter != null && mView != null) {
-            ListView list = (ListView)mView;
-            list.setAdapter(null);
-            final Cursor cursor = mCursorAdapter.getCursor();
-            // Gingerbread locks the DB when closing a cursor, so do it in the
-            // background.
-            ThreadUtils.postToBackgroundThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (cursor != null && !cursor.isClosed())
-                        cursor.close();
-                }
-            });
-        }
-    }
-
-    @Override
-    public boolean onBackPressed() {
-        // If the soft keyboard is visible in the bookmarks or history tab, the user
-        // must have explictly brought it up, so we should try hiding it instead of
-        // exiting the activity or going up a bookmarks folder level.
-        if (hideSoftInput(getView()))
-            return true;
-
-        return moveToParentFolder();
-    }
-
-    protected BookmarksListAdapter getCursorAdapter() {
-        return getCursorAdapter(null);
-    }
-
-    protected BookmarksListAdapter getCursorAdapter(Cursor c) {
-        if (mCursorAdapter == null) {
-            mCursorAdapter = new BookmarksListAdapter(mContext, c);
-        } else if (c != null) {
-            mCursorAdapter.changeCursor(c);
-        } else {
-            // do a quick return if just asking for the cached adapter
-            return mCursorAdapter;
-        }
-
-        TextView headerView = mCursorAdapter.getHeaderView();
-        if (headerView == null) {
-            headerView = (TextView) getInflater().inflate(R.layout.awesomebar_header_row, null);
-            mCursorAdapter.setHeaderView(headerView);
-        }
-
-        // Add/Remove header based on the root folder
-        if (mView != null) {
-            ListView list = (ListView)mView;
-            if (mFolderId == Bookmarks.FIXED_ROOT_ID) {
-                if (list.getHeaderViewsCount() == 1) {
-                    list.removeHeaderView(headerView);
-                }
-            } else {
-                if (list.getHeaderViewsCount() == 0) {
-                    list.addHeaderView(headerView, null, true);
-                }
-                headerView.setText(mFolderTitle);
-            }
-        }
-
-        return mCursorAdapter;
-    }
-
-    protected BookmarksQueryTask getQueryTask() {
-        if (mQueryTask == null) {
-            mQueryTask = new BookmarksQueryTask();
-        }
-        return mQueryTask;
-    }
-
-    public void handleItemClick(AdapterView<?> parent, View view, int position, long id) {
-        ListView list = (ListView)getView();
-        if (list == null)
-            return;
-
-        int headerCount = list.getHeaderViewsCount();
-        // If we tap on the header view, there's nothing to do
-        if (headerCount == 1 && position == 0)
-            return;
-
-        BookmarksListAdapter adapter = getCursorAdapter();
-        if (adapter == null)
-            return;
-
-        Cursor cursor = adapter.getCursor();
-        if (cursor == null)
-            return;
-
-        // The header view takes up a spot in the list
-        if (headerCount == 1)
-            position--;
-
-        cursor.moveToPosition(position);
-
-        int type = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE));
-        if (type == Bookmarks.TYPE_FOLDER) {
-            // If we're clicking on a folder, update adapter to move to that folder
-            int folderId = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID));
-            String folderTitle = adapter.getFolderTitle(position);
-
-            adapter.moveToChildFolder(folderId, folderTitle);
-            return;
-        }
-
-        // Otherwise, just open the URL
-        String url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
-        String title = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE));
-        long parentId = cursor.getLong(cursor.getColumnIndexOrThrow(Bookmarks.PARENT));
-        if (parentId == Bookmarks.FIXED_READING_LIST_ID) {
-            url = ReaderModeUtils.getAboutReaderForUrl(url, true);
-        }
-        sendToListener(url, title);
-    }
-
-    private class BookmarksListAdapter extends SimpleCursorAdapter {
-        private static final int VIEW_TYPE_ITEM = 0;
-        private static final int VIEW_TYPE_FOLDER = 1;
-        private static final int VIEW_TYPE_COUNT = 2;
-
-        private LinkedList<Pair<Integer, String>> mParentStack;
-        private TextView mBookmarksTitleView;
-
-        public BookmarksListAdapter(Context context, Cursor c) {
-            super(context, -1, c, new String[] {}, new int[] {});
-
-            // mParentStack holds folder id/title pairs that allow us to navigate
-            // back up the folder heirarchy
-            mParentStack = new LinkedList<Pair<Integer, String>>();
-
-            // Add the root folder to the stack
-            Pair<Integer, String> rootFolder = new Pair<Integer, String>(Bookmarks.FIXED_ROOT_ID, "");
-            mParentStack.addFirst(rootFolder);
-        }
-
-        public void refreshCurrentFolder() {
-            // Cancel any pre-existing async refresh tasks
-            if (mQueryTask != null)
-                mQueryTask.cancel(false);
-
-            Pair<Integer, String> folderPair = mParentStack.getFirst();
-            mQueryTask = new BookmarksQueryTask(folderPair.first, folderPair.second);
-            mQueryTask.execute();
-        }
-
-        // Returns false if there is no parent folder to move to
-        public boolean moveToParentFolder() {
-            // If we're already at the root, we can't move to a parent folder
-            if (mParentStack.size() == 1)
-                return false;
-
-            mParentStack.removeFirst();
-            refreshCurrentFolder();
-            return true;
-        }
-
-        public void moveToChildFolder(int folderId, String folderTitle) {
-            Pair<Integer, String> folderPair = new Pair<Integer, String>(folderId, folderTitle);
-            mParentStack.addFirst(folderPair);
-            refreshCurrentFolder();
-        }
-
-        public boolean isInReadingList() {
-            Pair<Integer, String> folderPair = mParentStack.getFirst();
-            return (folderPair.first == Bookmarks.FIXED_READING_LIST_ID);
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            Cursor c = getCursor();
- 
-            if (c.moveToPosition(position) &&
-                c.getInt(c.getColumnIndexOrThrow(Bookmarks.TYPE)) == Bookmarks.TYPE_FOLDER)
-                return VIEW_TYPE_FOLDER;
-
-            // Default to retuning normal item type
-            return VIEW_TYPE_ITEM;
-        }
- 
-        @Override
-        public int getViewTypeCount() {
-            return VIEW_TYPE_COUNT;
-        }
-
-        public String getFolderTitle(int position) {
-            Cursor c = getCursor();
-            if (!c.moveToPosition(position))
-                return "";
-
-            String guid = c.getString(c.getColumnIndexOrThrow(Bookmarks.GUID));
-
-            // If we don't have a special GUID, just return the folder title from the DB.
-            if (guid == null || guid.length() == 12)
-                return c.getString(c.getColumnIndexOrThrow(Bookmarks.TITLE));
-
-            // Use localized strings for special folder names.
-            if (guid.equals(Bookmarks.FAKE_DESKTOP_FOLDER_GUID))
-                return getResources().getString(R.string.bookmarks_folder_desktop);
-            else if (guid.equals(Bookmarks.MENU_FOLDER_GUID))
-                return getResources().getString(R.string.bookmarks_folder_menu);
-            else if (guid.equals(Bookmarks.TOOLBAR_FOLDER_GUID))
-                return getResources().getString(R.string.bookmarks_folder_toolbar);
-            else if (guid.equals(Bookmarks.UNFILED_FOLDER_GUID))
-                return getResources().getString(R.string.bookmarks_folder_unfiled);
-            else if (guid.equals(Bookmarks.READING_LIST_FOLDER_GUID))
-                return getResources().getString(R.string.bookmarks_folder_reading_list);
-
-            // If for some reason we have a folder with a special GUID, but it's not one of
-            // the special folders we expect in the UI, just return the title from the DB.
-            return c.getString(c.getColumnIndexOrThrow(Bookmarks.TITLE));
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            int viewType = getItemViewType(position);
-            AwesomeEntryViewHolder viewHolder = null;
-
-            if (convertView == null) {
-                if (viewType == VIEW_TYPE_ITEM)
-                    convertView = getInflater().inflate(R.layout.awesomebar_row, null);
-                else
-                    convertView = getInflater().inflate(R.layout.awesomebar_folder_row, null);
-
-                viewHolder = new AwesomeEntryViewHolder();
-                viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
-                viewHolder.faviconView = (FaviconView) convertView.findViewById(R.id.favicon);
-
-                if (viewType == VIEW_TYPE_ITEM)
-                    viewHolder.urlView = (TextView) convertView.findViewById(R.id.url);
-
-                convertView.setTag(viewHolder);
-            } else {
-                viewHolder = (AwesomeEntryViewHolder) convertView.getTag();
-            }
-
-            Cursor cursor = getCursor();
-            if (!cursor.moveToPosition(position))
-                throw new IllegalStateException("Couldn't move cursor to position " + position);
-
-            if (viewType == VIEW_TYPE_ITEM) {
-                updateTitle(viewHolder.titleView, cursor);
-                updateUrl(viewHolder, cursor);
-
-                byte[] b = cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON));
-                Bitmap favicon = null;
-                if (b != null) {
-                    Bitmap bitmap = BitmapUtils.decodeByteArray(b);
-                    if (bitmap != null) {
-                        favicon = Favicons.getInstance().scaleImage(bitmap);
-                    }
-                }
-                String url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
-                updateFavicon(viewHolder.faviconView, favicon, url);
-            } else {
-                viewHolder.titleView.setText(getFolderTitle(position));
-            }
-
-            return convertView;
-        }
-
-        public TextView getHeaderView() {
-            return mBookmarksTitleView;
-        }
-
-        public void setHeaderView(TextView titleView) {
-            mBookmarksTitleView = titleView;
-        }
-    }
-
-    private class BookmarksQueryTask extends AsyncTask<Void, Void, Cursor> {
-        public BookmarksQueryTask() {
-            mFolderId = Bookmarks.FIXED_ROOT_ID;
-            mFolderTitle = "";
-        }
-
-        public BookmarksQueryTask(int folderId, String folderTitle) {
-            mFolderId = folderId;
-            mFolderTitle = folderTitle;
-        }
-
-        @Override
-        protected Cursor doInBackground(Void... arg0) {
-            return BrowserDB.getBookmarksInFolder(getContentResolver(), mFolderId);
-        }
-
-        @Override
-        protected void onPostExecute(final Cursor cursor) {
-            // Hack: force this to the main thread, even though it should already be on it
-            ThreadUtils.postToUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    // this will update the cursorAdapter to use the new one if it already exists
-                    // We need to add the header before we set the adapter, hence make it null
-                    ListView list = (ListView)mView;
-                    list.setAdapter(null);
-                    list.setAdapter(getCursorAdapter(cursor));
-                }
-            });
-            mQueryTask = null;
-        }
-    }
-
-    public boolean moveToParentFolder() {
-        // If we're not in the bookmarks tab, we have nothing to do. We should
-        // also return false if mBookmarksAdapter hasn't been initialized yet.
-        BookmarksListAdapter adapter = getCursorAdapter();
-        if (adapter == null)
-            return false;
-
-        return adapter.moveToParentFolder();
-    }
-
-    /**
-     * Whether the user is in the Reading List bookmarks directory in the
-     * AwesomeScreen UI.
-     */
-    public boolean isInReadingList() {
-        if (mCursorAdapter == null)
-            return false;
-
-        return mCursorAdapter.isInReadingList();
-    }
-
-    @Override
-    public ContextMenuSubject getSubject(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
-        ContextMenuSubject subject = null;
-
-        if (!(menuInfo instanceof AdapterView.AdapterContextMenuInfo)) {
-            Log.e(LOGTAG, "menuInfo is not AdapterContextMenuInfo");
-            return subject;
-        }
-
-        ListView list = (ListView)view;
-        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
-        Object selectedItem = list.getItemAtPosition(info.position);
-
-        if (!(selectedItem instanceof Cursor)) {
-            Log.e(LOGTAG, "item at " + info.position + " is not a Cursor");
-            return subject;
-        }
-
-        Cursor cursor = (Cursor) selectedItem;
-
-        // Don't show the context menu for folders
-        if (!(cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE)) == Bookmarks.TYPE_FOLDER)) {
-            String keyword = null;
-            int keywordCol = cursor.getColumnIndex(URLColumns.KEYWORD);
-            if (keywordCol != -1)
-                keyword = cursor.getString(keywordCol);
-
-            int id = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID));
-
-            subject = new ContextMenuSubject(id,
-                                            cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL)),
-                                            cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON)),
-                                            cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE)),
-                                            keyword,
-                                            isInReadingList() ? Combined.DISPLAY_READER : Combined.DISPLAY_NORMAL);
-        }
-
-        if (subject == null)
-            return subject;
-
-        setupMenu(menu, subject);
-        
-        menu.findItem(R.id.remove_history).setVisible(false);
-        menu.findItem(R.id.open_in_reader).setVisible(false);
-
-        return subject;
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/awesomebar/HistoryTab.java
+++ /dev/null
@@ -1,455 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.AwesomeBar.ContextMenuSubject;
-import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.BrowserDB.URLColumns;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.widget.FaviconView;
-
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.os.AsyncTask;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.KeyEvent;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ExpandableListView;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.SimpleExpandableListAdapter;
-import android.widget.TextView;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-public class HistoryTab extends AwesomeBarTab {
-    public static final String LOGTAG = "HISTORY_TAB";
-    public static final String TAG = "history";
-    private static enum HistorySection { TODAY, YESTERDAY, WEEK, OLDER };
-    private ContentObserver mContentObserver;
-    private ContentResolver mContentResolver;
-    private HistoryQueryTask mQueryTask = null;
-    private HistoryListAdapter mCursorAdapter = null;
-
-    public HistoryTab(Context context) {
-        super(context);
-        mContentObserver = null;
-    }
-
-    @Override
-    public int getTitleStringId() {
-        return R.string.awesomebar_history_title;
-    }
-
-    @Override
-    public String getTag() {
-        return TAG;
-    }
-
-    @Override
-    public ListView getView() {
-        if (mView == null) {
-            mView = new ExpandableListView(mContext, null);
-            ((Activity)mContext).registerForContextMenu(mView);
-            mView.setTag(TAG);
-
-            ExpandableListView list = (ExpandableListView)mView;
-            list.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
-                @Override
-                public boolean onChildClick(ExpandableListView parent, View view,
-                                             int groupPosition, int childPosition, long id) {
-                    return handleItemClick(groupPosition, childPosition);
-                }
-            });
-
-            // This is to disallow collapsing the expandable groups in the
-            // history expandable list view to mimic simpler sections. We should
-            // Remove this if we decide to allow expanding/collapsing groups.
-            list.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
-                @Override
-                public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
-                    return true;
-                }
-            });
-            list.setOnKeyListener(new View.OnKeyListener() {
-                @Override public boolean onKey(View v, int keyCode, KeyEvent event) {
-                    if (GamepadUtils.isActionKeyDown(event)) {
-                        ExpandableListView expando = (ExpandableListView)v;
-                        long selected = expando.getSelectedPosition();
-                        switch (ExpandableListView.getPackedPositionType(selected)) {
-                        case ExpandableListView.PACKED_POSITION_TYPE_CHILD:
-                            return handleItemClick(ExpandableListView.getPackedPositionGroup(selected),
-                                                   ExpandableListView.getPackedPositionChild(selected));
-                        case ExpandableListView.PACKED_POSITION_TYPE_GROUP:
-                            int group = ExpandableListView.getPackedPositionGroup(selected);
-                            return (expando.isGroupExpanded(group)
-                                ? expando.collapseGroup(group)
-                                : expando.expandGroup(group));
-                        }
-                    }
-                    return false;
-                }
-            });
-
-            mView.setOnTouchListener(mListListener);
-
-            // We need to add the header before we set the adapter, hence make it null
-            list.setAdapter(getCursorAdapter());
-            HistoryQueryTask task = new HistoryQueryTask();
-            task.execute();
-        }
-        return (ListView)mView;
-    }
-
-    @Override
-    public void destroy() {
-        super.destroy();
-
-        if (mContentObserver != null)
-            BrowserDB.unregisterContentObserver(getContentResolver(), mContentObserver);
-    }
-
-    @Override
-    public boolean onBackPressed() {
-        // If the soft keyboard is visible in the bookmarks or history tab, the user
-        // must have explictly brought it up, so we should try hiding it instead of
-        // exiting the activity or going up a bookmarks folder level.
-        View view = getView();
-        if (hideSoftInput(view))
-            return true;
-
-        return false;
-    }
-
-    protected HistoryListAdapter getCursorAdapter() {
-        return mCursorAdapter;
-    }
-
-    private class HistoryListAdapter extends SimpleExpandableListAdapter {
-        public HistoryListAdapter(Context context, List<? extends Map<String, ?>> groupData,
-                int groupLayout, String[] groupFrom, int[] groupTo,
-                List<? extends List<? extends Map<String, ?>>> childData) {
-
-            super(context, groupData, groupLayout, groupFrom, groupTo,
-                  childData, -1, new String[] {}, new int[] {});
-        }
-
-        @Override
-        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
-                View convertView, ViewGroup parent) {
-            AwesomeEntryViewHolder viewHolder = null;
-
-            if (convertView == null) {
-                convertView = getInflater().inflate(R.layout.awesomebar_row, null);
-
-                viewHolder = new AwesomeEntryViewHolder();
-                viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
-                viewHolder.urlView = (TextView) convertView.findViewById(R.id.url);
-                viewHolder.faviconView = (FaviconView) convertView.findViewById(R.id.favicon);
-                viewHolder.bookmarkIconView = (ImageView) convertView.findViewById(R.id.bookmark_icon);
-
-                convertView.setTag(viewHolder);
-            } else {
-                viewHolder = (AwesomeEntryViewHolder) convertView.getTag();
-            }
-
-            HistoryListAdapter adapter = getCursorAdapter();
-            if (adapter == null)
-                return null;
-
-            @SuppressWarnings("unchecked")
-            Map<String,Object> historyItem =
-                    (Map<String,Object>) adapter.getChild(groupPosition, childPosition);
-
-            String title = (String) historyItem.get(URLColumns.TITLE);
-            String url = (String) historyItem.get(URLColumns.URL);
-
-            updateTitle(viewHolder.titleView, title, url);
-            updateUrl(viewHolder, url);
-
-            byte[] b = (byte[]) historyItem.get(URLColumns.FAVICON);
-            Bitmap favicon = null;
-
-            if (b != null) {
-                Bitmap bitmap = BitmapUtils.decodeByteArray(b);
-                if (bitmap != null) {
-                    favicon = Favicons.getInstance().scaleImage(bitmap);
-                }
-            }
-            updateFavicon(viewHolder.faviconView, favicon, url);
-
-            Integer bookmarkId = (Integer) historyItem.get(Combined.BOOKMARK_ID);
-            Integer display = (Integer) historyItem.get(Combined.DISPLAY);
-
-            // The bookmark id will be 0 (null in database) when the url
-            // is not a bookmark. Reading list items are irrelevant in history
-            // tab. We should never show any sign or them.
-            int visibility = (bookmarkId != 0 && display != Combined.DISPLAY_READER ?
-                              View.VISIBLE : View.GONE);
-
-            viewHolder.bookmarkIconView.setVisibility(visibility);
-            viewHolder.bookmarkIconView.setImageResource(R.drawable.ic_awesomebar_star);
-
-            return convertView;
-        }
-    }
-
-    private static class GroupList extends LinkedList<Map<String,String>> {
-        private static final long serialVersionUID = 0L;
-    }
-
-    private static class ChildrenList extends LinkedList<Map<String,Object>> {
-        private static final long serialVersionUID = 0L;
-    }
-
-    private class HistoryQueryTask extends AsyncTask<Void, Void, Pair<GroupList,List<ChildrenList>>> {
-        private static final long MS_PER_DAY = 86400000;
-        private static final long MS_PER_WEEK = MS_PER_DAY * 7;
-
-        @Override
-        protected Pair<GroupList,List<ChildrenList>> doInBackground(Void... arg0) {
-            Cursor cursor = BrowserDB.getRecentHistory(getContentResolver(), MAX_RESULTS);
-
-            Date now = new Date();
-            now.setHours(0);
-            now.setMinutes(0);
-            now.setSeconds(0);
-
-            long today = now.getTime();
-
-            // Split the list of urls into separate date range groups
-            // and show it in an expandable list view.
-            List<ChildrenList> childrenLists = new LinkedList<ChildrenList>();
-            ChildrenList children = null;
-            GroupList groups = new GroupList();
-            HistorySection section = null;
-
-            // Move cursor before the first row in preparation
-            // for the iteration.
-            cursor.moveToPosition(-1);
-
-            // Split the history query results into adapters per time
-            // section (today, yesterday, week, older). Queries on content
-            // Browser content provider don't support limitting the number
-            // of returned rows so we limit it here.
-            while (cursor.moveToNext()) {
-                long time = cursor.getLong(cursor.getColumnIndexOrThrow(URLColumns.DATE_LAST_VISITED));
-                HistorySection itemSection = getSectionForTime(time, today);
-
-                if (section != itemSection) {
-                    if (section != null) {
-                        groups.add(createGroupItem(section));
-                        childrenLists.add(children);
-                    }
-
-                    section = itemSection;
-                    children = new ChildrenList();
-                }
-
-                children.add(createHistoryItem(cursor));
-            }
-
-            // Add any remaining section to the list if it hasn't
-            // been added to the list after the loop.
-            if (section != null && children != null) {
-                groups.add(createGroupItem(section));
-                childrenLists.add(children);
-            }
-
-            // Close the query cursor as we won't use it anymore
-            cursor.close();
-
-            // groups and childrenLists will be empty lists if there's no history
-            return Pair.<GroupList,List<ChildrenList>>create(groups, childrenLists);
-        }
-
-        public Map<String,Object> createHistoryItem(Cursor cursor) {
-            Map<String,Object> historyItem = new HashMap<String,Object>();
-
-            String url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
-            String title = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE));
-            byte[] favicon = cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON));
-            Integer bookmarkId = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.BOOKMARK_ID));
-            Integer historyId = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.HISTORY_ID));
-            Integer display = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.DISPLAY));
-
-            // Use the URL instead of an empty title for consistency with the normal URL
-            // bar view - this is the equivalent of getDisplayTitle() in Tab.java
-            if (title == null || title.length() == 0)
-                title = url;
-
-            historyItem.put(URLColumns.URL, url);
-            historyItem.put(URLColumns.TITLE, title);
-
-            if (favicon != null)
-                historyItem.put(URLColumns.FAVICON, favicon);
-
-            historyItem.put(Combined.BOOKMARK_ID, bookmarkId);
-            historyItem.put(Combined.HISTORY_ID, historyId);
-            historyItem.put(Combined.DISPLAY, display);
-
-            return historyItem;
-        }
-
-        public Map<String,String> createGroupItem(HistorySection section) {
-            Map<String,String> groupItem = new HashMap<String,String>();
-
-            groupItem.put(URLColumns.TITLE, getSectionName(section));
-
-            return groupItem;
-        }
-
-        private String getSectionName(HistorySection section) {
-            Resources resources = mContext.getResources();
-
-            switch (section) {
-            case TODAY:
-                return resources.getString(R.string.history_today_section);
-            case YESTERDAY:
-                return resources.getString(R.string.history_yesterday_section);
-            case WEEK:
-                return resources.getString(R.string.history_week_section);
-            case OLDER:
-                return resources.getString(R.string.history_older_section);
-            }
-
-            return null;
-        }
-
-        private void expandAllGroups(ExpandableListView historyList) {
-            int groupCount = mCursorAdapter.getGroupCount();
-
-            for (int i = 0; i < groupCount; i++) {
-                historyList.expandGroup(i);
-            }
-        }
-
-        private HistorySection getSectionForTime(long time, long today) {
-            long delta = today - time;
-
-            if (delta < 0) {
-                return HistorySection.TODAY;
-            }
-
-            if (delta < MS_PER_DAY) {
-                return HistorySection.YESTERDAY;
-            }
-
-            if (delta < MS_PER_WEEK) {
-                return HistorySection.WEEK;
-            }
-
-            return HistorySection.OLDER;
-        }
-
-        @Override
-        protected void onPostExecute(Pair<GroupList,List<ChildrenList>> result) {
-            mCursorAdapter = new HistoryListAdapter(
-                mContext,
-                result.first,
-                R.layout.awesomebar_header_row,
-                new String[] { URLColumns.TITLE },
-                new int[] { R.id.title },
-                result.second
-            );
-
-            if (mContentObserver == null) {
-                // Register an observer to update the history tab contents if they change.
-                mContentObserver = new ContentObserver(ThreadUtils.getBackgroundHandler()) {
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        mQueryTask = new HistoryQueryTask();
-                        mQueryTask.execute();
-                    }
-                };
-                BrowserDB.registerHistoryObserver(getContentResolver(), mContentObserver);
-            }
-
-            final ExpandableListView historyList = (ExpandableListView)getView();
-
-            // Hack: force this to the main thread, even though it should already be on it
-            ThreadUtils.postToUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    historyList.setAdapter(mCursorAdapter);
-                    expandAllGroups(historyList);
-                }
-            });
-
-            mQueryTask = null;
-        }
-    }
-
-    public boolean handleItemClick(int groupPosition, int childPosition) {
-        HistoryListAdapter adapter = getCursorAdapter();
-        if (adapter == null)
-            return false;
-
-        @SuppressWarnings("unchecked")
-        Map<String,Object> historyItem = (Map<String,Object>) adapter.getChild(groupPosition, childPosition);
-
-        String url = (String) historyItem.get(URLColumns.URL);
-        String title = (String) historyItem.get(URLColumns.TITLE);
-        sendToListener(url, title);
-
-        return true;
-    }
-
-    @Override
-    public ContextMenuSubject getSubject(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
-        ContextMenuSubject subject = null;
-
-        if (!(menuInfo instanceof ExpandableListView.ExpandableListContextMenuInfo)) {
-            Log.e(LOGTAG, "menuInfo is not ExpandableListContextMenuInfo");
-            return subject;
-        }
-
-        ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
-        int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);
-        int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
-
-        // Check if long tap is on a header row
-        if (groupPosition < 0 || childPosition < 0)
-            return subject;
-
-        ExpandableListView exList = (ExpandableListView) view;
-
-        // The history list is backed by a SimpleExpandableListAdapter
-        @SuppressWarnings("rawtypes")
-        Map map = (Map) exList.getExpandableListAdapter().getChild(groupPosition, childPosition);
-        subject = new AwesomeBar.ContextMenuSubject((Integer) map.get(Combined.HISTORY_ID),
-                                                     (String) map.get(URLColumns.URL),
-                                                     (byte[]) map.get(URLColumns.FAVICON),
-                                                     (String) map.get(URLColumns.TITLE),
-                                                     null);
-
-        setupMenu(menu, subject);
-
-        menu.findItem(R.id.remove_bookmark).setVisible(false);
-        menu.findItem(R.id.edit_bookmark).setVisible(false);
-        menu.findItem(R.id.open_in_reader).setVisible(false);
-
-        return subject;
-    }
-}
--- a/mobile/android/base/db/BrowserDB.java
+++ b/mobile/android/base/db/BrowserDB.java
@@ -82,16 +82,18 @@ public class BrowserDB {
         public void updateBookmark(ContentResolver cr, int id, String uri, String title, String keyword);
 
         public void addReadingListItem(ContentResolver cr, String title, String uri);
 
         public void removeReadingListItemWithURL(ContentResolver cr, String uri);
 
         public Bitmap getFaviconForUrl(ContentResolver cr, String uri);
 
+        public byte[] getFaviconBytesForUrl(ContentResolver cr, String uri);
+
         public Cursor getFaviconsForUrls(ContentResolver cr, List<String> urls);
 
         public String getFaviconUrlForHistoryUrl(ContentResolver cr, String url);
 
         public void updateFaviconForUrl(ContentResolver cr, String pageUri, Bitmap favicon, String faviconUri);
 
         public void updateThumbnailForUrl(ContentResolver cr, String uri, BitmapDrawable thumbnail);
 
@@ -232,16 +234,20 @@ public class BrowserDB {
     public static void removeReadingListItemWithURL(ContentResolver cr, String uri) {
         sDb.removeReadingListItemWithURL(cr, uri);
     }
 
     public static Bitmap getFaviconForUrl(ContentResolver cr, String uri) {
         return sDb.getFaviconForUrl(cr, uri);
     }
 
+    public static byte[] getFaviconBytesForUrl(ContentResolver cr, String uri) {
+        return sDb.getFaviconBytesForUrl(cr, uri);
+    }
+
     public static Cursor getFaviconsForUrls(ContentResolver cr, List<String> urls) {
         return sDb.getFaviconsForUrls(cr, urls);
     }
 
     public static String getFaviconUrlForHistoryUrl(ContentResolver cr, String url) {
         return sDb.getFaviconUrlForHistoryUrl(cr, url);
     }
 
--- a/mobile/android/base/db/LocalBrowserDB.java
+++ b/mobile/android/base/db/LocalBrowserDB.java
@@ -17,16 +17,17 @@ import org.mozilla.gecko.db.BrowserContr
 import org.mozilla.gecko.gfx.BitmapUtils;
 
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.database.CursorWrapper;
+import android.database.DatabaseUtils;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.net.Uri;
 import android.provider.Browser;
 import android.text.TextUtils;
 import android.util.Log;
 
 import java.io.ByteArrayOutputStream;
@@ -47,17 +48,16 @@ public class LocalBrowserDB implements B
 
     private final String mProfile;
 
     // Map of folder GUIDs to IDs. Used for caching.
     private HashMap<String, Long> mFolderIdMap;
 
     // Use wrapped Boolean so that we can have a null state
     private Boolean mDesktopBookmarksExist;
-    private Boolean mReadingListItemsExist;
 
     private final Uri mBookmarksUriWithProfile;
     private final Uri mParentsUriWithProfile;
     private final Uri mHistoryUriWithProfile;
     private final Uri mHistoryExpireUriWithProfile;
     private final Uri mCombinedUriWithProfile;
     private final Uri mDeletedHistoryUriWithProfile;
     private final Uri mUpdateHistoryUriWithProfile;
@@ -65,25 +65,22 @@ public class LocalBrowserDB implements B
     private final Uri mThumbnailsUriWithProfile;
 
     private static final String[] DEFAULT_BOOKMARK_COLUMNS =
             new String[] { Bookmarks._ID,
                            Bookmarks.GUID,
                            Bookmarks.URL,
                            Bookmarks.TITLE,
                            Bookmarks.TYPE,
-                           Bookmarks.PARENT,
-                           Bookmarks.KEYWORD,
-                           Bookmarks.FAVICON }; 
+                           Bookmarks.PARENT };
 
     public LocalBrowserDB(String profile) {
         mProfile = profile;
         mFolderIdMap = new HashMap<String, Long>();
         mDesktopBookmarksExist = null;
-        mReadingListItemsExist = null;
 
         mBookmarksUriWithProfile = appendProfile(Bookmarks.CONTENT_URI);
         mParentsUriWithProfile = appendProfile(Bookmarks.PARENTS_CONTENT_URI);
         mHistoryUriWithProfile = appendProfile(History.CONTENT_URI);
         mHistoryExpireUriWithProfile = appendProfile(History.CONTENT_OLD_URI);
         mCombinedUriWithProfile = appendProfile(Combined.CONTENT_URI);
         mFaviconsUriWithProfile = appendProfile(Favicons.CONTENT_URI);
         mThumbnailsUriWithProfile = appendProfile(Thumbnails.CONTENT_URI);
@@ -95,17 +92,16 @@ public class LocalBrowserDB implements B
             appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").
             appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build();
     }
 
     // Invalidate cached data
     @Override
     public void invalidateCachedState() {
         mDesktopBookmarksExist = null;
-        mReadingListItemsExist = null;
     }
 
     private Uri historyUriWithLimit(int limit) {
         return mHistoryUriWithProfile.buildUpon().appendQueryParameter(BrowserContract.PARAM_LIMIT,
                                                                        String.valueOf(limit)).build();
     }
 
     private Uri bookmarksUriWithLimit(int limit) {
@@ -327,17 +323,16 @@ public class LocalBrowserDB implements B
     @Override
     public Cursor getRecentHistory(ContentResolver cr, int limit) {
         Cursor c = cr.query(combinedUriWithLimit(limit),
                             new String[] { Combined._ID,
                                            Combined.BOOKMARK_ID,
                                            Combined.HISTORY_ID,
                                            Combined.URL,
                                            Combined.TITLE,
-                                           Combined.FAVICON,
                                            Combined.DISPLAY,
                                            Combined.DATE_LAST_VISITED,
                                            Combined.VISITS },
                             History.DATE_LAST_VISITED + " > 0",
                             null,
                             History.DATE_LAST_VISITED + " DESC");
 
         return new LocalDBCursor(c);
@@ -368,29 +363,24 @@ public class LocalBrowserDB implements B
     public void clearHistory(ContentResolver cr) {
         cr.delete(mHistoryUriWithProfile, null, null);
     }
 
     @Override
     public Cursor getBookmarksInFolder(ContentResolver cr, long folderId) {
         Cursor c = null;
         boolean addDesktopFolder = false;
-        boolean addReadingListFolder = false;
 
         // We always want to show mobile bookmarks in the root view.
         if (folderId == Bookmarks.FIXED_ROOT_ID) {
             folderId = getFolderIdFromGuid(cr, Bookmarks.MOBILE_FOLDER_GUID);
 
             // We'll add a fake "Desktop Bookmarks" folder to the root view if desktop 
             // bookmarks exist, so that the user can still access non-mobile bookmarks.
             addDesktopFolder = desktopBookmarksExist(cr);
-
-            // We'll add the Reading List folder to the root view if any reading
-            // list items exist.
-            addReadingListFolder = readingListItemsExist(cr);
         }
 
         if (folderId == Bookmarks.FAKE_DESKTOP_FOLDER_ID) {
             // Since the "Desktop Bookmarks" folder doesn't actually exist, we
             // just fake it by querying specifically certain known desktop folders.
             c = cr.query(mBookmarksUriWithProfile,
                          DEFAULT_BOOKMARK_COLUMNS,
                          Bookmarks.GUID + " = ? OR " +
@@ -408,19 +398,19 @@ public class LocalBrowserDB implements B
                          Bookmarks.PARENT + " = ? AND " +
                          "(" + Bookmarks.TYPE + " = ? OR " + Bookmarks.TYPE + " = ?)",
                          new String[] { String.valueOf(folderId),
                                         String.valueOf(Bookmarks.TYPE_BOOKMARK),
                                         String.valueOf(Bookmarks.TYPE_FOLDER) },
                          null);
         }
 
-        if (addDesktopFolder || addReadingListFolder) {
+        if (addDesktopFolder) {
             // Wrap cursor to add fake desktop bookmarks and reading list folders
-            c = new SpecialFoldersCursorWrapper(c, addDesktopFolder, addReadingListFolder);
+            c = new SpecialFoldersCursorWrapper(c, addDesktopFolder);
         }
 
         return new LocalDBCursor(c);
     }
 
     // Returns true if any desktop bookmarks exist, which will be true if the user
     // has set up sync at one point, or done a profile migration from XUL fennec.
     private boolean desktopBookmarksExist(ContentResolver cr) {
@@ -447,39 +437,16 @@ public class LocalBrowserDB implements B
                 c.close();
         }
 
         // Cache result for future queries
         mDesktopBookmarksExist = (count > 0);
         return mDesktopBookmarksExist;
     }
 
-    private boolean readingListItemsExist(ContentResolver cr) {
-        if (mReadingListItemsExist != null)
-            return mReadingListItemsExist;
-
-        Cursor c = null;
-        int count = 0;
-        try {
-            c = cr.query(bookmarksUriWithLimit(1),
-                         new String[] { Bookmarks._ID },
-                         Bookmarks.PARENT + " = ?",
-                         new String[] { String.valueOf(Bookmarks.FIXED_READING_LIST_ID) },
-                         null);
-            count = c.getCount();
-        } finally {
-            if (c != null)
-                c.close();
-        }
-
-        // Cache result for future queries
-        mReadingListItemsExist = (count > 0);
-        return mReadingListItemsExist;
-    }
-
     @Override
     public int getReadingListCount(ContentResolver cr) {
         // This method is about the Reading List, not normal bookmarks
         Cursor c = null;
         try {
             c = cr.query(mBookmarksUriWithProfile,
                          new String[] { Bookmarks._ID },
                          Bookmarks.PARENT + " = ?",
@@ -722,40 +689,49 @@ public class LocalBrowserDB implements B
         cr.update(mBookmarksUriWithProfile,
                   values,
                   Bookmarks._ID + " = ?",
                   new String[] { String.valueOf(id) });
     }
 
     @Override
     public Bitmap getFaviconForUrl(ContentResolver cr, String uri) {
+        final byte[] b = getFaviconBytesForUrl(cr, uri);
+        if (b == null) {
+            return null;
+        }
+
+        return BitmapUtils.decodeByteArray(b);
+    }
+
+    @Override
+    public byte[] getFaviconBytesForUrl(ContentResolver cr, String uri) {
         Cursor c = null;
         byte[] b = null;
 
         try {
             c = cr.query(mCombinedUriWithProfile,
                          new String[] { Combined.FAVICON },
                          Combined.URL + " = ?",
                          new String[] { uri },
                          null);
 
-            if (c.moveToFirst()) {
-                int faviconIndex = c.getColumnIndexOrThrow(Combined.FAVICON);
-                b = c.getBlob(faviconIndex);
+            if (!c.moveToFirst()) {
+                return null;
             }
+
+            final int faviconIndex = c.getColumnIndexOrThrow(Combined.FAVICON);
+            b = c.getBlob(faviconIndex);
         } finally {
-            if (c != null)
+            if (c != null) {
                 c.close();
+            }
         }
 
-        if (b == null) {
-            return null;
-        }
-
-        return BitmapUtils.decodeByteArray(b);
+        return b;
     }
 
     @Override
     public String getFaviconUrlForHistoryUrl(ContentResolver cr, String uri) {
         Cursor c = null;
 
         try {
             c = cr.query(mHistoryUriWithProfile,
@@ -772,33 +748,33 @@ public class LocalBrowserDB implements B
         }
 
         return null;
     }
 
     @Override
     public Cursor getFaviconsForUrls(ContentResolver cr, List<String> urls) {
         StringBuilder selection = new StringBuilder();
-        String[] selectionArgs = new String[urls.size()];
+        selection.append(Favicons.URL + " IN (");
 
         for (int i = 0; i < urls.size(); i++) {
-          final String url = urls.get(i);
+            final String url = urls.get(i);
+
+            if (i > 0)
+                selection.append(", ");
 
-          if (i > 0)
-            selection.append(" OR ");
+            DatabaseUtils.appendEscapedSQLString(selection, url);
+        }
 
-          selection.append(Favicons.URL + " = ?");
-          selectionArgs[i] = url;
-        }
+        selection.append(")");
 
         return cr.query(mCombinedUriWithProfile,
                         new String[] { Combined.URL, Combined.FAVICON },
                         selection.toString(),
-                        selectionArgs,
-                        null);
+                        null, null);
     }
 
     @Override
     public void updateFaviconForUrl(ContentResolver cr, String pageUri,
             Bitmap favicon, String faviconUri) {
         ContentValues values = new ContentValues();
         values.put(Favicons.URL, faviconUri);
         values.put(Favicons.PAGE_URL, pageUri);
@@ -1068,96 +1044,78 @@ public class LocalBrowserDB implements B
     }
 
     // This wrapper adds a fake "Desktop Bookmarks" folder entry to the
     // beginning of the cursor's data set.
     private class SpecialFoldersCursorWrapper extends CursorWrapper {
         private int mIndexOffset;
 
         private int mDesktopBookmarksIndex = -1;
-        private int mReadingListIndex = -1;
 
         private boolean mAtDesktopBookmarksPosition = false;
-        private boolean mAtReadingListPosition = false;
 
-        public SpecialFoldersCursorWrapper(Cursor c, boolean showDesktopBookmarks, boolean showReadingList) {
+        public SpecialFoldersCursorWrapper(Cursor c, boolean showDesktopBookmarks) {
             super(c);
 
             mIndexOffset = 0;
 
             if (showDesktopBookmarks) {
                 mDesktopBookmarksIndex = mIndexOffset;
                 mIndexOffset++;
             }
-
-            if (showReadingList) {
-                mReadingListIndex = mIndexOffset;
-                mIndexOffset++;
-            }
         }
 
         @Override
         public int getCount() {
             return super.getCount() + mIndexOffset;
         }
 
         @Override
         public boolean moveToPosition(int position) {
             mAtDesktopBookmarksPosition = (mDesktopBookmarksIndex == position);
-            mAtReadingListPosition = (mReadingListIndex == position);
 
-            if (mAtDesktopBookmarksPosition || mAtReadingListPosition)
+            if (mAtDesktopBookmarksPosition)
                 return true;
 
             return super.moveToPosition(position - mIndexOffset);
         }
 
         @Override
         public long getLong(int columnIndex) {
-            if (!mAtDesktopBookmarksPosition && !mAtReadingListPosition)
+            if (!mAtDesktopBookmarksPosition)
                 return super.getLong(columnIndex);
 
             if (columnIndex == getColumnIndex(Bookmarks.PARENT)) {
                 return Bookmarks.FIXED_ROOT_ID;
             }
 
             return -1;
         }
 
         @Override
         public int getInt(int columnIndex) {
-            if (!mAtDesktopBookmarksPosition && !mAtReadingListPosition)
+            if (!mAtDesktopBookmarksPosition)
                 return super.getInt(columnIndex);
 
-            if (columnIndex == getColumnIndex(Bookmarks._ID)) {
-                if (mAtDesktopBookmarksPosition) {
+            if (columnIndex == getColumnIndex(Bookmarks._ID) && mAtDesktopBookmarksPosition)
                     return Bookmarks.FAKE_DESKTOP_FOLDER_ID;
-                } else if (mAtReadingListPosition) {
-                    return Bookmarks.FIXED_READING_LIST_ID;
-                }
-            }
 
             if (columnIndex == getColumnIndex(Bookmarks.TYPE))
                 return Bookmarks.TYPE_FOLDER;
 
             return -1;
         }
 
         @Override
         public String getString(int columnIndex) {
-            if (!mAtDesktopBookmarksPosition && !mAtReadingListPosition)
+            if (!mAtDesktopBookmarksPosition)
                 return super.getString(columnIndex);
 
-            if (columnIndex == getColumnIndex(Bookmarks.GUID)) {
-                if (mAtDesktopBookmarksPosition) {
+            if (columnIndex == getColumnIndex(Bookmarks.GUID) && mAtDesktopBookmarksPosition)
                     return Bookmarks.FAKE_DESKTOP_FOLDER_GUID;
-                } else if (mAtReadingListPosition) {
-                    return Bookmarks.READING_LIST_FOLDER_GUID;
-                }
-            }
 
             return "";
         }
     }
 
     private static class LocalDBCursor extends CursorWrapper {
         public LocalDBCursor(Cursor c) {
             super(c);
--- a/mobile/android/base/gfx/LayerView.java
+++ b/mobile/android/base/gfx/LayerView.java
@@ -260,25 +260,25 @@ public class LayerView extends FrameLayo
         if (shouldUseTextureView()) {
             mTextureView = new TextureView(getContext());
             mTextureView.setSurfaceTextureListener(new SurfaceTextureListener());
 
             // The background is set to this color when the LayerView is
             // created, and it will be shown immediately at startup. Shortly
             // after, the tab's background color will be used before any content
             // is shown.
-            mTextureView.setBackgroundResource(R.color.background_normal);
+            mTextureView.setBackgroundColor(Color.WHITE);
             addView(mTextureView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
         } else {
             // This will stop PropertyAnimator from creating a drawing cache (i.e. a bitmap)
             // from a SurfaceView, which is just not possible (the bitmap will be transparent).
             setWillNotCacheDrawing(false);
 
             mSurfaceView = new LayerSurfaceView(getContext(), this);
-            mSurfaceView.setBackgroundResource(R.color.background_normal);
+            mSurfaceView.setBackgroundColor(Color.WHITE);
             addView(mSurfaceView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
 
             SurfaceHolder holder = mSurfaceView.getHolder();
             holder.addCallback(new SurfaceListener());
             holder.setFormat(PixelFormat.RGB_565);
         }
     }
 
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/home/BookmarkFolderView.java
@@ -0,0 +1,55 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.home;
+
+import org.mozilla.gecko.R;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+public class BookmarkFolderView extends TextView {
+    private static final int[] STATE_OPEN = { R.attr.state_open };
+
+    private boolean mIsOpen = false;
+
+    public BookmarkFolderView(Context context) {
+        super(context);
+    }
+
+    public BookmarkFolderView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public BookmarkFolderView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    public int[] onCreateDrawableState(int extraSpace) {
+        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+
+        if (mIsOpen) {
+            mergeDrawableStates(drawableState, STATE_OPEN);
+        }
+
+        return drawableState;
+    }
+
+    public void open() {
+        if (!mIsOpen) {
+            mIsOpen = true;
+            refreshDrawableState();
+        }
+    }
+
+    public void close() {
+        if (mIsOpen) {
+            mIsOpen = false;
+            refreshDrawableState();
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/home/BookmarkThumbnailView.java
@@ -0,0 +1,102 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.home;
+
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.ThumbnailHelper;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+/**
+ * A height constrained ImageView to show thumbnails of top bookmarks.
+ */
+public class BookmarkThumbnailView extends ImageView {
+    private static final String LOGTAG = "GeckoBookmarkThumbnailView";
+
+    // 27.34% opacity filter for the dominant color.
+    private static final int COLOR_FILTER = 0x46FFFFFF;
+
+    // Default filter color for "Add a bookmark" views.
+    private static final int DEFAULT_COLOR = 0x46ECF0F3;
+
+    // Stroke width for the border.
+    private final float mStrokeWidth = getResources().getDisplayMetrics().density * 2;
+
+    // Paint for drawing the border.
+    private static Paint sBorderPaint;
+
+    // Initializing the static border paint.
+    static {
+        sBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        sBorderPaint.setColor(0xFFCFD9E1);
+        sBorderPaint.setStyle(Paint.Style.STROKE);
+    }
+
+    public BookmarkThumbnailView(Context context) {
+        this(context, null);
+
+        // A border will be drawn if needed.
+        setWillNotDraw(false);
+    }
+
+    public BookmarkThumbnailView(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.bookmarkThumbnailViewStyle);
+    }
+
+    public BookmarkThumbnailView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Measure the view to determine the measured width and height.
+     * The height is constrained by the measured width.
+     *
+     * @param widthMeasureSpec horizontal space requirements as imposed by the parent.
+     * @param heightMeasureSpec vertical space requirements as imposed by the parent, but ignored.
+     */
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // Default measuring.
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        // Force the height based on the aspect ratio.
+        final int width = getMeasuredWidth();
+        final int height = (int) (width * ThumbnailHelper.THUMBNAIL_ASPECT_RATIO);
+        setMeasuredDimension(width, height);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        if (getBackground() == null) {
+            sBorderPaint.setStrokeWidth(mStrokeWidth);
+            canvas.drawRect(0, 0, getWidth(), getHeight(), sBorderPaint);
+        }
+    }
+
+    /**
+     * Sets the background to a Drawable by applying the specified color as a filter.
+     *
+     * @param color the color filter to apply over the drawable.
+     */
+    @Override
+    public void setBackgroundColor(int color) {
+        int colorFilter = color == 0 ? DEFAULT_COLOR : color & COLOR_FILTER;
+        Drawable drawable = getResources().getDrawable(R.drawable.bookmark_thumbnail_bg);
+        drawable.setColorFilter(colorFilter, Mode.SRC_ATOP);
+        setBackgroundDrawable(drawable);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/home/BookmarksListAdapter.java
@@ -0,0 +1,190 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.home;
+
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.db.BrowserContract.Bookmarks;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.util.Pair;
+import android.view.View;
+
+import java.util.LinkedList;
+
+/**
+ * Adapter to back the BookmarksListView with a list of bookmarks.
+ */
+class BookmarksListAdapter extends MultiTypeCursorAdapter {
+    private static final int VIEW_TYPE_ITEM = 0;
+    private static final int VIEW_TYPE_FOLDER = 1;
+
+    private static final int[] VIEW_TYPES = new int[] { VIEW_TYPE_ITEM, VIEW_TYPE_FOLDER };
+    private static final int[] LAYOUT_TYPES = new int[] { R.layout.bookmark_item_row, R.layout.bookmark_folder_row };
+
+    // A listener that knows how to refresh the list for a given folder id.
+    // This is usually implemented by the enclosing fragment/activity.
+    public static interface OnRefreshFolderListener {
+        // The folder id to refresh the list with.
+        public void onRefreshFolder(int folderId);
+    }
+
+    // mParentStack holds folder id/title pairs that allow us to navigate
+    // back up the folder heirarchy.
+    private LinkedList<Pair<Integer, String>> mParentStack;
+
+    // Refresh folder listener.
+    private OnRefreshFolderListener mListener;
+
+    public BookmarksListAdapter(Context context, Cursor cursor) {
+        // Initializing with a null cursor.
+        super(context, cursor, VIEW_TYPES, LAYOUT_TYPES);
+
+        mParentStack = new LinkedList<Pair<Integer, String>>();
+
+        // Add the root folder to the stack
+        Pair<Integer, String> rootFolder = new Pair<Integer, String>(Bookmarks.FIXED_ROOT_ID, "");
+        mParentStack.addFirst(rootFolder);
+    }
+
+    // Refresh the current folder by executing a new task.
+    private void refreshCurrentFolder() {
+        if (mListener != null) {
+            mListener.onRefreshFolder(mParentStack.peek().first);
+        }
+    }
+
+    /**
+     * Moves to parent folder, if one exists.
+     */
+    public void moveToParentFolder() {
+        // If we're already at the root, we can't move to a parent folder
+        if (mParentStack.size() != 1) {
+            mParentStack.removeFirst();
+            refreshCurrentFolder();
+        }
+    }
+
+    /**
+     * Moves to child folder, given a folderId.
+     *
+     * @param folderId The id of the folder to show.
+     * @param folderTitle The title of the folder to show.
+     */
+    public void moveToChildFolder(int folderId, String folderTitle) {
+        Pair<Integer, String> folderPair = new Pair<Integer, String>(folderId, folderTitle);
+        mParentStack.addFirst(folderPair);
+        refreshCurrentFolder();
+    }
+
+    /**
+     * Set a listener that can refresh this adapter.
+     *
+     * @param listener The listener that can refresh the adapter.
+     */
+    public void setOnRefreshFolderListener(OnRefreshFolderListener listener) {
+        mListener = listener;
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        // The position also reflects the opened child folder row.
+        if (isShowingChildFolder()) {
+            if (position == 0) {
+                return VIEW_TYPE_FOLDER;
+            }
+
+            // Accounting for the folder view.
+            position--;
+        }
+
+        final Cursor c = getCursor(position);
+        if (c.getInt(c.getColumnIndexOrThrow(Bookmarks.TYPE)) == Bookmarks.TYPE_FOLDER) {
+            return VIEW_TYPE_FOLDER;
+        }
+
+        // Default to returning normal item type.
+        return VIEW_TYPE_ITEM;
+    }
+
+    /**
+     * Get the title of the folder given a cursor moved to the position.
+     *
+     * @param context The context of the view.
+     * @param cursor A cursor moved to the required position.
+     * @return The title of the folder at the position.
+     */
+    public String getFolderTitle(Context context, Cursor c) {
+        String guid = c.getString(c.getColumnIndexOrThrow(Bookmarks.GUID));
+
+        // If we don't have a special GUID, just return the folder title from the DB.
+        if (guid == null || guid.length() == 12) {
+            return c.getString(c.getColumnIndexOrThrow(Bookmarks.TITLE));
+        }
+
+        Resources res = context.getResources();
+
+        // Use localized strings for special folder names.
+        if (guid.equals(Bookmarks.FAKE_DESKTOP_FOLDER_GUID)) {
+            return res.getString(R.string.bookmarks_folder_desktop);
+        } else if (guid.equals(Bookmarks.MENU_FOLDER_GUID)) {
+            return res.getString(R.string.bookmarks_folder_menu);
+        } else if (guid.equals(Bookmarks.TOOLBAR_FOLDER_GUID)) {
+            return res.getString(R.string.bookmarks_folder_toolbar);
+        } else if (guid.equals(Bookmarks.UNFILED_FOLDER_GUID)) {
+            return res.getString(R.string.bookmarks_folder_unfiled);
+        }
+
+        // If for some reason we have a folder with a special GUID, but it's not one of
+        // the special folders we expect in the UI, just return the title from the DB.
+        return c.getString(c.getColumnIndexOrThrow(Bookmarks.TITLE));
+    }
+
+    /**
+     * @return true, if currently showing a child folder, false otherwise.
+     */
+    public boolean isShowingChildFolder() {
+        return (mParentStack.peek().first != Bookmarks.FIXED_ROOT_ID);
+    }
+
+    @Override
+    public int getCount() {
+        return super.getCount() + (isShowingChildFolder() ? 1 : 0);
+    }
+
+    @Override
+    public void bindView(View view, Context context, int position) {
+        final int viewType = getItemViewType(position);
+
+        final Cursor cursor;
+        if (isShowingChildFolder()) {
+            if (position == 0) {
+                cursor = null;
+            } else {
+                // Accounting for the folder view.
+                position--;
+                cursor = getCursor(position);
+            }
+        } else {
+            cursor = getCursor(position);
+        }
+
+        if (viewType == VIEW_TYPE_ITEM) {
+            final TwoLinePageRow row = (TwoLinePageRow) view;
+            row.updateFromCursor(cursor);
+        } else {
+            final BookmarkFolderView row = (BookmarkFolderView) view;
+            if (cursor == null) {
+                row.setText(mParentStack.peek().second);
+                row.open();
+            } else {
+                row.setText(getFolderTitle(context, cursor));
+                row.close();
+            }
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/home/BookmarksListView.java
@@ -0,0 +1,144 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.home;
+
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.db.BrowserContract.Bookmarks;
+import org.mozilla.gecko.db.BrowserDB.URLColumns;
+import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.AdapterView;
+import android.widget.HeaderViewListAdapter;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import java.util.EnumSet;
+
+/**
+ * A ListView of bookmarks.
+ */
+public class BookmarksListView extends HomeListView
+                               implements AdapterView.OnItemClickListener{
+    public static final String LOGTAG = "GeckoBookmarksListView";
+
+    // The last motion event that was intercepted.
+    private MotionEvent mMotionEvent;
+
+    // The default touch slop.
+    private int mTouchSlop;
+
+    public BookmarksListView(Context context) {
+        this(context, null);
+    }
+
+    public BookmarksListView(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.bookmarksListViewStyle);
+    }
+
+    public BookmarksListView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        // Scaled touch slop for this context.
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        setOnItemClickListener(this);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        switch(event.getAction() & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN: {
+                // Store the event by obtaining a copy.
+                mMotionEvent = MotionEvent.obtain(event);
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                if ((mMotionEvent != null) &&
+                    (Math.abs(event.getY() - mMotionEvent.getY()) > mTouchSlop)) {
+                    // The user is scrolling. Pass the last event to this view,
+                    // and make this view scroll.
+                    onTouchEvent(mMotionEvent);
+                    return true;
+                }
+                break;
+            }
+
+            default: {
+                mMotionEvent = null;
+                break;
+            }
+        }
+
+        // Do default interception.
+        return super.onInterceptTouchEvent(event);
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        final ListView list = (ListView) parent;
+        final int headerCount = list.getHeaderViewsCount();
+
+        if (position < headerCount) {
+            // The click is on a header, don't do anything.
+            return;
+        }
+
+        // Absolute position for the adapter.
+        position -= headerCount;
+
+        BookmarksListAdapter adapter;
+        ListAdapter listAdapter = getAdapter();
+        if (listAdapter instanceof HeaderViewListAdapter) {
+            adapter = (BookmarksListAdapter) ((HeaderViewListAdapter) listAdapter).getWrappedAdapter();
+        } else {
+            adapter = (BookmarksListAdapter) listAdapter;
+        }
+
+        if (adapter.isShowingChildFolder()) {
+            if (position == 0) {
+                // If we tap on an opened folder, move back to parent folder.
+                adapter.moveToParentFolder();
+                return;
+            }
+
+            // Accounting for the folder view.
+            position--;
+        }
+
+        final Cursor cursor = adapter.getCursor();
+        if (cursor == null) {
+            return;
+        }
+
+        cursor.moveToPosition(position);
+
+        int type = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE));
+        if (type == Bookmarks.TYPE_FOLDER) {
+            // If we're clicking on a folder, update adapter to move to that folder
+            final int folderId = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID));
+            final String folderTitle = adapter.getFolderTitle(parent.getContext(), cursor);
+            adapter.moveToChildFolder(folderId, folderTitle);
+        } else {
+            // Otherwise, just open the URL
+            final String url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
+
+            // This item is a TwoLinePageRow, so we allow switch-to-tab.
+            getOnUrlOpenListener().onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/home/BookmarksPage.java
@@ -0,0 +1,593 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.home;
+
+import org.mozilla.gecko.Favicons;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.Tabs;
+import org.mozilla.gecko.db.BrowserContract.Bookmarks;
+import org.mozilla.gecko.db.BrowserContract.Thumbnails;
+import org.mozilla.gecko.db.BrowserDB;
+import org.mozilla.gecko.db.BrowserDB.URLColumns;
+import org.mozilla.gecko.gfx.BitmapUtils;
+import org.mozilla.gecko.home.BookmarksListAdapter.OnRefreshFolderListener;
+import org.mozilla.gecko.home.HomeListView.HomeContextMenuInfo;
+import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
+import org.mozilla.gecko.home.PinBookmarkDialog.OnBookmarkSelectedListener;
+import org.mozilla.gecko.home.TopBookmarksAdapter.Thumbnail;
+import org.mozilla.gecko.home.TopBookmarksView.OnPinBookmarkListener;
+import org.mozilla.gecko.home.TopBookmarksView.TopBookmarksContextMenuInfo;
+import org.mozilla.gecko.util.ThreadUtils;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.app.LoaderManager.LoaderCallbacks;
+import android.support.v4.content.AsyncTaskLoader;
+import android.support.v4.content.Loader;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A page in about:home that displays a ListView of bookmarks.
+ */
+public class BookmarksPage extends HomeFragment {
+    public static final String LOGTAG = "GeckoBookmarksPage";
+
+    // Cursor loader ID for list of bookmarks.
+    private static final int LOADER_ID_BOOKMARKS_LIST = 0;
+
+    // Cursor loader ID for grid of bookmarks.
+    private static final int LOADER_ID_TOP_BOOKMARKS = 1;
+
+    // Loader ID for thumbnails.
+    private static final int LOADER_ID_THUMBNAILS = 2;
+
+    // Key for bookmarks folder id.
+    private static final String BOOKMARKS_FOLDER_KEY = "folder_id";
+
+    // Key for thumbnail urls.
+    private static final String THUMBNAILS_URLS_KEY = "urls";
+
+    // List of bookmarks.
+    private BookmarksListView mList;
+
+    // Grid of top bookmarks.
+    private TopBookmarksView mTopBookmarks;
+
+    // Adapter for list of bookmarks.
+    private BookmarksListAdapter mListAdapter;
+
+    // Adapter for grid of bookmarks.
+    private TopBookmarksAdapter mTopBookmarksAdapter;
+
+    // Callback for cursor loaders.
+    private CursorLoaderCallbacks mLoaderCallbacks;
+
+    // Callback for thumbnail loader.
+    private ThumbnailsLoaderCallbacks mThumbnailsLoaderCallbacks;
+
+    // Listener for pinning bookmarks.
+    private PinBookmarkListener mPinBookmarkListener;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        BookmarksListView list = (BookmarksListView) inflater.inflate(R.layout.home_bookmarks_page, container, false);
+
+        mTopBookmarks = new TopBookmarksView(getActivity());
+        list.addHeaderView(mTopBookmarks);
+
+        return list;
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        OnUrlOpenListener listener = null;
+        try {
+            listener = (OnUrlOpenListener) getActivity();
+        } catch (ClassCastException e) {
+            throw new ClassCastException(getActivity().toString()
+                    + " must implement HomePager.OnUrlOpenListener");
+        }
+
+        mPinBookmarkListener = new PinBookmarkListener();
+
+        mList = (BookmarksListView) view.findViewById(R.id.bookmarks_list);
+        mList.setTag(HomePager.LIST_TAG_BOOKMARKS);
+        mList.setOnUrlOpenListener(listener);
+
+        mTopBookmarks.setOnUrlOpenListener(listener);
+        mTopBookmarks.setOnPinBookmarkListener(mPinBookmarkListener);
+
+        registerForContextMenu(mList);
+        registerForContextMenu(mTopBookmarks);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        final Activity activity = getActivity();
+
+        // Setup the top bookmarks adapter.
+        mTopBookmarksAdapter = new TopBookmarksAdapter(activity, null);
+        mTopBookmarks.setAdapter(mTopBookmarksAdapter);
+
+        // Setup the list adapter.
+        mListAdapter = new BookmarksListAdapter(activity, null);
+        mListAdapter.setOnRefreshFolderListener(new OnRefreshFolderListener() {
+            @Override
+            public void onRefreshFolder(int folderId) {
+                // Restart the loader with folder as the argument.
+                Bundle bundle = new Bundle();
+                bundle.putInt(BOOKMARKS_FOLDER_KEY, folderId);
+                getLoaderManager().restartLoader(LOADER_ID_BOOKMARKS_LIST, bundle, mLoaderCallbacks);
+            }
+        });
+        mList.setAdapter(mListAdapter);
+
+        // Create callbacks before the initial loader is started.
+        mLoaderCallbacks = new CursorLoaderCallbacks(activity, getLoaderManager());
+        mThumbnailsLoaderCallbacks = new ThumbnailsLoaderCallbacks();
+        loadIfVisible();
+    }
+
+    @Override
+    public void onDestroyView() {
+        mList = null;
+        mListAdapter = null;
+        mTopBookmarks = null;
+        mTopBookmarksAdapter = null;
+        mPinBookmarkListener = null;
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        // Reattach the fragment, forcing a reinflation of its view.
+        // We use commitAllowingStateLoss() instead of commit() here to avoid
+        // an IllegalStateException. If the phone is rotated while Fennec
+        // is in the background, onConfigurationChanged() is fired.
+        // onConfigurationChanged() is called before onResume(), so
+        // using commit() would throw an IllegalStateException since it can't
+        // be used between the Activity's onSaveInstanceState() and
+        // onResume().
+        if (isVisible()) {
+            getFragmentManager().beginTransaction()
+                                .detach(this)
+                                .attach(this)
+                                .commitAllowingStateLoss();
+        }
+    }
+
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
+        if (menuInfo == null) {
+            return;
+        }
+
+        // HomeFragment will handle the default case.
+        if (menuInfo instanceof HomeContextMenuInfo) {
+            super.onCreateContextMenu(menu, view, menuInfo);
+        }
+
+        if (!(menuInfo instanceof TopBookmarksContextMenuInfo)) {
+            return;
+        }
+
+        MenuInflater inflater = new MenuInflater(view.getContext());
+        inflater.inflate(R.menu.top_bookmarks_contextmenu, menu);
+
+        TopBookmarksContextMenuInfo info = (TopBookmarksContextMenuInfo) menuInfo;
+
+        if (!TextUtils.isEmpty(info.url)) {
+            if (info.isPinned) {
+                menu.findItem(R.id.top_bookmarks_pin).setVisible(false);
+            } else {
+                menu.findItem(R.id.top_bookmarks_unpin).setVisible(false);
+            }
+        } else {
+            menu.findItem(R.id.top_bookmarks_open_new_tab).setVisible(false);
+            menu.findItem(R.id.top_bookmarks_open_private_tab).setVisible(false);
+            menu.findItem(R.id.top_bookmarks_pin).setVisible(false);
+            menu.findItem(R.id.top_bookmarks_unpin).setVisible(false);
+        }
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item) {
+        ContextMenuInfo menuInfo = item.getMenuInfo();
+
+        // HomeFragment will handle the default case.
+        if (menuInfo == null || !(menuInfo instanceof TopBookmarksContextMenuInfo)) {
+            return false;
+        }
+
+        TopBookmarksContextMenuInfo info = (TopBookmarksContextMenuInfo) menuInfo;
+        final Activity activity = getActivity();
+
+        final int itemId = item.getItemId();
+        if (itemId == R.id.top_bookmarks_open_new_tab || itemId == R.id.top_bookmarks_open_private_tab) {
+            if (info.url == null) {
+                Log.e(LOGTAG, "Can't open in new tab because URL is null");
+                return false;
+            }
+
+            int flags = Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_BACKGROUND;
+            if (item.getItemId() == R.id.top_bookmarks_open_private_tab)
+                flags |= Tabs.LOADURL_PRIVATE;
+
+            Tabs.getInstance().loadUrl(info.url, flags);
+            Toast.makeText(activity, R.string.new_tab_opened, Toast.LENGTH_SHORT).show();
+            return true;
+        }
+
+        if (itemId == R.id.top_bookmarks_pin) {
+            final String url = info.url;
+            final String title = info.title;
+            final int position = info.position;
+            final Context context = getActivity().getApplicationContext();
+
+            ThreadUtils.postToBackgroundThread(new Runnable() {
+                @Override
+                public void run() {
+                    BrowserDB.pinSite(context.getContentResolver(), url, title, position);
+                }
+            });
+
+            return true;
+        }
+
+        if (itemId == R.id.top_bookmarks_unpin) {
+            final int position = info.position;
+            final Context context = getActivity().getApplicationContext();
+
+            ThreadUtils.postToBackgroundThread(new Runnable() {
+                @Override
+                public void run() {
+                    BrowserDB.unpinSite(context.getContentResolver(), position);
+                }
+            });
+
+            return true;
+        }
+
+        if (itemId == R.id.top_bookmarks_edit) {
+            mPinBookmarkListener.onPinBookmark(info.position);