Bug 1310081 - 1. Move SpacingDecoration and introduce AutoFitRecyclerView. r?sebastian draft
authorTom Klein <twointofive@gmail.com>
Sun, 13 Nov 2016 09:10:51 -0600
changeset 438192 336b7256e61b46cd6974ac6385436c5fd25dd5fb
parent 437787 d284cdb3ad6e0609a53a275df6efcff4255c30ec
child 438193 22a9533aa578f059a77b1deaef94062e708d4e10
push id35651
push userbmo:twointofive@gmail.com
push dateMon, 14 Nov 2016 03:56:28 +0000
reviewerssebastian
bugs1310081
milestone52.0a1
Bug 1310081 - 1. Move SpacingDecoration and introduce AutoFitRecyclerView. r?sebastian Make PanelRecylerView an AutoFitRecyclerView. These changes are in preparation for making TabsGridLayout a RecyclerView. MozReview-Commit-ID: 1W0I6yaPVO5
mobile/android/base/java/org/mozilla/gecko/home/PanelRecyclerView.java
mobile/android/base/java/org/mozilla/gecko/home/SpacingDecoration.java
mobile/android/base/java/org/mozilla/gecko/widget/AutoFitRecyclerView.java
mobile/android/base/java/org/mozilla/gecko/widget/SpacingDecoration.java
mobile/android/base/moz.build
--- a/mobile/android/base/java/org/mozilla/gecko/home/PanelRecyclerView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/PanelRecyclerView.java
@@ -3,69 +3,73 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.home;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.home.PanelLayout.DatasetBacked;
 import org.mozilla.gecko.home.PanelLayout.PanelView;
+import org.mozilla.gecko.widget.AutoFitRecyclerView;
 import org.mozilla.gecko.widget.RecyclerViewClickSupport;
 import org.mozilla.gecko.widget.RecyclerViewClickSupport.OnItemClickListener;
 import org.mozilla.gecko.widget.RecyclerViewClickSupport.OnItemLongClickListener;
+import org.mozilla.gecko.widget.SpacingDecoration;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
 
 /**
  * RecyclerView implementation for grid home panels.
  */
 @SuppressLint("ViewConstructor") // View is only created from code
