Bug 1193745 - Implement the tablet tabs tray grid view on mobile r=mcomella
authorMartyn Haigh <mhaigh@mozilla.org>
Tue, 01 Sep 2015 13:57:44 +0100
changeset 260370 6ddd2771e1643911cedf92e8714da1fa26c1e74a
parent 260369 7499a1b1ea7c771fe8dffb60322a3d60be7fd2ae
child 260371 4aa12ff974247beecc4b131ddd6299f774163025
push id29308
push userryanvm@gmail.com
push dateWed, 02 Sep 2015 01:15:13 +0000
treeherdermozilla-central@fb720c90eb49 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcomella
bugs1193745
milestone43.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 1193745 - Implement the tablet tabs tray grid view on mobile r=mcomella
mobile/android/base/BrowserApp.java
mobile/android/base/moz.build
mobile/android/base/resources/layout/private_tabs_panel.xml
mobile/android/base/resources/layout/tabs_layout_item_view.xml
mobile/android/base/resources/layout/tabs_panel_default.xml
mobile/android/base/resources/values-land/dimens.xml
mobile/android/base/resources/values-sw240dp/dimens.xml
mobile/android/base/resources/values-sw400dp/dimens.xml
mobile/android/base/resources/values-xlarge-land-v11/dimens.xml
mobile/android/base/resources/values-xlarge-v11/dimens.xml
mobile/android/base/resources/values/dimens.xml
mobile/android/base/resources/values/styles.xml
mobile/android/base/tabs/PrivateTabsPanel.java
mobile/android/base/tabs/TabsGridLayout.java
mobile/android/base/tabs/TabsListLayout.java
mobile/android/base/tabs/TabsPanel.java
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -444,18 +444,16 @@ public class BrowserApp extends GeckoApp
         }
     }
 
     @Override
     public View onCreateView(final String name, final Context context, final AttributeSet attrs) {
         final View view;
         if (BrowserToolbar.class.getName().equals(name)) {
             view = BrowserToolbar.create(context, attrs);
-        } else if (TabsPanel.TabsLayout.class.getName().equals(name)) {
-            view = TabsPanel.createTabsLayout(context, attrs);
         } else {
             view = super.onCreateView(name, context, attrs);
         }
         return view;
     }
 
     @Override
     public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -465,17 +465,16 @@ gbjar.sources += [
     'tabs/TabHistoryController.java',
     'tabs/TabHistoryFragment.java',
     'tabs/TabHistoryItemRow.java',
     'tabs/TabHistoryPage.java',
     'tabs/TabPanelBackButton.java',
     'tabs/TabsGridLayout.java',
     'tabs/TabsLayoutAdapter.java',
     'tabs/TabsLayoutItemView.java',
-    'tabs/TabsListLayout.java',
     'tabs/TabsPanel.java',
     'tabs/TabsPanelThumbnailView.java',
     'Telemetry.java',
     'TelemetryContract.java',
     'TextSelection.java',
     'TextSelectionHandle.java',
     'ThumbnailHelper.java',
     'tiles/Tile.java',
--- a/mobile/android/base/resources/layout/private_tabs_panel.xml
+++ b/mobile/android/base/resources/layout/private_tabs_panel.xml
@@ -9,17 +9,17 @@
     <ImageView android:id="@+id/private_tabs_empty"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:src="@drawable/private_masq"
                android:layout_gravity="center"/>
 
     <!-- Note: for an unknown reason, scrolling in the TabsLayout
          does not work unless it is laid out after the empty view. -->
-    <view class="org.mozilla.gecko.tabs.TabsPanel$TabsLayout"
+    <org.mozilla.gecko.tabs.TabsGridLayout
           android:id="@+id/private_tabs_layout"
           style="@style/TabsLayout"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:choiceMode="singleChoice"
           gecko:tabs="tabs_private"/>
 
 </merge>
--- a/mobile/android/base/resources/layout/tabs_layout_item_view.xml
+++ b/mobile/android/base/resources/layout/tabs_layout_item_view.xml
@@ -11,19 +11,19 @@
                                            android:layout_height="wrap_content"
                                            android:gravity="center"
                                            android:orientation="vertical">
 
     <LinearLayout android:layout_width="fill_parent"
                   android:layout_height="wrap_content"
                   android:orientation="horizontal"
                   android:duplicateParentState="true"
-                  android:paddingLeft="@dimen/tablet_tab_highlight_stroke_width"
-                  android:paddingRight="@dimen/tablet_tab_highlight_stroke_width"
-                  android:paddingBottom="@dimen/tablet_tab_highlight_stroke_width">
+                  android:paddingLeft="@dimen/tab_highlight_stroke_width"
+                  android:paddingRight="@dimen/tab_highlight_stroke_width"
+                  android:paddingBottom="@dimen/tab_highlight_stroke_width">
 
        <org.mozilla.gecko.widget.FadedSingleColorTextView
                android:id="@+id/title"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                style="@style/TabLayoutItemTextAppearance"
                android:textSize="14sp"
@@ -57,20 +57,20 @@
 
     </LinearLayout>
 
     <!-- We set state_private on this View dynamically in TabsGridLayout. -->
     <org.mozilla.gecko.widget.TabThumbnailWrapper
             android:id="@+id/wrapper"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:padding="@dimen/tablet_tab_highlight_stroke_width"
+            android:padding="@dimen/tab_highlight_stroke_width"
             android:background="@drawable/tab_thumbnail"
             android:duplicateParentState="true">
 
         <org.mozilla.gecko.tabs.TabsPanelThumbnailView android:id="@+id/thumbnail"
-                                                       android:layout_width="@dimen/tablet_tab_thumbnail_width"
-                                                       android:layout_height="@dimen/tablet_tab_thumbnail_height"
+                                                       android:layout_width="@dimen/tab_thumbnail_width"
+                                                       android:layout_height="@dimen/tab_thumbnail_height"
                                                 />
 
     </org.mozilla.gecko.widget.TabThumbnailWrapper>
 
 </org.mozilla.gecko.tabs.TabsLayoutItemView>
--- a/mobile/android/base/resources/layout/tabs_panel_default.xml
+++ b/mobile/android/base/resources/layout/tabs_panel_default.xml
@@ -61,17 +61,17 @@
 
     </RelativeLayout>
 
     <FrameLayout
           android:id="@+id/tabs_container"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
 
-        <view class="org.mozilla.gecko.tabs.TabsPanel$TabsLayout"
+        <org.mozilla.gecko.tabs.TabsGridLayout
               android:id="@+id/normal_tabs"
               style="@style/TabsLayout"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:choiceMode="singleChoice"
               android:visibility="gone"
               gecko:tabs="tabs_normal"/>
 
--- a/mobile/android/base/resources/values-land/dimens.xml
+++ b/mobile/android/base/resources/values-land/dimens.xml
@@ -4,10 +4,10 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <resources>
 
     <!-- Remote Tabs static view top padding. Less in landscape on phones. -->
     <dimen name="home_remote_tabs_top_padding">16dp</dimen>
     <dimen name="page_group_height">64dp</dimen>
 
-    <dimen name="tablet_tab_panel_grid_padding">48dp</dimen>
+    <dimen name="tab_panel_grid_padding">48dp</dimen>
 </resources>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/values-sw240dp/dimens.xml
@@ -0,0 +1,10 @@
+<?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/. -->
+
+<resources>
+    <dimen name="tab_panel_column_width">143dip</dimen>
+    <dimen name="tab_thumbnail_height">100dip</dimen>
+    <dimen name="tab_thumbnail_width">135dip</dimen>
+</resources>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/values-sw400dp/dimens.xml
@@ -0,0 +1,10 @@
+<?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/. -->
+
+<resources>
+    <dimen name="tab_panel_column_width">174dip</dimen>
+    <dimen name="tab_thumbnail_height">120dip</dimen>
+    <dimen name="tab_thumbnail_width">168dip</dimen>
+</resources>
--- a/mobile/android/base/resources/values-xlarge-land-v11/dimens.xml
+++ b/mobile/android/base/resources/values-xlarge-land-v11/dimens.xml
@@ -1,10 +1,10 @@
 <?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/. -->
 
 <resources>
 
-    <dimen name="tablet_tab_panel_grid_padding">64dp</dimen>
+    <dimen name="tab_panel_grid_padding">64dp</dimen>
 
 </resources>
--- a/mobile/android/base/resources/values-xlarge-v11/dimens.xml
+++ b/mobile/android/base/resources/values-xlarge-v11/dimens.xml
@@ -1,11 +1,11 @@
 <?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/. -->
 
 <resources>
 
     <dimen name="panel_grid_view_column_width">250dp</dimen>
-    <dimen name="tablet_tab_panel_grid_padding">48dp</dimen>
+    <dimen name="tab_panel_grid_padding">48dp</dimen>
 
 </resources>
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -125,39 +125,37 @@
     <dimen name="menu_popup_width">256dp</dimen>
     <dimen name="nav_button_border_width">1dp</dimen>
     <dimen name="prompt_service_group_padding_size">32dp</dimen>
     <dimen name="prompt_service_icon_size">36dp</dimen>
     <dimen name="prompt_service_icon_text_padding">10dp</dimen>
     <dimen name="prompt_service_inputs_padding">16dp</dimen>
     <dimen name="prompt_service_left_right_text_with_icon_padding">10dp</dimen>
     <dimen name="prompt_service_top_bottom_text_with_icon_padding">8dp</dimen>
-    <dimen name="tab_thumbnail_height">90dp</dimen>
-    <dimen name="tab_thumbnail_width">160dp</dimen>
     <dimen name="tabs_panel_indicator_width">60dp</dimen>
     <dimen name="tabs_panel_button_width">48dp</dimen>
     <dimen name="tabs_strip_height">48dp</dimen>
     <dimen name="tabs_strip_button_width">100dp</dimen>
     <dimen name="tabs_strip_button_padding">18dp</dimen>
     <dimen name="tabs_strip_shadow_size">1dp</dimen>
     <dimen name="tabs_layout_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="validation_message_height">50dp</dimen>
     <dimen name="validation_message_margin_top">6dp</dimen>
 
-    <dimen name="tablet_tab_thumbnail_width">168dp</dimen>
-    <dimen name="tablet_tab_thumbnail_height">140dp</dimen>
-    <dimen name="tablet_tab_panel_column_width">178dp</dimen>
-    <dimen name="tablet_tab_panel_grid_padding">19dp</dimen>
-    <dimen name="tablet_tab_panel_grid_vspacing">21dp</dimen>
-    <dimen name="tablet_tab_panel_grid_padding_top">24dp</dimen>
+    <dimen name="tab_thumbnail_width">121dp</dimen>
+    <dimen name="tab_thumbnail_height">90dp</dimen>
+    <dimen name="tab_panel_column_width">129dp</dimen>
+    <dimen name="tab_panel_grid_padding">20dp</dimen>
+    <dimen name="tab_panel_grid_vspacing">20dp</dimen>
+    <dimen name="tab_panel_grid_padding_top">19dp</dimen>
 
-    <dimen name="tablet_tab_highlight_stroke_width">5dp</dimen>
+    <dimen name="tab_highlight_stroke_width">4dp</dimen>
 
     <!-- PageActionButtons dimensions -->
     <dimen name="page_action_button_width">32dp</dimen>
 
     <!-- Banner -->
     <dimen name="home_banner_height">72dp</dimen>
     <dimen name="home_banner_close_width">42dp</dimen>
     <dimen name="home_banner_icon_height">48dip</dimen>
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -200,19 +200,19 @@
     <style name="Widget.TabsGridLayout" parent="Widget.GridView">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">match_parent</item>
         <item name="android:paddingTop">0dp</item>
         <item name="android:stretchMode">spacingWidth</item>
         <item name="android:scrollbarStyle">outsideOverlay</item>
         <item name="android:gravity">center</item>
         <item name="android:numColumns">auto_fit</item>
-        <item name="android:columnWidth">@dimen/tablet_tab_panel_column_width</item>
+        <item name="android:columnWidth">@dimen/tab_panel_column_width</item>
         <item name="android:horizontalSpacing">2dp</item>
-        <item name="android:verticalSpacing">@dimen/tablet_tab_panel_grid_vspacing</item>
+        <item name="android:verticalSpacing">@dimen/tab_panel_grid_vspacing</item>
         <item name="android:drawSelectorOnTop">true</item>
         <item name="android:clipToPadding">false</item>
     </style>
 
     <style name="Widget.BookmarkItemView" parent="Widget.TwoLinePageRow"/>
 
     <style name="Widget.BookmarksListView" parent="Widget.HomeListView"/>
 
--- a/mobile/android/base/tabs/PrivateTabsPanel.java
+++ b/mobile/android/base/tabs/PrivateTabsPanel.java
@@ -8,58 +8,51 @@ package org.mozilla.gecko.tabs;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.tabs.TabsPanel.CloseAllPanelView;
 import org.mozilla.gecko.tabs.TabsPanel.TabsLayout;
 
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.FrameLayout;
-import android.widget.LinearLayout;
 
 /**
  * A container that wraps the private tabs {@link android.widget.AdapterView} and empty
  * {@link android.view.View} to manage both of their visibility states by changing the visibility of
  * this container as calling {@link android.widget.AdapterView#setVisibility} does not affect the
  * empty View's visibility.
  */
 class PrivateTabsPanel extends FrameLayout implements CloseAllPanelView {
     private final TabsLayout tabsLayout;
 
-    public PrivateTabsPanel(Context context, AttributeSet attrs) {
+    public PrivateTabsPanel(final Context context, final AttributeSet attrs) {
         super(context, attrs);
 
         LayoutInflater.from(context).inflate(R.layout.private_tabs_panel, this);
         tabsLayout = (TabsLayout) findViewById(R.id.private_tabs_layout);
 
         final View emptyTabsFrame = findViewById(R.id.private_tabs_empty);
         tabsLayout.setEmptyView(emptyTabsFrame);
     }
 
     @Override
-    public void setTabsPanel(TabsPanel panel) {
+    public void setTabsPanel(final TabsPanel panel) {
         tabsLayout.setTabsPanel(panel);
     }
 
     @Override
     public void show() {
         tabsLayout.show();
         setVisibility(View.VISIBLE);
     }
 
     @Override
     public void hide() {
         setVisibility(View.GONE);
         tabsLayout.hide();
     }
 
     @Override
-    public boolean shouldExpand() {
-        return tabsLayout.shouldExpand();
-    }
-
-    @Override
     public void closeAll() {
         tabsLayout.closeAll();
     }
 }
--- a/mobile/android/base/tabs/TabsGridLayout.java
+++ b/mobile/android/base/tabs/TabsGridLayout.java
@@ -1,30 +1,31 @@
 /* -*- 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.tabs;
 
+import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.animation.PropertyAnimator;
-import org.mozilla.gecko.animation.ViewHelper;
 import org.mozilla.gecko.tabs.TabsPanel.TabsLayout;
 import org.mozilla.gecko.widget.themed.ThemedRelativeLayout;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
@@ -33,70 +34,68 @@ import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.Button;
 import android.widget.GridView;
 import com.nineoldandroids.animation.Animator;
 import com.nineoldandroids.animation.AnimatorSet;
 import com.nineoldandroids.animation.ObjectAnimator;
 import com.nineoldandroids.animation.PropertyValuesHolder;
 import com.nineoldandroids.animation.ValueAnimator;
+import com.nineoldandroids.view.ViewHelper;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /**
- * A tabs layout implementation for the tablet redesign (bug 1014156).
- * Expected to replace TabsListLayout once complete.
+ * A tabs layout implementation for the tablet redesign (bug 1014156) and later ported to mobile (bug 1193745).
  */
 
 class TabsGridLayout extends GridView
                      implements TabsLayout,
                                 Tabs.OnTabsChangedListener {
     private static final String LOGTAG = "Gecko" + TabsGridLayout.class.getSimpleName();
 
     public static final int ANIM_DELAY_MULTIPLE_MS = 20;
     private static final int ANIM_TIME_MS = 200;
     private static final DecelerateInterpolator ANIM_INTERPOLATOR = new DecelerateInterpolator();
 
-    private final Context mContext;
-    private final SparseArray<PointF> mTabLocations = new SparseArray<PointF>();
-    private final boolean mIsPrivate;
-    private final TabsLayoutAdapter mTabsAdapter;
-    private final int mColumnWidth;
-    private TabsPanel mTabsPanel;
+    private final SparseArray<PointF> tabLocations = new SparseArray<PointF>();
+    private final boolean isPrivate;
+    private final TabsLayoutAdapter tabsAdapter;
+    private final int columnWidth;
+    private TabsPanel tabsPanel;
     private int lastSelectedTabId;
 
-    public TabsGridLayout(Context context, AttributeSet attrs) {
+    public TabsGridLayout(final Context context, final AttributeSet attrs) {
         super(context, attrs, R.attr.tabGridLayoutViewStyle);
-        mContext = context;
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabsLayout);
-        mIsPrivate = (a.getInt(R.styleable.TabsLayout_tabs, 0x0) == 1);
+        isPrivate = (a.getInt(R.styleable.TabsLayout_tabs, 0x0) == 1);
         a.recycle();
 
-        mTabsAdapter = new TabsGridLayoutAdapter(mContext);
-        setAdapter(mTabsAdapter);
+        tabsAdapter = new TabsGridLayoutAdapter(context);
+        setAdapter(tabsAdapter);
 
         setRecyclerListener(new RecyclerListener() {
             @Override
             public void onMovedToScrapHeap(View view) {
                 TabsLayoutItemView item = (TabsLayoutItemView) view;
                 item.setThumbnail(null);
             }
         });
 
         // The clipToPadding setting in the styles.xml doesn't seem to be working (bug 1101784)
         // so lets set it manually in code for the moment as it's needed for the padding animation
         setClipToPadding(false);
 
         final Resources resources = getResources();
-        mColumnWidth = resources.getDimensionPixelSize(R.dimen.tablet_tab_panel_column_width);
+        columnWidth = resources.getDimensionPixelSize(R.dimen.tab_panel_column_width);
 
-        final int padding = resources.getDimensionPixelSize(R.dimen.tablet_tab_panel_grid_padding);
-        final int paddingTop = resources.getDimensionPixelSize(R.dimen.tablet_tab_panel_grid_padding_top);
+        final int padding = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_padding);
+        final int paddingTop = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_padding_top);
 
         // Lets set double the top padding on the bottom so that the last row shows up properly!
         // Your demise, GridView, cannot come fast enough.
         final int paddingBottom = paddingTop * 2;
 
         setPadding(padding, paddingTop, padding, paddingBottom);
 
         setOnItemClickListener(new OnItemClickListener() {
@@ -109,45 +108,46 @@ class TabsGridLayout extends GridView
         });
 
         TabSwipeGestureListener mSwipeListener = new TabSwipeGestureListener();
         setOnTouchListener(mSwipeListener);
         setOnScrollListener(mSwipeListener.makeScrollListener());
     }
 
     private void populateTabLocations(final Tab removedTab) {
-        mTabLocations.clear();
+        tabLocations.clear();
 
         final int firstPosition = getFirstVisiblePosition();
         final int lastPosition = getLastVisiblePosition();
         final int numberOfColumns = getNumColumns();
         final int childCount = getChildCount();
-        final int removedPosition = mTabsAdapter.getPositionForTab(removedTab);
+        final int removedPosition = tabsAdapter.getPositionForTab(removedTab);
 
         for (int x = 1, i = (removedPosition - firstPosition) + 1; i < childCount; i++, x++) {
             final View child = getChildAt(i);
             if (child != null) {
                 // Reset the transformations here in case the user is swiping tabs away fast and they swipe a tab
                 // before the last animation has finished (bug 1179195).
                 resetTransforms(child);
-                mTabLocations.append(x, new PointF(child.getX(), child.getY()));
+
+                tabLocations.append(x, new PointF(child.getX(), child.getY()));
             }
         }
 
         final boolean firstChildOffScreen = ((firstPosition > 0) || getChildAt(0).getY() < 0);
         final boolean lastChildVisible = (lastPosition - childCount == firstPosition - 1);
         final boolean oneItemOnLastRow = (lastPosition % numberOfColumns == 0);
         if (firstChildOffScreen && lastChildVisible && oneItemOnLastRow) {
             // We need to set the view's bottom padding to prevent a sudden jump as the
             // last item in the row is being removed. We then need to remove the padding
             // via a sweet animation
 
             final int removedHeight = getChildAt(0).getMeasuredHeight();
             final int verticalSpacing =
-                    getResources().getDimensionPixelOffset(R.dimen.tablet_tab_panel_grid_vspacing);
+                    getResources().getDimensionPixelOffset(R.dimen.tab_panel_grid_vspacing);
 
             ValueAnimator paddingAnimator = ValueAnimator.ofInt(getPaddingBottom() + removedHeight + verticalSpacing, getPaddingBottom());
             paddingAnimator.setDuration(ANIM_TIME_MS * 2);
 
             paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
 
                 @Override
                 public void onAnimationUpdate(ValueAnimator animation) {
@@ -155,68 +155,65 @@ class TabsGridLayout extends GridView
                 }
             });
             paddingAnimator.start();
         }
     }
 
     @Override
     public void setTabsPanel(TabsPanel panel) {
-        mTabsPanel = panel;
+        tabsPanel = panel;
     }
 
     @Override
     public void show() {
         setVisibility(View.VISIBLE);
         Tabs.getInstance().refreshThumbnails();
         Tabs.registerOnTabsChangedListener(this);
         refreshTabsData();
 
         Tab currentlySelectedTab = Tabs.getInstance().getSelectedTab();
         if (lastSelectedTabId != currentlySelectedTab.getId()) {
-            smoothScrollToPosition(mTabsAdapter.getPositionForTab(currentlySelectedTab));
+            smoothScrollToPosition(tabsAdapter.getPositionForTab(currentlySelectedTab));
         }
     }
 
     @Override
     public void hide() {
         lastSelectedTabId = Tabs.getInstance().getSelectedTab().getId();
         setVisibility(View.GONE);
         Tabs.unregisterOnTabsChangedListener(this);
         GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Screenshot:Cancel", ""));
-        mTabsAdapter.clear();
-    }
-
-    @Override
-    public boolean shouldExpand() {
-        return true;
+        tabsAdapter.clear();
     }
 
     private void autoHidePanel() {
-        mTabsPanel.autoHidePanel();
+        tabsPanel.autoHidePanel();
     }
 
     @Override
     public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
         switch (msg) {
             case ADDED:
                 // Refresh the list to make sure the new tab is added in the right position.
                 refreshTabsData();
                 break;
 
             case CLOSED:
-                if (mTabsAdapter.getCount() > 0) {
+
+                // This is limited to >= ICS as animations on GB devices are generally pants
+                if (Build.VERSION.SDK_INT >= 11 && tabsAdapter.getCount() > 0) {
                     animateRemoveTab(tab);
                 }
 
                 final Tabs tabsInstance = Tabs.getInstance();
 
-                if (mTabsAdapter.removeTab(tab)) {
-                    if (tab.isPrivate() == mIsPrivate && mTabsAdapter.getCount() > 0) {
-                        int selected = mTabsAdapter.getPositionForTab(tabsInstance.getSelectedTab());
+                if (tabsAdapter.removeTab(tab)) {
+                    if (tab.isPrivate() == isPrivate && tabsAdapter.getCount() > 0) {
+                        int selected = tabsAdapter.getPositionForTab(tabsInstance.getSelectedTab());
                         updateSelectedStyle(selected);
                     }
                     if (!tab.isPrivate()) {
                         // Make sure we always have at least one normal tab
                         final Iterable<Tab> tabs = tabsInstance.getTabsInOrder();
                         boolean removedTabIsLastNormalTab = true;
                         for (Tab singleTab : tabs) {
                             if (!singleTab.isPrivate()) {
@@ -235,58 +232,63 @@ class TabsGridLayout extends GridView
                 // Update the selected position, then fall through...
                 updateSelectedPosition();
             case UNSELECTED:
                 // We just need to update the style for the unselected tab...
             case THUMBNAIL:
             case TITLE:
             case RECORDING_CHANGE:
             case AUDIO_PLAYING_CHANGE:
-                View view = getChildAt(mTabsAdapter.getPositionForTab(tab) - getFirstVisiblePosition());
+                View view = getChildAt(tabsAdapter.getPositionForTab(tab) - getFirstVisiblePosition());
                 if (view == null)
                     return;
 
                 ((TabsLayoutItemView) view).assignValues(tab);
                 break;
         }
     }
 
     // Updates the selected position in the list so that it will be scrolled to the right place.
     private void updateSelectedPosition() {
-        int selected = mTabsAdapter.getPositionForTab(Tabs.getInstance().getSelectedTab());
+        int selected = tabsAdapter.getPositionForTab(Tabs.getInstance().getSelectedTab());
         updateSelectedStyle(selected);
 
         if (selected != -1) {
             setSelection(selected);
         }
     }
 
     /**
      * Updates the selected/unselected style for the tabs.
      *
      * @param selected position of the selected tab
      */
     private void updateSelectedStyle(int selected) {
-        for (int i = 0; i < mTabsAdapter.getCount(); i++) {
-            setItemChecked(i, (i == selected));
+        for (int i = 0; i < tabsAdapter.getCount(); i++) {
+            // setItemChecked doesn't exist until API 11, despite what the API docs say!
+            if (AppConstants.Versions.feature11Plus) {
+                setItemChecked(i, (i == selected));
+            } else {
+                setSelection(i);
+            }
         }
     }
 
     private void refreshTabsData() {
         // Store a different copy of the tabs, so that we don't have to worry about
         // accidentally updating it on the wrong thread.
         ArrayList<Tab> tabData = new ArrayList<>();
 
         Iterable<Tab> allTabs = Tabs.getInstance().getTabsInOrder();
         for (Tab tab : allTabs) {
-            if (tab.isPrivate() == mIsPrivate)
+            if (tab.isPrivate() == isPrivate)
                 tabData.add(tab);
         }
 
-        mTabsAdapter.setTabs(tabData);
+        tabsAdapter.setTabs(tabData);
         updateSelectedPosition();
     }
 
     private void resetTransforms(View view) {
         ViewHelper.setAlpha(view, 1);
         ViewHelper.setTranslationX(view, 0);
         ViewHelper.setTranslationY(view, 0);
 
@@ -301,36 +303,36 @@ class TabsGridLayout extends GridView
         if (getChildCount() == 0) {
             return;
         }
 
         final Iterable<Tab> tabs = Tabs.getInstance().getTabsInOrder();
         for (Tab tab : tabs) {
             // In the normal panel we want to close all tabs (both private and normal),
             // but in the private panel we only want to close private tabs.
-            if (!mIsPrivate || tab.isPrivate()) {
+            if (!isPrivate || tab.isPrivate()) {
                 Tabs.getInstance().closeTab(tab, false);
             }
         }
     }
 
     private View getViewForTab(Tab tab) {
-        final int position = mTabsAdapter.getPositionForTab(tab);
+        final int position = tabsAdapter.getPositionForTab(tab);
         return getChildAt(position - getFirstVisiblePosition());
     }
 
     void closeTab(View v) {
         TabsLayoutItemView itemView = (TabsLayoutItemView) v.getTag();
         Tab tab = Tabs.getInstance().getTab(itemView.getTabId());
 
         Tabs.getInstance().closeTab(tab, true);
     }
 
     private void animateRemoveTab(final Tab removedTab) {
-        final int removedPosition = mTabsAdapter.getPositionForTab(removedTab);
+        final int removedPosition = tabsAdapter.getPositionForTab(removedTab);
 
         final View removedView = getViewForTab(removedTab);
 
         // The removed position might not have a matching child view
         // when it's not within the visible range of positions in the strip.
         if (removedView == null) {
             return;
         }
@@ -353,22 +355,22 @@ class TabsGridLayout extends GridView
 
                 PropertyValuesHolder translateX, translateY;
                 for (int x = 0, i = removedPosition - firstPosition; i < childCount; i++, x++) {
                     final View child = getChildAt(i);
                     ObjectAnimator animator;
 
                     if (i % numberOfColumns == numberOfColumns - 1) {
                         // Animate X & Y
-                        translateX = PropertyValuesHolder.ofFloat("translationX", -(mColumnWidth * numberOfColumns), 0);
+                        translateX = PropertyValuesHolder.ofFloat("translationX", -(columnWidth * numberOfColumns), 0);
                         translateY = PropertyValuesHolder.ofFloat("translationY", removedHeight, 0);
                         animator = ObjectAnimator.ofPropertyValuesHolder(child, translateX, translateY);
                     } else {
                         // Just animate X
-                        translateX = PropertyValuesHolder.ofFloat("translationX", mColumnWidth, 0);
+                        translateX = PropertyValuesHolder.ofFloat("translationX", columnWidth, 0);
                         animator = ObjectAnimator.ofPropertyValuesHolder(child, translateX);
                     }
                     animator.setStartDelay(x * ANIM_DELAY_MULTIPLE_MS);
                     childAnimators.add(animator);
                 }
 
                 final AnimatorSet animatorSet = new AnimatorSet();
                 animatorSet.playTogether(childAnimators);
@@ -377,30 +379,31 @@ class TabsGridLayout extends GridView
                 animatorSet.start();
 
                 // Set the starting position of the child views - because we are delaying the start
                 // of the animation, we need to prevent the items being drawn in their final position
                 // prior to the animation starting
                 for (int x = 1, i = (removedPosition - firstPosition) + 1; i < childCount; i++, x++) {
                     final View child = getChildAt(i);
 
-                    final PointF targetLocation = mTabLocations.get(x + 1);
+                    final PointF targetLocation = tabLocations.get(x + 1);
                     if (targetLocation == null) {
                         continue;
                     }
 
                     child.setX(targetLocation.x);
                     child.setY(targetLocation.y);
                 }
 
                 return true;
             }
         });
     }
 
+
     private void animateCancel(final View view) {
         PropertyAnimator animator = new PropertyAnimator(ANIM_TIME_MS);
         animator.attach(view, PropertyAnimator.Property.ALPHA, 1);
         animator.attach(view, PropertyAnimator.Property.TRANSLATION_X, 0);
 
         animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
             @Override
             public void onPropertyAnimationStart() {
@@ -431,17 +434,17 @@ class TabsGridLayout extends GridView
             };
         }
 
         @Override
         TabsLayoutItemView newView(int position, ViewGroup parent) {
             final TabsLayoutItemView item = super.newView(position, parent);
 
             item.setCloseOnClickListener(mCloseClickListener);
-            ((ThemedRelativeLayout) item.findViewById(R.id.wrapper)).setPrivateMode(mIsPrivate);
+            ((ThemedRelativeLayout) item.findViewById(R.id.wrapper)).setPrivateMode(isPrivate);
 
             return item;
         }
 
         @Override
         public void bindView(TabsLayoutItemView view, Tab tab) {
             super.bindView(view, tab);
 
deleted file mode 100644
--- a/mobile/android/base/tabs/TabsListLayout.java
+++ /dev/null
@@ -1,660 +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.tabs;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.mozilla.gecko.animation.PropertyAnimator.Property;
-import org.mozilla.gecko.animation.PropertyAnimator;
-import org.mozilla.gecko.animation.ViewHelper;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.GeckoEvent;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.Tab;
-import org.mozilla.gecko.tabs.TabsPanel.TabsLayout;
-import org.mozilla.gecko.Tabs;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.widget.themed.ThemedRelativeLayout;
-import org.mozilla.gecko.widget.TwoWayView;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewConfiguration;
-import android.widget.Button;
-
-class TabsListLayout extends TwoWayView
-                     implements TabsLayout,
-                                Tabs.OnTabsChangedListener {
-    private static final String LOGTAG = "Gecko" + TabsListLayout.class.getSimpleName();
-
-    private final Context mContext;
-    private TabsPanel mTabsPanel;
-
-    final private boolean mIsPrivate;
-
-    private final TabsLayoutAdapter mTabsAdapter;
-
-    private final List<View> mPendingClosedTabs;
-    private int mCloseAnimationCount;
-    private int mCloseAllAnimationCount;
-
-    private final TabSwipeGestureListener mSwipeListener;
-
-    // Time to animate non-flinged tabs of screen, in milliseconds
-    private static final int ANIMATION_DURATION = 250;
-
-    // Time between starting successive tab animations in closeAllTabs.
-    private static final int ANIMATION_CASCADE_DELAY = 75;
-
-    private int mOriginalSize;
-
-    public TabsListLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mContext = context;
-
-        mPendingClosedTabs = new ArrayList<View>();
-
-        setItemsCanFocus(true);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabsLayout);
-        mIsPrivate = (a.getInt(R.styleable.TabsLayout_tabs, 0x0) == 1);
-        a.recycle();
-
-        mTabsAdapter = new TabsListLayoutAdapter(mContext);
-        setAdapter(mTabsAdapter);
-
-        mSwipeListener = new TabSwipeGestureListener();
-        setOnTouchListener(mSwipeListener);
-        setOnScrollListener(mSwipeListener.makeScrollListener());
-
-        setRecyclerListener(new RecyclerListener() {
-            @Override
-            public void onMovedToScrapHeap(View view) {
-                TabsLayoutItemView item = (TabsLayoutItemView) view;
-                item.setThumbnail(null);
-                item.setCloseVisible(true);
-            }
-        });
-    }
-
-    private class TabsListLayoutAdapter extends TabsLayoutAdapter {
-        private final Button.OnClickListener mCloseOnClickListener;
-        public TabsListLayoutAdapter (Context context) {
-            super(context, R.layout.tabs_layout_item_view);
-
-            mCloseOnClickListener = new Button.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    // The view here is the close button, which has a reference
-                    // to the parent TabsLayoutItemView in it's tag, hence the getTag() call
-                    TabsLayoutItemView item = (TabsLayoutItemView) v.getTag();
-                    final int pos = (isVertical() ? item.getWidth() : 0 - item.getHeight());
-                    animateClose(item, pos);
-                }
-            };
-        }
-
-        @Override
-        public TabsLayoutItemView newView(int position, ViewGroup parent) {
-            TabsLayoutItemView item = super.newView(position, parent);
-
-            item.setCloseOnClickListener(mCloseOnClickListener);
-            ((ThemedRelativeLayout) item.findViewById(R.id.wrapper)).setPrivateMode(mIsPrivate);
-
-            return item;
-        }
-
-        @Override
-        public void bindView(TabsLayoutItemView view, Tab tab) {
-            super.bindView(view, tab);
-
-            // If we're recycling this view, there's a chance it was transformed during
-            // the close animation. Remove any of those properties.
-            resetTransforms(view);
-        }
-
-    }
-
-    @Override
-    public void setTabsPanel(TabsPanel panel) {
-        mTabsPanel = panel;
-    }
-
-    @Override
-    public void show() {
-        setVisibility(View.VISIBLE);
-        Tabs.getInstance().refreshThumbnails();
-        Tabs.registerOnTabsChangedListener(this);
-        refreshTabsData();
-    }
-
-    @Override
-    public void hide() {
-        setVisibility(View.GONE);
-        Tabs.unregisterOnTabsChangedListener(this);
-        GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Screenshot:Cancel",""));
-        mTabsAdapter.clear();
-    }
-
-    @Override
-    public boolean shouldExpand() {
-        return isVertical();
-    }
-
-    private void autoHidePanel() {
-        mTabsPanel.autoHidePanel();
-    }
-
-    @Override
-    public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
-        switch (msg) {
-            case ADDED:
-                // Refresh the list to make sure the new tab is added in the right position.
-                refreshTabsData();
-                break;
-
-            case CLOSED:
-               if (tab.isPrivate() == mIsPrivate && mTabsAdapter.getCount() > 0) {
-                   if (mTabsAdapter.removeTab(tab)) {
-                       int selected = mTabsAdapter.getPositionForTab(Tabs.getInstance().getSelectedTab());
-                       updateSelectedStyle(selected);
-                   }
-               }
-               break;
-
-            case SELECTED:
-                // Update the selected position, then fall through...
-                updateSelectedPosition();
-            case UNSELECTED:
-                // We just need to update the style for the unselected tab...
-            case THUMBNAIL:
-            case TITLE:
-            case RECORDING_CHANGE:
-            case AUDIO_PLAYING_CHANGE:
-                View view = getChildAt(mTabsAdapter.getPositionForTab(tab) - getFirstVisiblePosition());
-                if (view == null)
-                    return;
-
-                TabsLayoutItemView item = (TabsLayoutItemView) view;
-                item.assignValues(tab);
-                break;
-        }
-    }
-
-    // Updates the selected position in the list so that it will be scrolled to the right place.
-    private void updateSelectedPosition() {
-        int selected = mTabsAdapter.getPositionForTab(Tabs.getInstance().getSelectedTab());
-        updateSelectedStyle(selected);
-
-        if (selected != -1) {
-            setSelection(selected);
-        }
-    }
-
-    /**
-     * Updates the selected/unselected style for the tabs.
-     *
-     * @param selected position of the selected tab
-     */
-    private void updateSelectedStyle(int selected) {
-        for (int i = 0; i < mTabsAdapter.getCount(); i++) {
-            setItemChecked(i, (i == selected));
-        }
-    }
-
-    private void refreshTabsData() {
-        // Store a different copy of the tabs, so that we don't have to worry about
-        // accidentally updating it on the wrong thread.
-        ArrayList<Tab> tabData = new ArrayList<Tab>();
-
-        Iterable<Tab> allTabs = Tabs.getInstance().getTabsInOrder();
-        for (Tab tab : allTabs) {
-            if (tab.isPrivate() == mIsPrivate)
-                tabData.add(tab);
-        }
-
-        mTabsAdapter.setTabs(tabData);
-        updateSelectedPosition();
-    }
-
-    public void resetTransforms(View view) {
-        ViewHelper.setAlpha(view, 1);
-
-        if (isVertical()) {
-            ViewHelper.setTranslationX(view, 0);
-        } else {
-            ViewHelper.setTranslationY(view, 0);
-        }
-
-        // We only need to reset the height or width after individual tab close animations.
-        if (mOriginalSize != 0) {
-            if (isVertical()) {
-                ViewHelper.setHeight(view, mOriginalSize);
-            } else {
-                ViewHelper.setWidth(view, mOriginalSize);
-            }
-        }
-    }
-
-    private boolean isVertical() {
-        return (getOrientation().compareTo(TwoWayView.Orientation.VERTICAL) == 0);
-    }
-
-    @Override
-    public void closeAll() {
-        final int childCount = getChildCount();
-
-        // Just close the panel if there are no tabs to close.
-        if (childCount == 0) {
-            autoHidePanel();
-            return;
-        }
-
-        // Disable the view so that gestures won't interfere wth the tab close animation.
-        setEnabled(false);
-
-        // Delay starting each successive animation to create a cascade effect.
-        int cascadeDelay = 0;
-
-        for (int i = childCount - 1; i >= 0; i--) {
-            final View view = getChildAt(i);
-            final PropertyAnimator animator = new PropertyAnimator(ANIMATION_DURATION);
-            animator.attach(view, Property.ALPHA, 0);
-
-            if (isVertical()) {
-                animator.attach(view, Property.TRANSLATION_X, view.getWidth());
-            } else {
-                animator.attach(view, Property.TRANSLATION_Y, view.getHeight());
-            }
-
-            mCloseAllAnimationCount++;
-
-            animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
-                @Override
-                public void onPropertyAnimationStart() { }
-
-                @Override
-                public void onPropertyAnimationEnd() {
-                    mCloseAllAnimationCount--;
-                    if (mCloseAllAnimationCount > 0) {
-                        return;
-                    }
-
-                    // Hide the panel after the animation is done.
-                    autoHidePanel();
-
-                    // Re-enable the view after the animation is done.
-                    TabsListLayout.this.setEnabled(true);
-
-                    // Then actually close all the tabs.
-                    final Iterable<Tab> tabs = Tabs.getInstance().getTabsInOrder();
-                    for (Tab tab : tabs) {
-                        // In the normal panel we want to close all tabs (both private and normal),
-                        // but in the private panel we only want to close private tabs.
-                        if (!mIsPrivate || tab.isPrivate()) {
-                            Tabs.getInstance().closeTab(tab, false);
-                        }
-                    }
-                }
-            });
-
-            ThreadUtils.getUiHandler().postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    animator.start();
-                }
-            }, cascadeDelay);
-
-            cascadeDelay += ANIMATION_CASCADE_DELAY;
-        }
-    }
-
-    private void animateClose(final View view, int pos) {
-        PropertyAnimator animator = new PropertyAnimator(ANIMATION_DURATION);
-        animator.attach(view, Property.ALPHA, 0);
-
-        if (isVertical())
-            animator.attach(view, Property.TRANSLATION_X, pos);
-        else
-            animator.attach(view, Property.TRANSLATION_Y, pos);
-
-        mCloseAnimationCount++;
-        mPendingClosedTabs.add(view);
-
-        animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
-            @Override
-            public void onPropertyAnimationStart() { }
-            @Override
-            public void onPropertyAnimationEnd() {
-                mCloseAnimationCount--;
-                if (mCloseAnimationCount > 0)
-                    return;
-
-                for (View pendingView : mPendingClosedTabs) {
-                    animateFinishClose(pendingView);
-                }
-
-                mPendingClosedTabs.clear();
-            }
-        });
-
-        if (mTabsAdapter.getCount() == 1)
-            autoHidePanel();
-
-        animator.start();
-    }
-
-    private void animateFinishClose(final View view) {
-        PropertyAnimator animator = new PropertyAnimator(ANIMATION_DURATION);
-
-        final boolean isVertical = isVertical();
-        if (isVertical)
-            animator.attach(view, Property.HEIGHT, 1);
-        else
-            animator.attach(view, Property.WIDTH, 1);
-
-        final int tabId = ((TabsLayoutItemView) view).getTabId();
-
-        // Caching this assumes that all rows are the same height
-        if (mOriginalSize == 0) {
-            mOriginalSize = (isVertical ? view.getHeight() : view.getWidth());
-        }
-
-        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, true);
-            }
-        });
-
-        animator.start();
-    }
-
-    private void animateCancel(final View view) {
-        PropertyAnimator animator = new PropertyAnimator(ANIMATION_DURATION);
-        animator.attach(view, Property.ALPHA, 1);
-
-        if (isVertical())
-            animator.attach(view, Property.TRANSLATION_X, 0);
-        else
-            animator.attach(view, Property.TRANSLATION_Y, 0);
-
-
-        animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
-            @Override
-            public void onPropertyAnimationStart() { }
-            @Override
-            public void onPropertyAnimationEnd() {
-                TabsLayoutItemView tab = (TabsLayoutItemView) view;
-                tab.setCloseVisible(true);
-            }
-        });
-
-        animator.start();
-    }
-
-    private class TabSwipeGestureListener implements View.OnTouchListener {
-        // same value the stock browser uses for after drag animation velocity in pixels/sec
-        // http://androidxref.com/4.0.4/xref/packages/apps/Browser/src/com/android/browser/NavTabScroller.java#61
-        private static final float MIN_VELOCITY = 750;
-
-        private final int mSwipeThreshold;
-        private final int mMinFlingVelocity;
-
-        private final int mMaxFlingVelocity;
-        private VelocityTracker mVelocityTracker;
-
-        private int mListWidth = 1;
-        private int mListHeight = 1;
-
-        private View mSwipeView;
-        private Runnable mPendingCheckForTap;
-
-        private float mSwipeStartX;
-        private float mSwipeStartY;
-        private boolean mSwiping;
-        private boolean mEnabled;
-
-        public TabSwipeGestureListener() {
-            mEnabled = true;
-
-            ViewConfiguration vc = ViewConfiguration.get(TabsListLayout.this.getContext());
-            mSwipeThreshold = vc.getScaledTouchSlop();
-            mMinFlingVelocity = (int) (getContext().getResources().getDisplayMetrics().density * MIN_VELOCITY);
-            mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
-        }
-
-        public void setEnabled(boolean enabled) {
-            mEnabled = enabled;
-        }
-
-        public TwoWayView.OnScrollListener makeScrollListener() {
-            return new TwoWayView.OnScrollListener() {
-                @Override
-                public void onScrollStateChanged(TwoWayView twoWayView, int scrollState) {
-                    setEnabled(scrollState != TwoWayView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
-                }
-
-                @Override
-                public void onScroll(TwoWayView twoWayView, int i, int i1, int i2) {
-                }
-            };
-        }
-
-        @Override
-        public boolean onTouch(View view, MotionEvent e) {
-            if (!mEnabled)
-                return false;
-
-            if (mListWidth < 2 || mListHeight < 2) {
-                mListWidth = TabsListLayout.this.getWidth();
-                mListHeight = TabsListLayout.this.getHeight();
-            }
-
-            switch (e.getActionMasked()) {
-                case MotionEvent.ACTION_DOWN: {
-                    // Check if we should set pressed state on the
-                    // touched view after a standard delay.
-                    triggerCheckForTap();
-
-                    final float x = e.getRawX();
-                    final float y = e.getRawY();
-
-                    // Find out which view is being touched
-                    mSwipeView = findViewAt(x, y);
-
-                    if (mSwipeView != null) {
-                        mSwipeStartX = e.getRawX();
-                        mSwipeStartY = e.getRawY();
-
-                        mVelocityTracker = VelocityTracker.obtain();
-                        mVelocityTracker.addMovement(e);
-                    }
-
-                    view.onTouchEvent(e);
-                    return true;
-                }
-
-                case MotionEvent.ACTION_UP: {
-                    if (mSwipeView == null)
-                        break;
-
-                    cancelCheckForTap();
-                    mSwipeView.setPressed(false);
-
-                    if (!mSwiping) {
-                        TabsLayoutItemView item = (TabsLayoutItemView) mSwipeView;
-                        Tabs.getInstance().selectTab(item.getTabId());
-                        autoHidePanel();
-
-                        mVelocityTracker.recycle();
-                        mVelocityTracker = null;
-                        break;
-                    }
-
-                    mVelocityTracker.addMovement(e);
-                    mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity);
-
-                    float velocityX = Math.abs(mVelocityTracker.getXVelocity());
-                    float velocityY = Math.abs(mVelocityTracker.getYVelocity());
-
-                    boolean dismiss = false;
-                    boolean dismissDirection = false;
-                    int dismissTranslation = 0;
-
-                    if (isVertical()) {
-                        float deltaX = ViewHelper.getTranslationX(mSwipeView);
-
-                        if (Math.abs(deltaX) > mListWidth / 2) {
-                            dismiss = true;
-                            dismissDirection = (deltaX > 0);
-                        } else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity
-                                && velocityY < velocityX) {
-                            dismiss = mSwiping && (deltaX * mVelocityTracker.getXVelocity() > 0);
-                            dismissDirection = (mVelocityTracker.getXVelocity() > 0);
-                        }
-
-                        dismissTranslation = (dismissDirection ? mListWidth : -mListWidth);
-                    } else {
-                        float deltaY = ViewHelper.getTranslationY(mSwipeView);
-
-                        if (Math.abs(deltaY) > mListHeight / 2) {
-                            dismiss = true;
-                            dismissDirection = (deltaY > 0);
-                        } else if (mMinFlingVelocity <= velocityY && velocityY <= mMaxFlingVelocity
-                                && velocityX < velocityY) {
-                            dismiss = mSwiping && (deltaY * mVelocityTracker.getYVelocity() > 0);
-                            dismissDirection = (mVelocityTracker.getYVelocity() > 0);
-                        }
-
-                        dismissTranslation = (dismissDirection ? mListHeight : -mListHeight);
-                     }
-
-                    if (dismiss)
-                        animateClose(mSwipeView, dismissTranslation);
-                    else
-                        animateCancel(mSwipeView);
-
-                    mVelocityTracker.recycle();
-                    mVelocityTracker = null;
-                    mSwipeView = null;
-
-                    mSwipeStartX = 0;
-                    mSwipeStartY = 0;
-                    mSwiping = false;
-
-                    break;
-                }
-
-                case MotionEvent.ACTION_MOVE: {
-                    if (mSwipeView == null || mVelocityTracker == null)
-                        break;
-
-                    mVelocityTracker.addMovement(e);
-
-                    final boolean isVertical = isVertical();
-
-                    float deltaX = e.getRawX() - mSwipeStartX;
-                    float deltaY = e.getRawY() - mSwipeStartY;
-                    float delta = (isVertical ? deltaX : deltaY);
-
-                    boolean isScrollingX = Math.abs(deltaX) > mSwipeThreshold;
-                    boolean isScrollingY = Math.abs(deltaY) > mSwipeThreshold;
-                    boolean isSwipingToClose = (isVertical ? isScrollingX : isScrollingY);
-
-                    // If we're actually swiping, make sure we don't
-                    // set pressed state on the swiped view.
-                    if (isScrollingX || isScrollingY)
-                        cancelCheckForTap();
-
-                    if (isSwipingToClose) {
-                        mSwiping = true;
-                        TabsListLayout.this.requestDisallowInterceptTouchEvent(true);
-
-                        ((TabsLayoutItemView) mSwipeView).setCloseVisible(false);
-
-                        // Stops listview from highlighting the touched item
-                        // in the list when swiping.
-                        MotionEvent cancelEvent = MotionEvent.obtain(e);
-                        cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
-                                (e.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
-                        TabsListLayout.this.onTouchEvent(cancelEvent);
-                        cancelEvent.recycle();
-                    }
-
-                    if (mSwiping) {
-                        if (isVertical)
-                            ViewHelper.setTranslationX(mSwipeView, delta);
-                        else
-                            ViewHelper.setTranslationY(mSwipeView, delta);
-
-                        ViewHelper.setAlpha(mSwipeView, Math.max(0.1f, Math.min(1f,
-                                1f - 2f * Math.abs(delta) / (isVertical ? mListWidth : mListHeight))));
-
-                        return true;
-                    }
-
-                    break;
-                }
-            }
-
-            return false;
-        }
-
-        private View findViewAt(float rawX, float rawY) {
-            Rect rect = new Rect();
-
-            int[] listViewCoords = new int[2];
-            TabsListLayout.this.getLocationOnScreen(listViewCoords);
-
-            int x = (int) rawX - listViewCoords[0];
-            int y = (int) rawY - listViewCoords[1];
-
-            for (int i = 0; i < TabsListLayout.this.getChildCount(); i++) {
-                View child = TabsListLayout.this.getChildAt(i);
-                child.getHitRect(rect);
-
-                if (rect.contains(x, y))
-                    return child;
-            }
-
-            return null;
-        }
-
-        private void triggerCheckForTap() {
-            if (mPendingCheckForTap == null)
-                mPendingCheckForTap = new CheckForTap();
-
-            TabsListLayout.this.postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
-        }
-
-        private void cancelCheckForTap() {
-            if (mPendingCheckForTap == null)
-                return;
-
-            TabsListLayout.this.removeCallbacks(mPendingCheckForTap);
-        }
-
-        private class CheckForTap implements Runnable {
-            @Override
-            public void run() {
-                if (!mSwiping && mSwipeView != null && mEnabled)
-                    mSwipeView.setPressed(true);
-            }
-        }
-    }
-}
--- a/mobile/android/base/tabs/TabsPanel.java
+++ b/mobile/android/base/tabs/TabsPanel.java
@@ -50,35 +50,26 @@ public class TabsPanel extends LinearLay
         NORMAL_TABS,
         PRIVATE_TABS,
     }
 
     public interface PanelView {
         void setTabsPanel(TabsPanel panel);
         void show();
         void hide();
-        boolean shouldExpand();
     }
 
     public interface CloseAllPanelView extends PanelView {
         void closeAll();
     }
 
     public interface TabsLayout extends CloseAllPanelView {
         void setEmptyView(View view);
     }
 
-    public static View createTabsLayout(final Context context, final AttributeSet attrs) {
-        if (HardwareUtils.isTablet()) {
-            return new TabsGridLayout(context, attrs);
-        } else {
-            return new TabsListLayout(context, attrs);
-        }
-    }
-
     public interface TabsLayoutChangeListener {
         void onTabsLayoutChange(int width, int height);
     }
 
     private final Context mContext;
     private final GeckoApp mActivity;
     private final LightweightTheme mTheme;
     private RelativeLayout mHeader;
@@ -427,20 +418,16 @@ public class TabsPanel extends LinearLay
         mActivity.autoHideTabs();
     }
 
     @Override
     public boolean isShown() {
         return mVisible;
     }
 
-    public Panel getCurrentPanel() {
-        return mCurrentPanel;
-    }
-
     public void setHWLayerEnabled(boolean enabled) {
         if (Versions.preHC) {
             return;
         }
         if (enabled) {
             mHeader.setLayerType(View.LAYER_TYPE_HARDWARE, null);
             mTabsContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
         } else {