Bug 917394 - Rearrange about:home tabs as per new design (r=sriram, a=lsblakk)
authorLucas Rocha <lucasr@mozilla.com>
Tue, 17 Sep 2013 16:58:12 -0400
changeset 160501 757bacb00499ba76a54ff9a0be53bb567a2dcac2
parent 160500 75e1f0a7290c624384d849853a6546322ffcd0dc
child 160502 067c524d378fb355f7b633c8c55c464d4e6e1b9c
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssriram, lsblakk
bugs917394
milestone26.0a2
Bug 917394 - Rearrange about:home tabs as per new design (r=sriram, a=lsblakk)
mobile/android/base/BrowserApp.java
mobile/android/base/Makefile.in
mobile/android/base/Tab.java
mobile/android/base/home/BookmarksPage.java
mobile/android/base/home/HistoryPage.java
mobile/android/base/home/HomePager.java
mobile/android/base/home/MostVisitedPage.java
mobile/android/base/home/TopSitesPage.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/resources/layout-large-land-v11/home_history_page.xml
mobile/android/base/resources/layout-xlarge-v11/home_history_page.xml
mobile/android/base/resources/layout/home_bookmarks_page.xml
mobile/android/base/resources/layout/home_history_page.xml
mobile/android/base/resources/layout/home_most_visited_page.xml
mobile/android/base/resources/layout/home_top_sites_page.xml
mobile/android/base/resources/values-large-v11/styles.xml
mobile/android/base/resources/values/dimens.xml
mobile/android/base/resources/values/styles.xml
mobile/android/base/strings.xml.in
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -1390,17 +1390,17 @@ abstract public class BrowserApp extends
         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);
+        showHomePagerWithAnimator(HomePager.Page.TOP_SITES, animator);
 
         animator.start();
     }
 
     private void commitEditingMode() {
         if (!mBrowserToolbar.isEditing()) {
             return;
         }
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -223,29 +223,29 @@ FENNEC_JAVA_FILES = \
   home/HomeFragment.java \
   home/HomeListView.java \
   home/HomePager.java \
   home/HomePagerTabStrip.java \
   home/HomeBanner.java \
   home/FadedTextView.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/TopSitesPage.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 \
@@ -471,22 +471,22 @@ RES_LAYOUT = \
   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_banner.xml \
   res/layout/home_suggestion_prompt.xml \
+  res/layout/home_top_sites_page.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 \
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -88,17 +88,17 @@ public class Tab {
         mAppContext = context.getApplicationContext();
         mId = id;
         mLastUsed = 0;
         mUrl = url;
         mBaseDomain = "";
         mUserSearch = "";
         mExternal = external;
         mParentId = parentId;
-        mAboutHomePage = HomePager.Page.BOOKMARKS;
+        mAboutHomePage = HomePager.Page.TOP_SITES;
         mTitle = title == null ? "" : title;
         mFavicon = null;
         mFaviconUrl = null;
         mFaviconSize = 0;
         mFeedsEnabled = false;
         mIdentityData = null;
         mReaderEnabled = false;
         mEnteringReaderMode = false;
--- a/mobile/android/base/home/BookmarksPage.java
+++ b/mobile/android/base/home/BookmarksPage.java
@@ -3,169 +3,95 @@
  * 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.Favicons;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tabs;
-import org.mozilla.gecko.animation.PropertyAnimator;
-import org.mozilla.gecko.animation.PropertyAnimator.Property;
-import org.mozilla.gecko.animation.ViewHelper;
 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.MotionEvent;
 import android.view.View;
-import android.view.View.OnTouchListener;
 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;
-
-    // Banner to show snippets.
-    private HomeBanner mBanner;
-
     // 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;
-
-    // Raw Y value of the last event that happened on the list view.
-    private float mListTouchY = -1;
-
-    // Scrolling direction of the banner.
-    private boolean mSnapBannerToTop;
-
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         final View view = inflater.inflate(R.layout.home_bookmarks_page, container, false);
 
         mList = (BookmarksListView) view.findViewById(R.id.bookmarks_list);
 
-        mTopBookmarks = new TopBookmarksView(getActivity());
-        mList.addHeaderView(mTopBookmarks);
-
         return view;
     }
 
     @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.setTag(HomePager.LIST_TAG_BOOKMARKS);
         mList.setOnUrlOpenListener(listener);
         mList.setHeaderDividersEnabled(false);
 
-        mTopBookmarks.setOnUrlOpenListener(listener);
-        mTopBookmarks.setOnPinBookmarkListener(mPinBookmarkListener);
-
         registerForContextMenu(mList);
-        registerForContextMenu(mTopBookmarks);
-
-        mBanner = (HomeBanner) view.findViewById(R.id.home_banner);
-        mList.setOnTouchListener(new OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                BookmarksPage.this.handleListTouchEvent(event);
-                return false;
-            }
-        });
     }
 
     @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);
@@ -175,27 +101,23 @@ public class BookmarksPage extends HomeF
         mList.setAdapter(mListAdapter);
 
         // Invalidate the cached value that keeps track of whether or
         // not desktop bookmarks (or reading list items) exist.
         BrowserDB.invalidateCachedState();
 
         // Create callbacks before the initial loader is started.
         mLoaderCallbacks = new CursorLoaderCallbacks();
