Bug 1116415 - 5. Move SpacingDecoration and introduce AutoFitRecyclerView. r?sebastian draft
authorTom Klein <twointofive@gmail.com>
Mon, 12 Sep 2016 15:01:44 -0500
changeset 424671 e7fce024e563867f791d174d4b4fcd878acc8cbf
parent 424670 c7ce98269ea9692c922b11f3d2ec619dc55dccee
child 424672 1c6a92e7614c2b0981db9ccfbc1d673656c88daf
push id32215
push userbmo:twointofive@gmail.com
push dateThu, 13 Oct 2016 05:22:21 +0000
reviewerssebastian
bugs1116415
milestone52.0a1
Bug 1116415 - 5. 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,85 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.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 desiredColumnWidth-width columns that will fit in the
+    // available width, so the actual column width can turn out to be larger than desiredColumnWidth,
+    // or even smaller if 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
+    protected void onMeasure(int widthSpec, int heightSpec) {
+        super.onMeasure(widthSpec, heightSpec);
+
+        if (!autoFit || getMeasuredWidth() == 0 || desiredColumnWidth <= 0) {
+            return;
+        }
+
+        final int nonPaddingWidth = getMeasuredWidth() - 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);
+        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
@@ -490,17 +490,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',
@@ -720,16 +719,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'trackingprotection/TrackingProtectionPrompt.java',
     'updater/PostUpdateHandler.java',
     'updater/UpdateService.java',
     'updater/UpdateServiceHelper.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/DoorHanger.java',
@@ -746,16 +746,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/TwoWayView.java',
     'ZoomedView.java',
 ]]