Bug 1377819 - Use ViewStub and give a default implementation of TabsLayout instead of puting an interface in layout xml. draft
authorNevin Chen <cnevinchen@gmail.com>
Mon, 04 Sep 2017 01:49:28 +0800
changeset 658330 391b1d9fba1986e6ebc3be23441e8d36b0dc5e6d
parent 658329 d1e865f084a35cf563fe28dd126f772509684e34
child 729604 924e2c7c2ac42d4b2bfe0ae36cb5dbcccc3e5444
push id77718
push userbmo:cnevinchen@gmail.com
push dateSun, 03 Sep 2017 20:40:22 +0000
bugs1377819
milestone57.0a1
Bug 1377819 - Use ViewStub and give a default implementation of TabsLayout instead of puting an interface in layout xml. As per comment 1, and I can't find a STR for onCreateView not being called, I try to use ViewStub to swap TabLayout for different layout/orientation. And for portrait mode, I give a default implementation (i.e. AutoFitTabsGridLayout) since compact tab is now by default. The problem for View Stub is that I can't set custom attribute to it.(i.e gecko:tabs="tabs_private). So I need to add extra tabs_panel_private for it. This seems to be redundant but I can't think of a better way to make this change smaller. Maybe set isPrivate for TabsLayout programmatically, but this will also need to move tabsAdapter out from constructor... that may be a future enhancement. I haven't decided if I should do the enhancement now, and I'll be super busy next week. So if any one is intrested in it, feel free to continue the work. MozReview-Commit-ID: 5Ht0Rxhpew6
mobile/android/app/src/main/res/layout-land/tabs_panel_normal.xml
mobile/android/app/src/main/res/layout-land/tabs_panel_private.xml
mobile/android/app/src/main/res/layout-large/tabs_panel_normal.xml
mobile/android/app/src/main/res/layout-large/tabs_panel_private.xml
mobile/android/app/src/main/res/layout-port/tabs_panel_normal.xml
mobile/android/app/src/main/res/layout-port/tabs_panel_private.xml
mobile/android/app/src/main/res/layout/tabs_panel_default.xml
mobile/android/app/src/photon/res/layout/private_tabs_panel.xml
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/base/java/org/mozilla/gecko/tabs/AutoFitTabsGridLayout.java
mobile/android/base/java/org/mozilla/gecko/tabs/CompactTabsGridLayout.java
mobile/android/base/java/org/mozilla/gecko/tabs/PrivateTabsPanel.java
mobile/android/base/java/org/mozilla/gecko/tabs/TabsPanel.java
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/src/main/res/layout-land/tabs_panel_normal.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/. -->
+
+<org.mozilla.gecko.tabs.AutoFitTabsGridLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:gecko="http://schemas.android.com/apk/res-auto"
+    style="@style/TabsLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:visibility="gone"
+    gecko:tabs="tabs_normal">
+
+</org.mozilla.gecko.tabs.AutoFitTabsGridLayout>
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/src/main/res/layout-land/tabs_panel_private.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/. -->
+
+<org.mozilla.gecko.tabs.AutoFitTabsGridLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:gecko="http://schemas.android.com/apk/res-auto"
+    style="@style/TabsLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:visibility="gone"
+    gecko:tabs="tabs_private">
+
+</org.mozilla.gecko.tabs.AutoFitTabsGridLayout>
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/src/main/res/layout-large/tabs_panel_normal.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/. -->
+
+<org.mozilla.gecko.tabs.AutoFitTabsGridLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:gecko="http://schemas.android.com/apk/res-auto"
+    style="@style/TabsLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:visibility="gone"
+    gecko:tabs="tabs_normal">
+
+</org.mozilla.gecko.tabs.AutoFitTabsGridLayout>
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/src/main/res/layout-large/tabs_panel_private.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/. -->
+
+<org.mozilla.gecko.tabs.AutoFitTabsGridLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:gecko="http://schemas.android.com/apk/res-auto"
+    style="@style/TabsLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:visibility="gone"
+    gecko:tabs="tabs_private">
+
+</org.mozilla.gecko.tabs.AutoFitTabsGridLayout>
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/src/main/res/layout-port/tabs_panel_normal.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/. -->
+
+<org.mozilla.gecko.tabs.CompactTabsGridLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:gecko="http://schemas.android.com/apk/res-auto"
+    style="@style/TabsLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:visibility="gone"
+    gecko:tabs="tabs_normal">
+
+</org.mozilla.gecko.tabs.CompactTabsGridLayout>
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/src/main/res/layout-port/tabs_panel_private.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/. -->
+
+<org.mozilla.gecko.tabs.CompactTabsGridLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:gecko="http://schemas.android.com/apk/res-auto"
+    style="@style/TabsLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:visibility="gone"
+    gecko:tabs="tabs_private">
+
+</org.mozilla.gecko.tabs.CompactTabsGridLayout>
--- a/mobile/android/app/src/main/res/layout/tabs_panel_default.xml
+++ b/mobile/android/app/src/main/res/layout/tabs_panel_default.xml
@@ -79,23 +79,22 @@
 
     </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"
-              android:id="@+id/normal_tabs"
-              style="@style/TabsLayout"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:visibility="gone"
-              gecko:tabs="tabs_normal"/>
+        <ViewStub
+            android:id="@+id/normal_tabs"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout="@layout/tabs_panel_normal"
+            android:visibility="gone"/>
 
         <org.mozilla.gecko.tabs.PrivateTabsPanel
                 android:id="@+id/private_tabs_panel"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:visibility="gone"/>
 
     </FrameLayout>
--- a/mobile/android/app/src/photon/res/layout/private_tabs_panel.xml
+++ b/mobile/android/app/src/photon/res/layout/private_tabs_panel.xml
@@ -65,18 +65,16 @@
                 android:textColor="@color/link_blue"/>
 
         </LinearLayout>
 
     </ScrollView>
 
     <!-- Note: for an unknown reason, scrolling in the TabsLayout
          does not work unless it is laid out after the empty view. -->
-    <view
+    <ViewStub
         android:id="@+id/private_tabs_layout"
-        style="@style/TabsLayout"
-        class="org.mozilla.gecko.tabs.TabsPanel$TabsLayout"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:visibility="gone"
-        gecko:tabs="tabs_private"/>
+        android:layout="@layout/tabs_panel_private"
+        android:visibility="gone"/>
 
 </merge>
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -75,16 +75,17 @@ import org.mozilla.gecko.reader.SavedRea
 import org.mozilla.gecko.reader.ReaderModeUtils;
 import org.mozilla.gecko.reader.ReadingListHelper;
 import org.mozilla.gecko.restrictions.Restrictable;
 import org.mozilla.gecko.restrictions.Restrictions;
 import org.mozilla.gecko.search.SearchEngineManager;
 import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
 import org.mozilla.gecko.tabqueue.TabQueueHelper;
 import org.mozilla.gecko.tabqueue.TabQueuePrompt;
+import org.mozilla.gecko.tabs.CompactTabsGridLayout;
 import org.mozilla.gecko.tabs.TabHistoryController;
 import org.mozilla.gecko.tabs.TabHistoryController.OnShowTabHistory;
 import org.mozilla.gecko.tabs.TabHistoryFragment;
 import org.mozilla.gecko.tabs.TabHistoryPage;
 import org.mozilla.gecko.tabs.TabsPanel;
 import org.mozilla.gecko.telemetry.TelemetryUploadService;
 import org.mozilla.gecko.telemetry.TelemetryCorePingDelegate;
 import org.mozilla.gecko.telemetry.measurements.SearchCountMeasurements;
@@ -349,17 +350,17 @@ public class BrowserApp extends GeckoApp
 
     private boolean mHasResumed;
 
     @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)) {
+        } else if (CompactTabsGridLayout.class.getName().equals(name)) {
             view = TabsPanel.createTabsLayout(context, attrs);
         } else {
             view = super.onCreateView(name, context, attrs);
         }
         return view;
     }
 
     @Override
