Bug 891183: Added custom tab strip in about:home for tablets [r=sriram]
authorShilpan Bhagat <sbhagat@mozilla.com>
Tue, 13 Aug 2013 17:08:16 -0700
changeset 143528 353b024859c15b1295bbf46e61329d4cee10d1d0
parent 143527 0db3b6642ad006283ee1ba0075852303b105a759
child 143529 1a6e28e051e0e3fb9a508e02de18922afd4e364c
push id25130
push userlrocha@mozilla.com
push dateWed, 21 Aug 2013 09:41:27 +0000
treeherdermozilla-central@b2486721572e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssriram
bugs891183
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
Bug 891183: Added custom tab strip in about:home for tablets [r=sriram]
mobile/android/base/Makefile.in
mobile/android/base/home/HomePager.java
mobile/android/base/home/TabMenuStrip.java
mobile/android/base/resources/drawable-hdpi/home_tab_menu_strip.9.png
mobile/android/base/resources/drawable-mdpi/home_tab_menu_strip.9.png
mobile/android/base/resources/drawable-xhdpi/home_tab_menu_strip.9.png
mobile/android/base/resources/layout-large-v11/home_pager.xml
mobile/android/base/resources/layout/gecko_app.xml
mobile/android/base/resources/layout/home_pager.xml
mobile/android/base/resources/layout/tab_menu_strip.xml
mobile/android/base/resources/values/attrs.xml
mobile/android/base/resources/values/dimens.xml
mobile/android/base/resources/values/styles.xml
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -235,16 +235,17 @@ FENNEC_JAVA_FILES = \
   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 \
@@ -471,16 +472,17 @@ RES_LAYOUT = \
   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 \
@@ -495,16 +497,17 @@ RES_LAYOUT = \
   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 \
@@ -516,16 +519,17 @@ RES_LAYOUT = \
   res/layout/simple_dropdown_item_1line.xml \
   res/layout/suggestion_item.xml \
   res/layout/validation_message.xml \
   res/layout/videoplayer.xml \
   $(NULL)
 
 RES_LAYOUT_LARGE_V11 = \
   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 \
@@ -636,16 +640,17 @@ RES_DRAWABLE_MDPI = \
   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/bookmark_folder_closed.png \
   res/drawable-mdpi/bookmark_folder_opened.png \
   res/drawable-mdpi/desktop_notification.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_new_private_tab.png \
   res/drawable-mdpi/ic_menu_new_tab.png \
@@ -744,16 +749,17 @@ RES_DRAWABLE_HDPI = \
   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/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_new_private_tab.png \
   res/drawable-hdpi/ic_menu_new_tab.png \
@@ -839,16 +845,17 @@ RES_DRAWABLE_XHDPI = \
   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/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_new_private_tab.png \
   res/drawable-xhdpi/ic_menu_new_tab.png \
--- a/mobile/android/base/home/HomePager.java
+++ b/mobile/android/base/home/HomePager.java
@@ -9,31 +9,35 @@ import org.mozilla.gecko.R;
 import org.mozilla.gecko.animation.PropertyAnimator;
 import org.mozilla.gecko.animation.ViewHelper;
 
 import android.content.Context;
 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;
 import android.support.v4.view.ViewPager;
+import android.view.ViewGroup.LayoutParams;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.ViewGroup;
+import android.view.View;
 
 import java.util.ArrayList;
 import java.util.EnumMap;
 import java.util.EnumSet;
 
 public class HomePager extends ViewPager {
     // Subpage fragment tag
     public static final String SUBPAGE_TAG = "home_pager_subpage";
 
     private final Context mContext;
     private volatile boolean mLoaded;
+    private Decor mDecor;
 
     // List of pages in order.
     public enum Page {
         HISTORY,
         BOOKMARKS,
         READING_LIST
     }
 
@@ -46,29 +50,68 @@ public class HomePager extends ViewPager
 
         public void onUrlOpen(String url, EnumSet<Flags> flags);
     }
 
     public interface OnNewTabsListener {
         public void onNewTabs(String[] urls);
     }
 