-public class PanelRecyclerView extends RecyclerView
+public class PanelRecyclerView extends AutoFitRecyclerView
         implements DatasetBacked, PanelView, OnItemClickListener, OnItemLongClickListener {
     private final PanelRecyclerViewAdapter adapter;
     private final GridLayoutManager layoutManager;
     private final PanelViewItemHandler itemHandler;
-    private final float columnWidth;
-    private final boolean autoFit;
     private final HomeConfig.ViewConfig viewConfig;
 
     private PanelLayout.OnItemOpenListener itemOpenListener;
     private HomeContextMenuInfo contextMenuInfo;
     private HomeContextMenuInfo.Factory contextMenuInfoFactory;
 
     public PanelRecyclerView(Context context, HomeConfig.ViewConfig viewConfig) {
         super(context);
 
         this.viewConfig = viewConfig;
 
         final Resources resources = context.getResources();
 
-        int spanCount;
+        final boolean autoFit;
+        final int spanCount;
         if (viewConfig.getItemType() == HomeConfig.ItemType.ICON) {
             autoFit = false;
             spanCount = getResources().getInteger(R.integer.panel_icon_grid_view_columns);
         } else {
             autoFit = true;
             spanCount = 1;
         }
 
-        columnWidth = resources.getDimension(R.dimen.panel_grid_view_column_width);
         layoutManager = new GridLayoutManager(context, spanCount);
         adapter = new PanelRecyclerViewAdapter(context, viewConfig);
         itemHandler = new PanelViewItemHandler();
 
         layoutManager.setSpanSizeLookup(new PanelSpanSizeLookup());
 
         setLayoutManager(layoutManager);
+        if (autoFit) {
+            setAutoFit(true);
+            setDesiredColumnWidth(resources.getDimension(R.dimen.panel_grid_view_column_width));
+        }
         setAdapter(adapter);
 
         int horizontalSpacing = (int) resources.getDimension(R.dimen.panel_grid_view_horizontal_spacing);
         int verticalSpacing = (int) resources.getDimension(R.dimen.panel_grid_view_vertical_spacing);
         int outerSpacing = (int) resources.getDimension(R.dimen.panel_grid_view_outer_spacing);
 
         addItemDecoration(new SpacingDecoration(horizontalSpacing, verticalSpacing));
 
@@ -73,27 +77,16 @@ public class PanelRecyclerView extends R
         setClipToPadding(false);
 
         RecyclerViewClickSupport.addTo(this)
             .setOnItemClickListener(this)
             .setOnItemLongClickListener(this);
     }
 
     @Override
-    protected void onMeasure(int widthSpec, int heightSpec) {
-        super.onMeasure(widthSpec, heightSpec);
-
-        if (autoFit) {
-            // Adjust span based on space available (What GridView does when you say numColumns="auto_fit")
-            final int spanCount = (int) Math.max(1, getMeasuredWidth() / columnWidth);
-            layoutManager.setSpanCount(spanCount);
-        }
-    }
-
-    @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
         itemHandler.setOnItemOpenListener(itemOpenListener);
     }
 
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/AutoFitRecyclerView.java
@@ -0,0 +1,90 @@
+/* -*- 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.widget;
+
+import android.content.Context;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+
+/**
+ *  Currently assumes vertical layout in the autofit case.
+ */
+public abstract class AutoFitRecyclerView extends RecyclerView {
+    private float desiredColumnWidth;
+    // If true then the current layout manager is a GridLayoutManager.
+    private boolean autoFit;
+
+    public AutoFitRecyclerView(Context context) {
+        super(context);
+        autoFit = false;
+    }
+
+    public AutoFitRecyclerView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        autoFit = false;
+    }
+
+    public AutoFitRecyclerView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        autoFit = false;
+    }
+
+    /** AutoFit is turned off whenever a non-GridLayoutManager is set. */
+    @Override
+    public void setLayoutManager(LayoutManager layoutManager) {
+        super.setLayoutManager(layoutManager);
+
+        if (!hasGridLayoutManager()) {
+            autoFit = false;
+        }
+    }
+
+    /**
+     * GridLayoutManager operates on number of columns, not column width - AutoFit sets the number
+     * of columns to be the largest number of {@code desiredColumnWidth}-width columns that will fit
+     * in the available width, so the actual column width can turn out to be larger than
+     * {@code desiredColumnWidth}, or even smaller if {@code desiredColumnWidth} is larger than the
+     * total available width.
+     */
+    protected void setDesiredColumnWidth(float desiredColumnWidth) {
+        this.desiredColumnWidth = desiredColumnWidth;
+    }
+
+    /** AutoFit can be set true only if the current layout manager is a GridLayoutManager. */
+    public void setAutoFit(boolean b) {
+        if (b && hasGridLayoutManager()) {
+            autoFit = true;
+        } else {
+            autoFit = false;
+        }
+    }
+
+    @Override
+    public void onSizeChanged (int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        if (!autoFit || w == oldw || desiredColumnWidth <= 0) {
+            return;
+        }
+
+        final int nonPaddingWidth = w - getPaddingLeft() - getPaddingRight();
+        // Adjust span based on space available (what GridView does when you say numColumns="auto_fit").
+        final int spanCount = (int) Math.max(1, nonPaddingWidth / desiredColumnWidth);
+        final GridLayoutManager layoutManager = (GridLayoutManager) getLayoutManager();
+        if (spanCount == layoutManager.getSpanCount()) {
+            return;
+        }
+        layoutManager.setSpanCount(spanCount);
+        onSpanCountChanged();
+    }
+
+    protected void onSpanCountChanged() {}
+
+    private boolean hasGridLayoutManager() {
+        return getLayoutManager() instanceof GridLayoutManager;
+    }
+}
rename from mobile/android/base/java/org/mozilla/gecko/home/SpacingDecoration.java
rename to mobile/android/base/java/org/mozilla/gecko/widget/SpacingDecoration.java
--- a/mobile/android/base/java/org/mozilla/gecko/home/SpacingDecoration.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/SpacingDecoration.java
@@ -1,9 +1,14 @@
-package org.mozilla.gecko.home;
+/* -*- 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.widget;
 
 import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
 
 public class SpacingDecoration extends RecyclerView.ItemDecoration {
     private final int horizontalSpacing;
     private final int verticalSpacing;
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -494,17 +494,16 @@ gbjar.sources += ['java/org/mozilla/geck
     'home/RecentTabsAdapter.java',
     'home/RemoteTabsExpandableListState.java',
     'home/SearchEngine.java',
     'home/SearchEngineAdapter.java',
     'home/SearchEngineBar.java',
     'home/SearchEngineRow.java',
     'home/SearchLoader.java',
     'home/SimpleCursorLoader.java',
-    'home/SpacingDecoration.java',
     'home/TabMenuStrip.java',
     'home/TabMenuStripLayout.java',
     'home/TopSitesGridItemView.java',
     'home/TopSitesGridView.java',
     'home/TopSitesPanel.java',
     'home/TopSitesThumbnailView.java',
     'home/TwoLinePageRow.java',
     'icons/decoders/FaviconDecoder.java',
@@ -742,16 +741,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'util/DrawableUtil.java',
     'util/ResourceDrawableUtils.java',
     'util/TouchTargetUtil.java',
     'util/ViewUtil.java',
     'widget/ActivityChooserModel.java',
     'widget/AllCapsTextView.java',
     'widget/AnchoredPopup.java',
     'widget/AnimatedHeightLayout.java',
+    'widget/AutoFitRecyclerView.java',
     'widget/BasicColorPicker.java',
     'widget/CheckableLinearLayout.java',
     'widget/ClickableWhenDisabledEditText.java',
     'widget/ContentSecurityDoorHanger.java',
     'widget/CropImageView.java',
     'widget/DateTimePicker.java',
     'widget/DefaultDoorHanger.java',
     'widget/DefaultItemAnimatorBase.java',
@@ -769,16 +769,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'widget/GeckoPopupMenu.java',
     'widget/HistoryDividerItemDecoration.java',
     'widget/IconTabWidget.java',
     'widget/LoginDoorHanger.java',
     'widget/RecyclerViewClickSupport.java',
     'widget/ResizablePathDrawable.java',
     'widget/RoundedCornerLayout.java',
     'widget/SiteLogins.java',
+    'widget/SpacingDecoration.java',
     'widget/SquaredImageView.java',
     'widget/SquaredRelativeLayout.java',
     'widget/SwipeDismissListViewTouchListener.java',
     'widget/TabThumbnailWrapper.java',
     'widget/ThumbnailView.java',
     'widget/TouchDelegateWithReset.java',
     'widget/TwoWayView.java',
     'ZoomedView.java',