-        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.
@@ -209,214 +131,19 @@ public class BookmarksPage extends HomeF
         if (isVisible()) {
             getFragmentManager().beginTransaction()
                                 .detach(this)
                                 .attach(this)
                                 .commitAllowingStateLoss();
         }
     }
 
-    private void handleListTouchEvent(MotionEvent event) {
-        // Ignore the event if the banner is hidden for this session.
-        if (mBanner.isDismissed()) {
-            return;
-        }
-
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN: {
-                mListTouchY = event.getRawY();
-                break;
-             }
-
-            case MotionEvent.ACTION_MOVE: {
-                // There is a chance that we won't receive ACTION_DOWN, if the touch event
-                // actually started on the Grid instead of the List. Treat this as first event.
-                if (mListTouchY == -1) {
-                    mListTouchY = event.getRawY();
-                    return;
-                }
-
-                final float curY = event.getRawY();
-                final float delta = mListTouchY - curY;
-                mSnapBannerToTop = (delta > 0.0f) ? false : true;
-
-                final float height = mBanner.getHeight();
-                float newTranslationY = ViewHelper.getTranslationY(mBanner) + delta;
-
-                // Clamp the values to be between 0 and height.
-                if (newTranslationY < 0.0f) {
-                    newTranslationY = 0.0f;
-                } else if (newTranslationY > height) {
-                    newTranslationY = height;
-                }
-
-                ViewHelper.setTranslationY(mBanner, newTranslationY);
-                mListTouchY = curY;
-                break;
-            }
-
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL: {
-                mListTouchY = -1;
-                final float y = ViewHelper.getTranslationY(mBanner);
-                final float height = mBanner.getHeight();
-                if (y > 0.0f && y < height) {
-                    final PropertyAnimator animator = new PropertyAnimator(100);
-                    animator.attach(mBanner, Property.TRANSLATION_Y, mSnapBannerToTop ? 0 : height);
-                    animator.start();
-                }
-                break;
-            }
-        }
-    }
-
-    @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;
-        menu.setHeaderTitle(info.getDisplayTitle());
-
-        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);
-            return true;
-        }
-
-        return false;
-    }
-
     @Override
     protected void load() {
-        final LoaderManager manager = getLoaderManager();
-        manager.initLoader(LOADER_ID_BOOKMARKS_LIST, null, mLoaderCallbacks);
-        manager.initLoader(LOADER_ID_TOP_BOOKMARKS, null, mLoaderCallbacks);
-    }
-
-    /**
-     * Listener for pinning bookmarks.
-     */
-    private class PinBookmarkListener implements OnPinBookmarkListener,
-                                                 OnBookmarkSelectedListener {
-        // Tag for the PinBookmarkDialog fragment.
-        private static final String TAG_PIN_BOOKMARK = "pin_bookmark";
-
-        // Position of the pin.
-        private int mPosition;
-
-        @Override
-        public void onPinBookmark(int position) {
-            mPosition = position;
-
-            final FragmentManager manager = getActivity().getSupportFragmentManager();
-            PinBookmarkDialog dialog = (PinBookmarkDialog) manager.findFragmentByTag(TAG_PIN_BOOKMARK);
-            if (dialog == null) {
-                dialog = PinBookmarkDialog.newInstance();
-            }
-
-            dialog.setOnBookmarkSelectedListener(this);
-            dialog.show(manager, TAG_PIN_BOOKMARK);
-        }
-
-        @Override
-        public void onBookmarkSelected(final String url, final String title) {
-            final int position = mPosition;
-            final Context context = getActivity().getApplicationContext();
-            ThreadUtils.postToBackgroundThread(new Runnable() {
-                @Override
-                public void run() {
-                    BrowserDB.pinSite(context.getContentResolver(), url, title, position);
-                }
-            });
-        }
+        getLoaderManager().initLoader(LOADER_ID_BOOKMARKS_LIST, null, mLoaderCallbacks);
     }
 
     /**
      * Loader for the list for bookmarks.
      */
     private static class BookmarksLoader extends SimpleCursorLoader {
         private final int mFolderId;
 
@@ -431,226 +158,34 @@ public class BookmarksPage extends HomeF
 
         @Override
         public Cursor loadCursor() {
             return BrowserDB.getBookmarksInFolder(getContext().getContentResolver(), mFolderId);
         }
     }
 
     /**
-     * Loader for the grid for top bookmarks.
-     */
-    private static class TopBookmarksLoader extends SimpleCursorLoader {
-        public TopBookmarksLoader(Context context) {
-            super(context);
-        }
-
-        @Override
-        public Cursor loadCursor() {
-            final int max = getContext().getResources().getInteger(R.integer.number_of_top_sites);
-            return BrowserDB.getTopBookmarks(getContext().getContentResolver(), max);
-        }
-    }
-
-    /**
      * Loader callbacks for the LoaderManager of this fragment.
      */
     private class CursorLoaderCallbacks implements LoaderCallbacks<Cursor> {
         @Override
         public Loader<Cursor> onCreateLoader(int id, Bundle args) {
-            switch(id) {
-                case LOADER_ID_BOOKMARKS_LIST: {
-                    if (args == null) {
-                        return new BookmarksLoader(getActivity());
-                    } else {
-                        return new BookmarksLoader(getActivity(), args.getInt(BOOKMARKS_FOLDER_KEY));
-                    }
-                }
-
-                case LOADER_ID_TOP_BOOKMARKS: {
-                    return new TopBookmarksLoader(getActivity());
-                }
+            if (args == null) {
+                return new BookmarksLoader(getActivity());
+            } else {
+                return new BookmarksLoader(getActivity(), args.getInt(BOOKMARKS_FOLDER_KEY));
             }
-
-            return null;
         }
 
         @Override
         public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
-            final int loaderId = loader.getId();
-            switch(loaderId) {
-                case LOADER_ID_BOOKMARKS_LIST: {
-                    mListAdapter.swapCursor(c);
-                    mList.setHeaderDividersEnabled(c != null && c.getCount() > 0);
-                    break;
-                }
-
-                case LOADER_ID_TOP_BOOKMARKS: {
-                    mTopBookmarksAdapter.swapCursor(c);
-
-                    // Load the thumbnails.
-                    if (c.getCount() > 0 && c.moveToFirst()) {
-                        final ArrayList<String> urls = new ArrayList<String>();
-                        do {
-                            final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
-                            urls.add(url);
-                        } while (c.moveToNext());
-
-                        if (urls.size() > 0) {
-                            Bundle bundle = new Bundle();
-                            bundle.putStringArrayList(THUMBNAILS_URLS_KEY, urls);
-                            getLoaderManager().restartLoader(LOADER_ID_THUMBNAILS, bundle, mThumbnailsLoaderCallbacks);
-                        }
-                    }
-                    break;
-                }
-            }
+            mListAdapter.swapCursor(c);
+            mList.setHeaderDividersEnabled(c != null && c.getCount() > 0);
         }
 
         @Override
         public void onLoaderReset(Loader<Cursor> loader) {
-            final int loaderId = loader.getId();
-            switch(loaderId) {
-                case LOADER_ID_BOOKMARKS_LIST: {
-                    if (mList != null) {
-                        mListAdapter.swapCursor(null);
-                    }
-                    break;
-                }
-
-                case LOADER_ID_TOP_BOOKMARKS: {
-                    if (mTopBookmarks != null) {
-                        mTopBookmarksAdapter.swapCursor(null);
-                        break;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * An AsyncTaskLoader to load the thumbnails from a cursor.
-     */
-    private static class ThumbnailsLoader extends AsyncTaskLoader<Map<String, Thumbnail>> {
-        private Map<String, Thumbnail> mThumbnails;
-        private ArrayList<String> mUrls;
-
-        public ThumbnailsLoader(Context context, ArrayList<String> urls) {
-            super(context);
-            mUrls = urls;
-        }
-
-        @Override
-        public Map<String, Thumbnail> loadInBackground() {
-            if (mUrls == null || mUrls.size() == 0) {
-                return null;
-            }
-
-            final Map<String, Thumbnail> thumbnails = new HashMap<String, Thumbnail>();
-
-            // Query the DB for thumbnails.
-            final ContentResolver cr = getContext().getContentResolver();
-            final Cursor cursor = BrowserDB.getThumbnailsForUrls(cr, mUrls);
-
-            try {
-                if (cursor != null && cursor.moveToFirst()) {
-                    do {
-                        // Try to get the thumbnail, if cursor is valid.
-                        String url = cursor.getString(cursor.getColumnIndexOrThrow(Thumbnails.URL));
-                        final byte[] b = cursor.getBlob(cursor.getColumnIndexOrThrow(Thumbnails.DATA));
-                        final Bitmap bitmap = (b == null ? null : BitmapUtils.decodeByteArray(b));
-
-                        if (bitmap != null) {
-                            thumbnails.put(url, new Thumbnail(bitmap, true));
-                        }
-                    } while (cursor.moveToNext());
-                }
-            } finally {
-                if (cursor != null) {
-                    cursor.close();
-                }
-            }
-
-            // Query the DB for favicons for the urls without thumbnails.
-            for (String url : mUrls) {
-                if (!thumbnails.containsKey(url)) {
-                    final Bitmap bitmap = BrowserDB.getFaviconForUrl(cr, url);
-                    if (bitmap != null) {
-                        // Favicons.scaleImage can return several different size favicons,
-                        // but will at least prevent this from being too large.
-                        thumbnails.put(url, new Thumbnail(Favicons.scaleImage(bitmap), false));
-                    }
-                }
-            }
-
-            return thumbnails;
-        }
-
-        @Override
-        public void deliverResult(Map<String, Thumbnail> thumbnails) {
-            if (isReset()) {
-                mThumbnails = null;
-                return;
-            }
-
-            mThumbnails = thumbnails;
-
-            if (isStarted()) {
-                super.deliverResult(thumbnails);
-            }
-        }
-
-        @Override
-        protected void onStartLoading() {
-            if (mThumbnails != null) {
-                deliverResult(mThumbnails);
-            }
-
-            if (takeContentChanged() || mThumbnails == null) {
-                forceLoad();
-            }
-        }
-
-        @Override
-        protected void onStopLoading() {
-            cancelLoad();
-        }
-
-        @Override
-        public void onCanceled(Map<String, Thumbnail> thumbnails) {
-            mThumbnails = null;
-        }
-
-        @Override
-        protected void onReset() {
-            super.onReset();
-
-            // Ensure the loader is stopped.
-            onStopLoading();
-
-            mThumbnails = null;
-        }
-    }
-
-    /**
-     * Loader callbacks for the thumbnails on TopBookmarksView.
-     */
-    private class ThumbnailsLoaderCallbacks implements LoaderCallbacks<Map<String, Thumbnail>> {
-        @Override
-        public Loader<Map<String, Thumbnail>> onCreateLoader(int id, Bundle args) {
-            return new ThumbnailsLoader(getActivity(), args.getStringArrayList(THUMBNAILS_URLS_KEY));
-        }
-
-        @Override
-        public void onLoadFinished(Loader<Map<String, Thumbnail>> loader, Map<String, Thumbnail> thumbnails) {
-            if (mTopBookmarksAdapter != null) {
-                mTopBookmarksAdapter.updateThumbnails(thumbnails);
-            }
-        }
-
-        @Override
-        public void onLoaderReset(Loader<Map<String, Thumbnail>> loader) {
-            if (mTopBookmarksAdapter != null) {
-                mTopBookmarksAdapter.updateThumbnails(null);
+            if (mList != null) {
+                mListAdapter.swapCursor(null);
             }
         }
     }
 }
--- a/mobile/android/base/home/HistoryPage.java
+++ b/mobile/android/base/home/HistoryPage.java
@@ -20,60 +20,57 @@ import android.view.LayoutInflater;
 import android.widget.ImageButton;
 
 public class HistoryPage extends HomeFragment
                         implements IconTabWidget.OnTabChangedListener {
     // Logging tag name
     private static final String LOGTAG = "GeckoHistoryPage";
     private IconTabWidget mTabWidget;
     private int mSelectedTab;
-    private boolean initializeVisitedPage;
+    private boolean initializeRecentPage;
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         return inflater.inflate(R.layout.home_history_page, container, false);
     }
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
 
         mTabWidget = (IconTabWidget) view.findViewById(R.id.tab_icon_widget);
 
-        mTabWidget.addTab(R.drawable.icon_most_visited, R.string.home_most_visited_title);
         mTabWidget.addTab(R.drawable.icon_most_recent, R.string.home_most_recent_title);
         mTabWidget.addTab(R.drawable.icon_last_tabs, R.string.home_last_tabs_title);
 
         mTabWidget.setTabSelectionListener(this);
         mTabWidget.setCurrentTab(mSelectedTab);
 
         loadIfVisible();
     }
 
     @Override
     public void load() {
-        // Show most visited page as the initial page.
+        // Show most recent page as the initial page.
         // Since we detach/attach on config change, this prevents from replacing current fragment.
-        if (!initializeVisitedPage) {
-            showMostVisitedPage();
-            initializeVisitedPage = true;
+        if (!initializeRecentPage) {
+            showMostRecentPage();
+            initializeRecentPage = true;
         }
     }
 
     @Override
     public void onTabChanged(int index) {
         if (index == mSelectedTab) {
             return;
         }
 
         if (index == 0) {
-            showMostVisitedPage();
+            showMostRecentPage();
         } else if (index == 1) {
-            showMostRecentPage();
-        } else if (index == 2) {
             showLastTabsPage();
         }
 
         mTabWidget.setCurrentTab(index);
         mSelectedTab = index;
     }
 
     @Override
@@ -90,25 +87,20 @@ public class HistoryPage extends HomeFra
     }
 
     private void showSubPage(Fragment subPage) {
         final Bundle args = new Bundle();
         args.putBoolean(HomePager.CAN_LOAD_ARG, getCanLoadHint());
         subPage.setArguments(args);
 
         getChildFragmentManager().beginTransaction()
-                .addToBackStack(null).replace(R.id.visited_page_container, subPage)
+                .addToBackStack(null).replace(R.id.history_page_container, subPage)
                 .commitAllowingStateLoss();
     }
 
-    private void showMostVisitedPage() {
-        final MostVisitedPage mostVisitedPage = MostVisitedPage.newInstance();
-        showSubPage(mostVisitedPage);
-    }
-
     private void showMostRecentPage() {
         final MostRecentPage mostRecentPage = MostRecentPage.newInstance();
         showSubPage(mostRecentPage);
     }
 
     private void showLastTabsPage() {
         final LastTabsPage lastTabsPage = LastTabsPage.newInstance();
         showSubPage(lastTabsPage);
--- a/mobile/android/base/home/HomePager.java
+++ b/mobile/android/base/home/HomePager.java
@@ -3,16 +3,17 @@
  * 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.animation.PropertyAnimator;
 import org.mozilla.gecko.animation.ViewHelper;
+import org.mozilla.gecko.util.HardwareUtils;
 
 import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentStatePagerAdapter;
 import android.support.v4.view.PagerAdapter;
@@ -33,16 +34,17 @@ public class HomePager extends ViewPager
 
     private final Context mContext;
     private volatile boolean mLoaded;
     private Decor mDecor;
 
     // List of pages in order.
     public enum Page {
         HISTORY,
+        TOP_SITES,
         BOOKMARKS,
         READING_LIST
     }
 
     // This is mostly used by UI tests to easily fetch
     // specific list views at runtime.
     static final String LIST_TAG_HISTORY = "history";
     static final String LIST_TAG_BOOKMARKS = "bookmarks";
@@ -85,19 +87,19 @@ public class HomePager extends ViewPager
     public HomePager(Context context) {
         this(context, null);
     }
 
     public HomePager(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
 
-        // This is to keep all 3 pages in memory after they are
+        // This is to keep all 4 pages in memory after they are
         // selected in the pager.
-        setOffscreenPageLimit(2);
+        setOffscreenPageLimit(3);
     }
 
     @Override
     public void addView(View child, int index, ViewGroup.LayoutParams params) {
         if (child instanceof Decor) {
             ((ViewPager.LayoutParams) params).isDecor = true;
             mDecor = (Decor) child;
             setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@@ -126,24 +128,29 @@ public class HomePager extends ViewPager
      */
     public void show(FragmentManager fm, Page page, PropertyAnimator animator) {
         mLoaded = true;
         final TabsAdapter adapter = new TabsAdapter(fm);
 
         // Only animate on post-HC devices, when a non-null animator is given
         final boolean shouldAnimate = (animator != null && Build.VERSION.SDK_INT >= 11);
 
-        // Add the pages to the adapter in order.
-        adapter.addTab(Page.HISTORY, HistoryPage.class, new Bundle(),
-                getContext().getString(R.string.home_history_title));
+        adapter.addTab(Page.TOP_SITES, TopSitesPage.class, new Bundle(),
+                getContext().getString(R.string.home_top_sites_title));
         adapter.addTab(Page.BOOKMARKS, BookmarksPage.class, new Bundle(),
                 getContext().getString(R.string.bookmarks_title));
         adapter.addTab(Page.READING_LIST, ReadingListPage.class, new Bundle(),
                 getContext().getString(R.string.reading_list_title));
 
+        // On phones, the history tab is the first tab. On tablets, the
+        // history tab is the last tab.
+        adapter.addTab(HardwareUtils.isTablet() ? -1 : 0,
+                Page.HISTORY, HistoryPage.class, new Bundle(),
+                getContext().getString(R.string.home_history_title));
+
         adapter.setCanLoadHint(!shouldAnimate);
 
         setAdapter(adapter);
 
         setCurrentItem(adapter.getItemPosition(page), false);
         setVisibility(VISIBLE);
 
         if (shouldAnimate) {
@@ -221,18 +228,28 @@ public class HomePager extends ViewPager
 
             if (mDecor != null) {
                 mDecor.removeAllPagerViews();
                 mDecor.setOnTitleClickListener(this);
             }
         }
 
         public void addTab(Page page, Class<?> clss, Bundle args, String title) {
+            addTab(-1, page, clss, args, title);
+        }
+
+        public void addTab(int index, Page page, Class<?> clss, Bundle args, String title) {
             TabInfo info = new TabInfo(page, clss, args, title);
-            mTabs.add(info);
+
+            if (index >= 0) {
+                mTabs.add(index, info);
+            } else {
+                mTabs.add(info);
+            }
+
             notifyDataSetChanged();
 
             if (mDecor != null) {
                 mDecor.onAddPagerView(title);
             }
         }
 
         @Override
rename from mobile/android/base/home/MostVisitedPage.java
rename to mobile/android/base/home/TopSitesPage.java
--- a/mobile/android/base/home/MostVisitedPage.java
+++ b/mobile/android/base/home/TopSitesPage.java
@@ -1,73 +1,85 @@
 /* -*- 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.animation.PropertyAnimator;
+import org.mozilla.gecko.animation.PropertyAnimator.Property;
+import org.mozilla.gecko.animation.ViewHelper;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.BrowserDB.URLColumns;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
 
 import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.database.Cursor;
 import android.os.Bundle;
 import android.support.v4.app.LoaderManager;
 import android.support.v4.app.LoaderManager.LoaderCallbacks;
 import android.support.v4.content.Loader;
 import android.support.v4.widget.CursorAdapter;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.widget.AdapterView;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
 
 import java.util.EnumSet;
 
 /**
  * Fragment that displays frecency search results in a ListView.
  */
-public class MostVisitedPage extends HomeFragment {
+public class TopSitesPage extends HomeFragment {
     // Logging tag name
-    private static final String LOGTAG = "GeckoMostVisitedPage";
+    private static final String LOGTAG = "GeckoTopSitesPage";
 
     // Cursor loader ID for search query
-    private static final int LOADER_ID_FRECENCY = 0;
+    private static final int LOADER_ID_TOP_SITES = 0;
 
     // Adapter for the list of search results
     private VisitedAdapter mAdapter;
 
     // The view shown by the fragment.
     private ListView mList;
 
-    // The title for this HomeFragment page.
-    private TextView mTitle;
-
     // Reference to the View to display when there are no results.
     private View mEmptyView;
 
+    // Banner to show snippets.
+    private HomeBanner mBanner;
+
+    // Raw Y value of the last event that happened on the list view.
+    private float mListTouchY = -1;
+
+    // Scrolling direction of the banner.
+    private boolean mSnapBannerToTop;
+
     // Callbacks used for the search and favicon cursor loaders
     private CursorLoaderCallbacks mCursorLoaderCallbacks;
 
     // On URL open listener
     private OnUrlOpenListener mUrlOpenListener;
 
-    public static MostVisitedPage newInstance() {
-        return new MostVisitedPage();
+    public static TopSitesPage newInstance() {
+        return new TopSitesPage();
     }
 
-    public MostVisitedPage() {
+    public TopSitesPage() {
         mUrlOpenListener = null;
     }
 
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
 
         try {
@@ -82,26 +94,21 @@ public class MostVisitedPage extends Hom
     public void onDetach() {
         super.onDetach();
 
         mUrlOpenListener = null;
     }
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        return inflater.inflate(R.layout.home_most_visited_page, container, false);
+        return inflater.inflate(R.layout.home_top_sites_page, container, false);
     }
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
-        mTitle = (TextView) view.findViewById(R.id.title);
-        if (mTitle != null) {
-            mTitle.setText(R.string.home_most_visited_title);
-        }
-
         mList = (HomeListView) view.findViewById(R.id.list);
         mList.setTag(HomePager.LIST_TAG_MOST_VISITED);
 
         mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
             @Override
             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                 final Cursor c = mAdapter.getCursor();
                 if (c == null || !c.moveToPosition(position)) {
@@ -111,78 +118,144 @@ public class MostVisitedPage extends Hom
                 final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
 
                 // This item is a TwoLinePageRow, so we allow switch-to-tab.
                 mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
             }
         });
 
         registerForContextMenu(mList);
+
+        mBanner = (HomeBanner) view.findViewById(R.id.home_banner);
+        mList.setOnTouchListener(new OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                TopSitesPage.this.handleListTouchEvent(event);
+                return false;
+            }
+        });
     }
 
     @Override
     public void onDestroyView() {
         super.onDestroyView();
         mList = null;
-        mTitle = null;
         mEmptyView = null;
     }
 
     @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        // Detach and reattach the fragment as the layout changes.
+        if (isVisible()) {
+            getFragmentManager().beginTransaction()
+                                .detach(this)
+                                .attach(this)
+                                .commitAllowingStateLoss();
+        }
+    }
+
+    @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
         // Intialize the search adapter
         mAdapter = new VisitedAdapter(getActivity(), null);
         mList.setAdapter(mAdapter);
 
         // Create callbacks before the initial loader is started
         mCursorLoaderCallbacks = new CursorLoaderCallbacks();
         loadIfVisible();
     }
 
     @Override
     protected void load() {
-        getLoaderManager().initLoader(LOADER_ID_FRECENCY, null, mCursorLoaderCallbacks);
+        getLoaderManager().initLoader(LOADER_ID_TOP_SITES, null, mCursorLoaderCallbacks);
+    }
+
+    private void handleListTouchEvent(MotionEvent event) {
+        // Ignore the event if the banner is hidden for this session.
+        if (mBanner.isDismissed()) {
+            return;
+        }
+
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN: {
+                mListTouchY = event.getRawY();
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                // There is a chance that we won't receive ACTION_DOWN, if the touch event
+                // actually started on the Grid instead of the List. Treat this as first event.
+                if (mListTouchY == -1) {
+                    mListTouchY = event.getRawY();
+                    return;
+                }
+
+                final float curY = event.getRawY();
+                final float delta = mListTouchY - curY;
+                mSnapBannerToTop = (delta > 0.0f) ? false : true;
+
+                final float height = mBanner.getHeight();
+                float newTranslationY = ViewHelper.getTranslationY(mBanner) + delta;
+
+                // Clamp the values to be between 0 and height.
+                if (newTranslationY < 0.0f) {
+                    newTranslationY = 0.0f;
+                } else if (newTranslationY > height) {
+                    newTranslationY = height;
+                }
+
+                ViewHelper.setTranslationY(mBanner, newTranslationY);
+                mListTouchY = curY;
+                break;
+            }
+
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL: {
+                mListTouchY = -1;
+                final float y = ViewHelper.getTranslationY(mBanner);
+                final float height = mBanner.getHeight();
+                if (y > 0.0f && y < height) {
+                    final PropertyAnimator animator = new PropertyAnimator(100);
+                    animator.attach(mBanner, Property.TRANSLATION_Y, mSnapBannerToTop ? 0 : height);
+                    animator.start();
+                }
+                break;
+            }
+        }
     }
 
     private void updateUiFromCursor(Cursor c) {
         if (c != null && c.getCount() > 0) {
-            if (mTitle != null) {
-                mTitle.setVisibility(View.VISIBLE);
-            }
             return;
         }
 
-        // Cursor is empty, so hide the title and set the
-        // empty view if it hasn't been set already.
-        if (mTitle != null) {
-            mTitle.setVisibility(View.GONE);
-        }
-
         if (mEmptyView == null) {
             // Set empty page view. We delay this so that the empty view won't flash.
             ViewStub emptyViewStub = (ViewStub) getView().findViewById(R.id.home_empty_view_stub);
             mEmptyView = emptyViewStub.inflate();
 
             final ImageView emptyIcon = (ImageView) mEmptyView.findViewById(R.id.home_empty_image);
             emptyIcon.setImageResource(R.drawable.icon_most_visited_empty);
 
             final TextView emptyText = (TextView) mEmptyView.findViewById(R.id.home_empty_text);
             emptyText.setText(R.string.home_most_visited_empty);
 
             mList.setEmptyView(mEmptyView);
         }
     }
 
-    private static class FrecencyCursorLoader extends SimpleCursorLoader {
+    private static class TopSitesCursorLoader extends SimpleCursorLoader {
         // Max number of search results
         private static final int SEARCH_LIMIT = 50;
 
-        public FrecencyCursorLoader(Context context) {
+        public TopSitesCursorLoader(Context context) {
             super(context);
         }
 
         @Override
         public Cursor loadCursor() {
             final ContentResolver cr = getContext().getContentResolver();
             return BrowserDB.filter(cr, "", SEARCH_LIMIT);
         }
@@ -203,17 +276,17 @@ public class MostVisitedPage extends Hom
         public View newView(Context context, Cursor cursor, ViewGroup parent) {
             return LayoutInflater.from(parent.getContext()).inflate(R.layout.home_item_row, parent, false);
         }
     }
 
     private class CursorLoaderCallbacks implements LoaderCallbacks<Cursor> {
         @Override
         public Loader<Cursor> onCreateLoader(int id, Bundle args) {
-            return new FrecencyCursorLoader(getActivity());
+            return new TopSitesCursorLoader(getActivity());
         }
 
         @Override
         public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
             mAdapter.swapCursor(c);
             updateUiFromCursor(c);
         }
 
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -265,16 +265,17 @@ size. -->
 <!ENTITY button_ok "OK">
 <!ENTITY button_cancel "Cancel">
 <!ENTITY button_yes "Yes">
 <!ENTITY button_no "No">
 <!ENTITY button_clear_data "Clear data">
 <!ENTITY button_set "Set">
 <!ENTITY button_clear "Clear">
 
+<!ENTITY home_top_sites_title "Top Sites">
 <!ENTITY home_history_title "History">
 <!ENTITY home_last_tabs_title "Tabs from last time">
 <!ENTITY home_last_tabs_open "Open all tabs from last time">
 <!ENTITY home_last_tabs_empty "Your recent tabs show up here.">
 <!ENTITY home_most_recent_title "Most recent">
 <!ENTITY home_most_recent_empty "Websites you visited most recently show up here.">
 <!ENTITY home_most_visited_title "Most visited">
 <!ENTITY home_reading_list_empty "Articles you save for later show up here.">
--- a/mobile/android/base/resources/layout-large-land-v11/home_history_page.xml
+++ b/mobile/android/base/resources/layout-large-land-v11/home_history_page.xml
@@ -11,14 +11,14 @@
     <org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_icon_widget"
                                             style="@style/Widget.Home.HistoryTabWidget"
                                             android:layout_width="@dimen/history_tab_widget_width"
                                             android:layout_height="@dimen/history_tab_widget_height"
                                             android:orientation="vertical"
                                             android:layout="@layout/home_history_tabs_indicator"
                                             gecko:display="text"/>
 
-    <FrameLayout android:id="@+id/visited_page_container"
+    <FrameLayout android:id="@+id/history_page_container"
                  android:layout_width="0dp"
                  android:layout_height="fill_parent"
                  android:layout_weight="1" />
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout-xlarge-v11/home_history_page.xml
+++ b/mobile/android/base/resources/layout-xlarge-v11/home_history_page.xml
@@ -11,14 +11,14 @@
     <org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_icon_widget"
                                             style="@style/Widget.Home.HistoryTabWidget"
                                             android:layout_width="@dimen/history_tab_widget_width"
                                             android:layout_height="@dimen/history_tab_widget_height"
                                             android:orientation="vertical"
                                             android:layout="@layout/home_history_tabs_indicator"
                                             gecko:display="text"/>
 
-    <FrameLayout android:id="@+id/visited_page_container"
+    <FrameLayout android:id="@+id/history_page_container"
                  android:layout_width="0dp"
                  android:layout_height="fill_parent"
                  android:layout_weight="1" />
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout/home_bookmarks_page.xml
+++ b/mobile/android/base/resources/layout/home_bookmarks_page.xml
@@ -7,20 +7,9 @@
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">
 
     <org.mozilla.gecko.home.BookmarksListView
             android:id="@+id/bookmarks_list"
             android:layout_width="fill_parent"
             android:layout_height="fill_parent"/>
 
-    <org.mozilla.gecko.home.HomeBanner android:id="@+id/home_banner"
-                                       style="@style/Widget.HomeBanner"
-                                       android:layout_width="fill_parent"
-                                       android:layout_height="@dimen/home_banner_height"
-                                       android:background="@drawable/home_banner"
-                                       android:layout_gravity="bottom"
-                                       android:gravity="center_vertical"
-                                       android:visibility="gone"
-                                       android:clickable="true"
-                                       android:focusable="true"/>
-
 </FrameLayout>
--- a/mobile/android/base/resources/layout/home_history_page.xml
+++ b/mobile/android/base/resources/layout/home_history_page.xml
@@ -3,17 +3,17 @@
    - 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/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:layout_width="fill_parent"
               android:layout_height="fill_parent"
               android:orientation="vertical">
 
-    <FrameLayout android:id="@+id/visited_page_container"
+    <FrameLayout android:id="@+id/history_page_container"
                  android:layout_width="fill_parent"
                  android:layout_height="0dp"
                  android:layout_weight="1" />
 
     <org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_icon_widget"
                                             android:layout_width="fill_parent"
                                             android:layout_height="@dimen/browser_toolbar_height"
                                             android:tabStripEnabled="false"
rename from mobile/android/base/resources/layout/home_most_visited_page.xml
rename to mobile/android/base/resources/layout/home_top_sites_page.xml
--- a/mobile/android/base/resources/layout/home_most_visited_page.xml
+++ b/mobile/android/base/resources/layout/home_top_sites_page.xml
@@ -3,11 +3,32 @@
    - 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/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:layout_width="fill_parent"
               android:layout_height="fill_parent"
               android:orientation="vertical">
 
-    <include layout="@layout/home_history_list"/>
+    <ViewStub android:id="@+id/home_empty_view_stub"
+              android:layout="@layout/home_empty_page"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"/>
+
+    <org.mozilla.gecko.home.HomeListView
+            android:id="@+id/list"
+            style="@style/Widget.TopSitesListView"
+            android:layout_width="fill_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"/>
+
+    <org.mozilla.gecko.home.HomeBanner android:id="@+id/home_banner"
+                                       style="@style/Widget.HomeBanner"
+                                       android:layout_width="fill_parent"
+                                       android:layout_height="@dimen/home_banner_height"
+                                       android:background="@drawable/home_banner"
+                                       android:layout_gravity="bottom"
+                                       android:gravity="center_vertical"
+                                       android:visibility="gone"
+                                       android:clickable="true"
+                                       android:focusable="true"/>
 
 </LinearLayout>
--- a/mobile/android/base/resources/values-large-v11/styles.xml
+++ b/mobile/android/base/resources/values-large-v11/styles.xml
@@ -57,33 +57,34 @@
 
         <item name="android:paddingTop">0dp</item>
         <item name="android:paddingBottom">0dp</item>
         <item name="android:paddingLeft">0dp</item>
         <item name="android:paddingRight">0dp</item>
     </style>
 
     <style name="Widget.BookmarksListView" parent="Widget.HomeListView">
+        <item name="android:paddingTop">30dp</item>
         <item name="android:paddingLeft">32dp</item>
         <item name="android:paddingRight">32dp</item>
         <item name="android:scrollbarStyle">outsideOverlay</item>
+        <item name="topDivider">true</item>
     </style>
 
     <style name="Widget.TopBookmarksView" parent="Widget.GridView">
         <item name="android:paddingLeft">5dp</item>
         <item name="android:paddingRight">5dp</item>
         <item name="android:paddingTop">30dp</item>
         <item name="android:paddingBottom">30dp</item>
         <item name="android:horizontalSpacing">10dp</item>
         <item name="android:verticalSpacing">10dp</item>
     </style>
 
-    <style name="Widget.ReadingListView" parent="Widget.BookmarksListView">
-        <item name="android:paddingTop">30dp</item>
-        <item name="topDivider">true</item>
-    </style>
+    <style name="Widget.TopSitesListView" parent="Widget.BookmarksListView"/>
+
+    <style name="Widget.ReadingListView" parent="Widget.BookmarksListView"/>
 
     <style name="Widget.HomeBanner">
         <item name="android:paddingLeft">32dp</item>
         <item name="android:paddingRight">32dp</item>
     </style>
 
 </resources>
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -77,17 +77,17 @@
     <dimen name="forward_default_offset">-13dip</dimen>
     <dimen name="url_bar_offset_left">32dp</dimen>
     <dimen name="toast_button_padding">8dp</dimen>
     <dimen name="history_tab_indicator_height">50dp</dimen>
 
     <!-- We need to maintain height for the tab widget on History Page
          since android does not add footer/header divider height to its
          calculation for wrap_content in LinearLayout.
-         50dp * 3 Views + 30dp padding + 4dp dividers-->
-    <dimen name="history_tab_widget_height">184dp</dimen>
+         50dp * 2 Views + 30dp padding + 4dp dividers-->
+    <dimen name="history_tab_widget_height">134dp</dimen>
 
     <!-- PageActionButtons dimensions -->
     <dimen name="page_action_button_width">32dp</dimen>
 
     <!-- Banner -->
     <dimen name="home_banner_height">72dp</dimen>
 </resources>
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -153,16 +153,18 @@
       <item name="android:paddingTop">5dip</item>
       <item name="android:gravity">left</item>
     </style>
 
     <style name="Widget.HomeListView" parent="Widget.ListView">
         <item name="android:divider">#E7ECF0</item>
     </style>
 
+    <style name="Widget.TopSitesListView" parent="Widget.BookmarksListView"/>
+
     <style name="Widget.ReadingListView" parent="Widget.BookmarksListView"/>
 
     <style name="Widget.HomeBanner"/>
 
     <style name="Widget.Home" />
 
     <style name="Widget.Home.HeaderItem">
         <item name="android:layout_width">fill_parent</item>
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -247,16 +247,17 @@
   <string name="button_ok">&button_ok;</string>
   <string name="button_cancel">&button_cancel;</string>
   <string name="button_clear_data">&button_clear_data;</string>
   <string name="button_set">&button_set;</string>
   <string name="button_clear">&button_clear;</string>
   <string name="button_yes">&button_yes;</string>
   <string name="button_no">&button_no;</string>
 
+  <string name="home_top_sites_title">&home_top_sites_title;</string>
   <string name="home_history_title">&home_history_title;</string>
   <string name="home_last_tabs_title">&home_last_tabs_title;</string>
   <string name="home_last_tabs_open">&home_last_tabs_open;</string>
   <string name="home_last_tabs_empty">&home_last_tabs_empty;</string>
   <string name="home_most_recent_title">&home_most_recent_title;</string>
   <string name="home_most_recent_empty">&home_most_recent_empty;</string>
   <string name="home_most_visited_title">&home_most_visited_title;</string>
   <string name="home_most_visited_empty">&home_most_visited_empty;</string>