--- a/mobile/android/base/java/org/mozilla/gecko/tabs/AutoFitTabsGridLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabs/AutoFitTabsGridLayout.java
@@ -9,26 +9,26 @@ import org.mozilla.gecko.R;
 import org.mozilla.gecko.widget.GridSpacingDecoration;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.support.v7.widget.GridLayoutManager;
 import android.util.AttributeSet;
 import android.util.Log;
 
-class AutoFitTabsGridLayout extends TabsGridLayout {
+public class AutoFitTabsGridLayout extends TabsGridLayout {
     private static final String LOGTAG = "Gecko" + AutoFitTabsGridLayout.class.getSimpleName();
 
     private GridSpacingDecoration spacingDecoration;
     private final int desiredItemWidth;
     private final int desiredHorizontalItemSpacing;
     private final int minHorizontalItemSpacing;
     private final int verticalItemPadding;
 
-    AutoFitTabsGridLayout(Context context, AttributeSet attrs) {
+    public AutoFitTabsGridLayout(Context context, AttributeSet attrs) {
         super(context, attrs, 1);
 
         final Resources resources = context.getResources();
         desiredItemWidth = resources.getDimensionPixelSize(R.dimen.tab_panel_item_width_autofit);
         desiredHorizontalItemSpacing = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_item_hpadding_autofit);
         minHorizontalItemSpacing = resources.getDimensionPixelOffset(R.dimen.tab_panel_grid_min_item_hspacing_autofit);
         verticalItemPadding = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_item_vpadding_autofit);
         final int viewPaddingVertical = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_vpadding_autofit);
--- a/mobile/android/base/java/org/mozilla/gecko/tabs/CompactTabsGridLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabs/CompactTabsGridLayout.java
@@ -7,17 +7,17 @@ package org.mozilla.gecko.tabs;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.widget.GridSpacingDecoration;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.AttributeSet;
 
-class CompactTabsGridLayout extends TabsGridLayout {
+public class CompactTabsGridLayout extends TabsGridLayout {
     CompactTabsGridLayout(Context context, AttributeSet attrs) {
         super(context, attrs, 2);
 
         final Resources resources = context.getResources();
         final int desiredHorizontalItemSpacing = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_hpadding_compact);
         final int viewPaddingVertical = resources.getDimensionPixelSize(R.dimen.tab_panel_grid_vpadding_compact);
 
         setPadding(desiredHorizontalItemSpacing, viewPaddingVertical, desiredHorizontalItemSpacing, viewPaddingVertical);
--- a/mobile/android/base/java/org/mozilla/gecko/tabs/PrivateTabsPanel.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabs/PrivateTabsPanel.java
@@ -12,38 +12,40 @@ import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 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.ViewStub;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
 import static org.mozilla.gecko.Tabs.LOADURL_NEW_TAB;
 import static org.mozilla.gecko.Tabs.LOADURL_PRIVATE;
 
 /**
  * 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 RelativeLayout implements CloseAllPanelView {
+public class PrivateTabsPanel extends RelativeLayout implements CloseAllPanelView {
     private final static String PRIVATE_BROWSING_URL = "https://support.mozilla.org/kb/private-browsing-firefox-android";
 
     private final TabsLayout tabsLayout;
 
     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 ViewStub viewStub = (ViewStub) findViewById(R.id.private_tabs_layout);
+        tabsLayout = (TabsLayout) viewStub.inflate();
 
         final View emptyTabsFrame = findViewById(R.id.private_tabs_empty);
         tabsLayout.setEmptyView(emptyTabsFrame);
 
         final TextView learnMoreView = (TextView) findViewById(R.id.learn_more_link);
         learnMoreView.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
--- a/mobile/android/base/java/org/mozilla/gecko/tabs/TabsPanel.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabs/TabsPanel.java
@@ -35,16 +35,17 @@ import android.support.v4.content.Contex
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewStub;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 
 import org.mozilla.gecko.switchboard.SwitchBoard;
 
@@ -82,26 +83,25 @@ public class TabsPanel extends LinearLay
     }
 
     private static boolean tabletOrLandscapeMode(Context context) {
         return HardwareUtils.isTablet() ||
                 context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
     }
 
     public static View createTabsLayout(final Context context, final AttributeSet attrs) {
-        if (tabletOrLandscapeMode(context)) {
-            return new AutoFitTabsGridLayout(context, attrs);
-        } else {
+        if (!tabletOrLandscapeMode(context)) {
             // Phone in portrait mode.
             if (GeckoSharedPrefs.forApp(context).getBoolean(GeckoPreferences.PREFS_COMPACT_TABS, true)) {
                 return new CompactTabsGridLayout(context, attrs);
             } else {
                 return new TabsListLayout(context, attrs);
             }
         }
+        return null;
     }
 
     private final Context mContext;
     private final GeckoApp mActivity;
     private final LightweightTheme mTheme;
     private RelativeLayout mHeader;
     private FrameLayout mTabsContainer;
     private PanelView mPanel;
@@ -143,17 +143,18 @@ public class TabsPanel extends LinearLay
     private void inflateLayout(Context context) {
         LayoutInflater.from(context).inflate(R.layout.tabs_panel_default, this);
     }
 
     private void initialize() {
         mHeader = (RelativeLayout) findViewById(R.id.tabs_panel_header);
         mTabsContainer = (FrameLayout) findViewById(R.id.tabs_container);
 
-        mPanelNormal = (PanelView) findViewById(R.id.normal_tabs);
+        final ViewStub stub = (ViewStub) findViewById(R.id.normal_tabs);
+        mPanelNormal = (PanelView) stub.inflate();
         mPanelNormal.setTabsPanel(this);
 
         mPanelPrivate = (PanelView) findViewById(R.id.private_tabs_panel);
         mPanelPrivate.setTabsPanel(this);
 
         mAddTab = (ImageButton) findViewById(R.id.add_tab);
         mAddTab.setOnClickListener(new Button.OnClickListener() {
             @Override