+    interface OnTitleClickListener {
+        public void onTitleClicked(int index);
+    }
+
+    /**
+     * Special type of child views that could be added as pager decorations by default.
+     */
+    interface Decor {
+        public void onAddPagerView(String title);
+        public void removeAllPagerViews();
+        public void onPageSelected(int position);
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
+        public void setOnTitleClickListener(OnTitleClickListener onTitleClickListener);
+    }
+
     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
         // selected in the pager.
         setOffscreenPageLimit(2);
     }
 
+    @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() {
+                @Override
+                public void onPageSelected(int position) {
+                    mDecor.onPageSelected(position);
+                }
+
+                @Override
+                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+                    mDecor.onPageScrolled(position, positionOffset, positionOffsetPixels);
+                }
+
+                @Override
+                public void onPageScrollStateChanged(int state) { }
+            });
+        }
+
+        super.addView(child, index, params);
+    }
+
     /**
      * Loads and initializes the pager.
      *
      * @param fm FragmentManager for the adapter
      */
     public void show(FragmentManager fm, Page page, PropertyAnimator animator) {
         mLoaded = true;
         TabsAdapter adapter = new TabsAdapter(fm);
@@ -108,17 +151,18 @@ public class HomePager extends ViewPager
      * thread.
      *
      * @return Whether the pager and its fragments are being displayed
      */
     public boolean isVisible() {
         return mLoaded;
     }
 
-    class TabsAdapter extends FragmentStatePagerAdapter {
+    class TabsAdapter extends FragmentStatePagerAdapter
+                      implements OnTitleClickListener {
         private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
 
         final class TabInfo {
             private final Page page;
             private final Class<?> clss;
             private final Bundle args;
             private final String title;
 
@@ -127,22 +171,36 @@ public class HomePager extends ViewPager
                 this.clss = clss;
                 this.args = args;
                 this.title = title;
             }
         }
 
         public TabsAdapter(FragmentManager fm) {
             super(fm);
+
+            if (mDecor != null) {
+                mDecor.removeAllPagerViews();
+                mDecor.setOnTitleClickListener(this);
+            }
         }
 
         public void addTab(Page page, Class<?> clss, Bundle args, String title) {
             TabInfo info = new TabInfo(page, clss, args, title);
             mTabs.add(info);
             notifyDataSetChanged();
+
+            if (mDecor != null) {
+                mDecor.onAddPagerView(title);
+            }
+        }
+
+        @Override
+        public void onTitleClicked(int index) {
+            setCurrentItem(index, true);
         }
 
         public int getItemPosition(Page page) {
             for (int i = 0; i < mTabs.size(); i++) {
                 TabInfo info = mTabs.get(i);
                 if (info.page == page) {
                     return i;
                 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/home/TabMenuStrip.java
@@ -0,0 +1,202 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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 android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.graphics.Rect;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.util.Log;
+
+import org.mozilla.gecko.home.HomePager;
+import org.mozilla.gecko.R;
+
+public class TabMenuStrip extends LinearLayout
+                          implements HomePager.Decor,
+                                     View.OnFocusChangeListener {
+    private static final String LOGTAG = "GeckoTabMenuStrip";
+
+    private HomePager.OnTitleClickListener mOnTitleClickListener;
+    private Drawable mStrip;
+    private View mSelectedView;
+
+    // Data associated with the scrolling of the strip drawable.
+    private View toTab;
+    private View fromTab;
+    private float progress;
+
+    // This variable is used to predict the direction of scroll.
+    private float mPrevProgress;
+
+    public TabMenuStrip(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabMenuStrip);
+        final int stripResId = a.getResourceId(R.styleable.TabMenuStrip_strip, -1);
+        a.recycle();
+
+        if (stripResId != -1) {
+            mStrip = getResources().getDrawable(stripResId);
+        }
+
+        setWillNotDraw(false);
+    }
+
+    @Override
+    public void onAddPagerView(String title) {
+        final TextView button = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.tab_menu_strip, this, false);
+        button.setText(title.toUpperCase());
+
+        addView(button);
+        button.setOnClickListener(new ViewClickListener(getChildCount() - 1));
+        button.setOnFocusChangeListener(this);
+    }
+
+    @Override
+    public void removeAllPagerViews() {
+        removeAllViews();
+    }
+
+    @Override
+    public void onPageSelected(final int position) {
+        mSelectedView = getChildAt(position);
+
+        // Callback to measure and draw the strip after the view is visible.
+        ViewTreeObserver vto = mSelectedView.getViewTreeObserver();
+        if (vto.isAlive()) {
+            vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+                @Override
+                public void onGlobalLayout() {
+                    mSelectedView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+
+                    if (mStrip != null) {
+                        mStrip.setBounds(mSelectedView.getLeft(),
+                                         mSelectedView.getTop(),
+                                         mSelectedView.getRight(),
+                                         mSelectedView.getBottom());
+                    }
+
+                    mPrevProgress = position;
+                }
+            });
+        }
+    }
+
+    // Page scroll animates the drawable and it's bounds from the previous to next child view.
+    @Override
+    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+        if (mStrip == null) {
+            return;
+        }
+
+        setScrollingData(position, positionOffset);
+
+        final int fromTabLeft =  fromTab.getLeft();
+        final int fromTabRight = fromTab.getRight();
+
+        final int toTabLeft =  toTab.getLeft();
+        final int toTabRight = toTab.getRight();
+
+        mStrip.setBounds((int) (fromTabLeft + ((toTabLeft - fromTabLeft) * progress)),
+                         0,
+                         (int) (fromTabRight + ((toTabRight - fromTabRight) * progress)),
+                         getHeight());
+        invalidate();
+    }
+
+    /*
+     * position + positionOffset goes from 0 to 2 as we scroll from page 1 to 3.
+     * Normalized progress is relative to the the direction the page is being scrolled towards.
+     * For this, we maintain direction of scroll with a state, and the child view we are moving towards and away from.
+     */
+    private void setScrollingData(int position, float positionOffset) {
+        if (position >= getChildCount() - 1) {
+            return;
+        }
+
+        final float currProgress = position + positionOffset;
+
+        if (mPrevProgress > currProgress) {
+            toTab = getChildAt(position);
+            fromTab = getChildAt(position + 1);
+            progress = 1 - positionOffset;
+        } else {
+            toTab = getChildAt(position + 1);
+            fromTab = getChildAt(position);
+            progress = positionOffset;
+        }
+
+        mPrevProgress = currProgress;
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        if (mStrip != null) {
+            mStrip.draw(canvas);
+        }
+    }
+
+    @Override
+    public void onFocusChange(View v, boolean hasFocus) {
+        if (v == this && hasFocus && getChildCount() > 0) {
+            mSelectedView.requestFocus();
+            return;
+        }
+
+        if (!hasFocus) {
+            return;
+        }
+
+        int i = 0;
+        final int numTabs = getChildCount();
+
+        while (i < numTabs) {
+            View view = getChildAt(i);
+            if (view == v) {
+                view.requestFocus();
+                if (isShown()) {
+                    // A view is focused so send an event to announce the menu strip state.
+                    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+                }
+                break;
+            }
+
+            i++;
+        }
+    }
+
+    @Override
+    public void setOnTitleClickListener(HomePager.OnTitleClickListener onTitleClickListener) {
+        mOnTitleClickListener = onTitleClickListener;
+    }
+
+    private class ViewClickListener implements OnClickListener {
+        private final int mIndex;
+
+        public ViewClickListener(int index) {
+            mIndex = index;
+        }
+
+        @Override
+        public void onClick(View view) {
+            if (mOnTitleClickListener != null) {
+                mOnTitleClickListener.onTitleClicked(mIndex);
+            }
+        }
+    }
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9ad4464c910cbb5fbea210cd615206a642e04104
GIT binary patch
literal 89
zc%17D@N?(olHy`uVBq!ia0vp^tU%1g!3HF2ET<R%DFsg#$B>F!$q5Y&|2-u18hHLq
nRy*;bp6hVE#IltNyB;&9E;Fy&_@+7psFuOg)z4*}Q$iB}uqGN|
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9ad4464c910cbb5fbea210cd615206a642e04104
GIT binary patch
literal 89
zc%17D@N?(olHy`uVBq!ia0vp^tU%1g!3HF2ET<R%DFsg#$B>F!$q5Y&|2-u18hHLq
nRy*;bp6hVE#IltNyB;&9E;Fy&_@+7psFuOg)z4*}Q$iB}uqGN|
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..448235e4109531faafe55e9ca1e553f40d4a94ac
GIT binary patch
literal 90
zc%17D@N?(olHy`uVBq!ia0vp^Y(UJ%0U~+k=c)oJMNb#UkcwN$2@MVZGbHpn`2Gb)
nHa+|=()RyE#R{(kZWo4?8?!Wfcd?296*G9c`njxgN@xNAx<MJ8
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/layout-large-v11/home_pager.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<!-- This file is used to include the home pager in gecko app
+     layout based on screen size -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:gecko="http://schemas.android.com/apk/res-auto">
+
+    <org.mozilla.gecko.home.HomePager android:id="@+id/home_pager"
+                                      android:layout_width="fill_parent"
+                                      android:layout_height="fill_parent"
+                                      android:background="@android:color/white"
+                                      android:visibility="gone">
+
+        <org.mozilla.gecko.home.TabMenuStrip android:layout_width="fill_parent"
+                                             android:layout_height="32dip"
+                                             android:background="@color/background_light"
+                                             android:layout_gravity="top"
+                                             gecko:strip="@drawable/home_tab_menu_strip"/>
+
+    </org.mozilla.gecko.home.HomePager>
+</merge>
--- a/mobile/android/base/resources/layout/gecko_app.xml
+++ b/mobile/android/base/resources/layout/gecko_app.xml
@@ -26,33 +26,17 @@
                         android:layout_above="@+id/find_in_page">
 
             <include layout="@layout/shared_ui_components"/>
 
             <FrameLayout android:id="@+id/home_pager_container"
                          android:layout_width="fill_parent"
                          android:layout_height="fill_parent">
 
-                <org.mozilla.gecko.home.HomePager android:id="@+id/home_pager"
-                                                  android:layout_width="fill_parent"
-                                                  android:layout_height="fill_parent"
-                                                  android:background="@android:color/white"
-                                                  android:visibility="gone"
-                                                  android:focusableInTouchMode="true"
-                                                  android:descendantFocusability="afterDescendants">
-
-                    <org.mozilla.gecko.home.HomePagerTabStrip android:layout_width="fill_parent"
-                                                              android:layout_height="32dip"
-                                                              android:layout_gravity="top"
-                                                              android:gravity="bottom"
-                                                              android:background="@color/background_light"
-                                                              gecko:tabIndicatorColor="@color/text_color_highlight"
-                                                              android:textAppearance="@style/TextAppearance.Widget.HomePagerTabStrip"/>
-
-                </org.mozilla.gecko.home.HomePager>
+                <include layout="@layout/home_pager"/>
 
             </FrameLayout>
 
         </RelativeLayout>
 
         <org.mozilla.gecko.FindInPageBar android:id="@+id/find_in_page"
                                          android:layout_width="fill_parent"
                                          android:layout_height="wrap_content"
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/layout/home_pager.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<!-- This file is used to include the home pager in gecko app
+     layout based on screen size -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:gecko="http://schemas.android.com/apk/res-auto">
+
+    <org.mozilla.gecko.home.HomePager android:id="@+id/home_pager"
+                                      android:layout_width="fill_parent"
+                                      android:layout_height="fill_parent"
+                                      android:background="@android:color/white"
+                                      android:visibility="gone">
+
+        <org.mozilla.gecko.home.HomePagerTabStrip android:layout_width="fill_parent"
+                                                  android:layout_height="32dip"
+                                                  android:layout_gravity="top"
+                                                  android:gravity="bottom"
+                                                  android:background="@color/background_light"
+                                                  gecko:tabIndicatorColor="@color/text_color_highlight"
+                                                  android:textAppearance="@style/TextAppearance.Widget.HomePagerTabStrip"/>
+
+    </org.mozilla.gecko.home.HomePager>
+</merge>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/layout/tab_menu_strip.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="wrap_content"
+          android:layout_height="fill_parent"
+          android:minWidth="@dimen/tabs_strip_button_width"
+          android:background="@drawable/tabs_panel_indicator"
+          android:paddingLeft="@dimen/tabs_strip_button_padding"
+          android:paddingRight="@dimen/tabs_strip_button_padding"
+          android:gravity="center"
+          android:focusable="true"
+          style="@style/TextAppearance.Widget.HomePagerTabMenuStrip"/>
--- a/mobile/android/base/resources/values/attrs.xml
+++ b/mobile/android/base/resources/values/attrs.xml
@@ -211,10 +211,14 @@
         </attr>
     </declare-styleable>
 
     <declare-styleable name="TopBookmarksView">
         <attr name="android:horizontalSpacing"/>
         <attr name="android:verticalSpacing"/>
     </declare-styleable>
 
+    <declare-styleable name="TabMenuStrip">
+        <attr name="strip" format="reference"/>
+    </declare-styleable>
+
 </resources>
 
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -60,16 +60,18 @@
     <dimen name="searchpreferences_icon_size">32dp</dimen>
     <dimen name="tab_thumbnail_height">90dp</dimen>
     <dimen name="tab_thumbnail_width">160dp</dimen>
     <dimen name="tabs_counter_size">22sp</dimen>
     <dimen name="tabs_panel_indicator_width">60dp</dimen>
     <dimen name="tabs_panel_list_padding">16dip</dimen>
     <dimen name="tabs_list_divider_height">2dp</dimen>
     <dimen name="tabs_sidebar_width">200dp</dimen>
+    <dimen name="tabs_strip_button_width">100dp</dimen>
+    <dimen name="tabs_strip_button_padding">18dp</dimen>
     <dimen name="tabs_tray_horizontal_height">156dp</dimen>
     <dimen name="text_selection_handle_width">47dp</dimen>
     <dimen name="text_selection_handle_height">58dp</dimen>
     <dimen name="text_selection_handle_shadow">11dp</dimen>
     <dimen name="top_bookmark_pinsize">20dp</dimen>
     <dimen name="validation_message_height">50dp</dimen>
     <dimen name="validation_message_margin_top">6dp</dimen>
     <dimen name="forward_default_offset">-13dip</dimen>
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -288,16 +288,21 @@
     <style name="TextAppearance.Widget.TextView">
         <item name="android:textColor">@color/primary_text</item>
     </style>
 
     <style name="TextAppearance.Widget.HomePagerTabStrip" parent="TextAppearance.Small">
         <item name="android:textColor">?android:attr/textColorHint</item>
     </style>
 
+    <style name="TextAppearance.Widget.HomePagerTabMenuStrip" parent="TextAppearance.Small">
+        <item name="android:textColor">?android:attr/textColorHint</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+
     <style name="TextAppearance.Widget.TwoLinePageRow" />
 
     <style name="TextAppearance.Widget.TwoLinePageRow.Title" parent="TextAppearance.Medium"/>
 
     <style name="TextAppearance.Widget.TwoLinePageRow.Url" parent="TextAppearance.Micro">
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>