Bug 1410221: Pass in parent snackbarAnchor for WebpageItemRow. r=liuche draft
authorMichael Comella <michael.l.comella@gmail.com>
Mon, 23 Oct 2017 14:05:39 -0700
changeset 689873 e2890904f2e057877568e0729cf7bd6ff0299eaf
parent 688832 befd2dd89771edd86d05a92b6f7ce2ccde6835c3
child 689874 906036ec63861906b94f75697b7de3c2576d0057
push id87125
push usermichael.l.comella@gmail.com
push dateWed, 01 Nov 2017 02:42:22 +0000
reviewersliuche
bugs1410221
milestone58.0a1
Bug 1410221: Pass in parent snackbarAnchor for WebpageItemRow. r=liuche MozReview-Commit-ID: 76VLKcEPQWF
mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/StreamHighlightItemRowContextMenuListener.java
mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/StreamRecyclerAdapter.java
mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/menu/ActivityStreamContextMenu.java
mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/stream/WebpageItemRow.java
--- a/mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/StreamHighlightItemRowContextMenuListener.java
+++ b/mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/StreamHighlightItemRowContextMenuListener.java
@@ -1,18 +1,19 @@
 /* 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.activitystream.homepanel;
 
 import android.support.annotation.NonNull;
+import android.view.View;
 import org.mozilla.gecko.activitystream.homepanel.stream.WebpageItemRow;
 
 /**
  * Provides a method to open the context menu for a highlight item.
  *
  * I tried declaring this inside StreamRecyclerAdapter but I got cyclical inheritance warnings
  * (I don't understand why) so it's here instead.
  */
 public interface StreamHighlightItemRowContextMenuListener {
-    void openContextMenu(WebpageItemRow highlightItem, int position, @NonNull final String interactionExtra);
+    void openContextMenu(WebpageItemRow highlightItem, int position, View snackbarAnchor, @NonNull final String interactionExtra);
 }
--- a/mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/StreamRecyclerAdapter.java
+++ b/mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/StreamRecyclerAdapter.java
@@ -17,16 +17,17 @@ import android.view.ViewGroup;
 
 import org.mozilla.gecko.GeckoSharedPrefs;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
 import org.mozilla.gecko.activitystream.homepanel.menu.ActivityStreamContextMenu;
 import org.mozilla.gecko.activitystream.homepanel.model.RowModel;
+import org.mozilla.gecko.activitystream.homepanel.model.WebpageModel;
 import org.mozilla.gecko.activitystream.homepanel.model.WebpageRowModel;
 import org.mozilla.gecko.activitystream.homepanel.stream.HighlightsEmptyStateRow;
 import org.mozilla.gecko.activitystream.homepanel.stream.LearnMoreRow;
 import org.mozilla.gecko.activitystream.homepanel.stream.TopPanelRow;
 import org.mozilla.gecko.activitystream.homepanel.model.TopStory;
 import org.mozilla.gecko.activitystream.homepanel.topstories.PocketStoriesLoader;
 import org.mozilla.gecko.home.HomePager;
 import org.mozilla.gecko.activitystream.homepanel.model.Highlight;
@@ -125,27 +126,31 @@ public class StreamRecyclerAdapter exten
         if (position >= recyclerViewModel.size()) {
             throw new IllegalArgumentException("Requested position, " + position + ", does not exist. Size is :" +
                     recyclerViewModel.size());
         }
         return recyclerViewModel.get(position).getRowItemType().getViewType();
     }
 
     @Override
-    public StreamViewHolder onCreateViewHolder(ViewGroup parent, final int type) {
+    public StreamViewHolder onCreateViewHolder(final ViewGroup parent, final int type) {
         final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
 
         if (type == RowItemType.TOP_PANEL.getViewType()) {
             return new TopPanelRow(inflater.inflate(TopPanelRow.LAYOUT_ID, parent, false), onUrlOpenListener, onUrlOpenInBackgroundListener);
         } else if (type == RowItemType.TOP_STORIES_TITLE.getViewType()) {
             return new StreamTitleRow(inflater.inflate(StreamTitleRow.LAYOUT_ID, parent, false), R.string.activity_stream_topstories, R.string.activity_stream_link_more, LINK_MORE_POCKET, onUrlOpenListener);
-        } else if (type == RowItemType.TOP_STORIES_ITEM.getViewType()) {
-            return new WebpageItemRow(inflater.inflate(WebpageItemRow.LAYOUT_ID, parent, false), this);
-        } else if (type == RowItemType.HIGHLIGHT_ITEM.getViewType()) {
-            return new WebpageItemRow(inflater.inflate(WebpageItemRow.LAYOUT_ID, parent, false), this);
+        } else if (type == RowItemType.TOP_STORIES_ITEM.getViewType() ||
+                type == RowItemType.HIGHLIGHT_ITEM.getViewType()) {
+            return new WebpageItemRow(inflater.inflate(WebpageItemRow.LAYOUT_ID, parent, false), new WebpageItemRow.OnMenuButtonClickListener() {
+                @Override
+                public void onMenuButtonClicked(final WebpageItemRow row, final int position) {
+                    openContextMenu(row, position, parent, ActivityStreamTelemetry.Contract.INTERACTION_MENU_BUTTON);
+                }
+            });
         } else if (type == RowItemType.HIGHLIGHTS_TITLE.getViewType()) {
             return new StreamTitleRow(inflater.inflate(StreamTitleRow.LAYOUT_ID, parent, false), R.string.activity_stream_highlights);
         } else if (type == RowItemType.HIGHLIGHTS_EMPTY_STATE.getViewType()) {
             return new HighlightsEmptyStateRow(inflater.inflate(HighlightsEmptyStateRow.LAYOUT_ID, parent, false));
         } else if (type == RowItemType.LEARN_MORE_LINK.getViewType()) {
             return new LearnMoreRow(inflater.inflate(LearnMoreRow.LAYOUT_ID, parent, false));
         } else {
             throw new IllegalStateException("Missing inflation for ViewType " + type);
@@ -281,17 +286,17 @@ public class StreamRecyclerAdapter exten
 
     @Override
     public boolean onItemLongClicked(final RecyclerView recyclerView, final int position, final View v) {
         if (!onItemClickIsValidRowItem(position)) {
             return false;
         }
 
         final WebpageItemRow highlightItem = (WebpageItemRow) recyclerView.getChildViewHolder(v);
-        openContextMenu(highlightItem, position, ActivityStreamTelemetry.Contract.INTERACTION_LONG_CLICK);
+        openContextMenu(highlightItem, position, recyclerView, ActivityStreamTelemetry.Contract.INTERACTION_LONG_CLICK);
         return true;
     }
 
     private boolean onItemClickIsValidRowItem(final int position) {
         // The position this method receives is from RecyclerView.ViewHolder.getAdapterPosition, whose docs state:
         // "Note that if you've called notifyDataSetChanged(), until the next layout pass, the return value of this
         // method will be NO_POSITION."
         //
@@ -311,18 +316,23 @@ public class StreamRecyclerAdapter exten
                 && viewType != RowItemType.TOP_STORIES_ITEM.getViewType()) {
             // Headers (containing topsites and/or the highlights title) do their own click handling as needed
             return false;
         }
 
         return true;
     }
 
+    /**
+     * @param snackbarAnchor See {@link ActivityStreamContextMenu#show(Context, View, ActivityStreamTelemetry.Extras.Builder, ActivityStreamContextMenu.MenuMode, WebpageModel, boolean, HomePager.OnUrlOpenListener, HomePager.OnUrlOpenInBackgroundListener, int, int)}
+     *                       for additional details.
+     */
     @Override
-    public void openContextMenu(final WebpageItemRow webpageItemRow, final int position, @NonNull final String interactionExtra) {
+    public void openContextMenu(final WebpageItemRow webpageItemRow, final int position, final View snackbarAnchor,
+            @NonNull final String interactionExtra) {
         final WebpageRowModel model = (WebpageRowModel) recyclerViewModel.get(position);
 
         final String sourceType;
         final int actionPosition;
         final ActivityStreamContextMenu.MenuMode menuMode;
 
         ActivityStreamTelemetry.Extras.Builder extras = ActivityStreamTelemetry.Extras.builder();
         if (model.getRowItemType() == RowItemType.HIGHLIGHT_ITEM) {
@@ -336,17 +346,17 @@ public class StreamRecyclerAdapter exten
             menuMode = ActivityStreamContextMenu.MenuMode.TOPSTORY;
         }
 
         extras.set(ActivityStreamTelemetry.Contract.SOURCE_TYPE, sourceType)
               .set(ActivityStreamTelemetry.Contract.ACTION_POSITION, actionPosition)
               .set(ActivityStreamTelemetry.Contract.INTERACTION, interactionExtra);
 
         ActivityStreamContextMenu.show(webpageItemRow.itemView.getContext(),
-                webpageItemRow.getContextMenuAnchor(),
+                snackbarAnchor,
                 extras,
                 menuMode,
                 model,
                 /* shouldOverrideWithImageProvider */ true, // we use image providers in HighlightItem.pageIconLayout.
                 onUrlOpenListener, onUrlOpenInBackgroundListener,
                 webpageItemRow.getTileWidth(), webpageItemRow.getTileHeight());
 
         Telemetry.sendUIEvent(
--- a/mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/menu/ActivityStreamContextMenu.java
+++ b/mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/menu/ActivityStreamContextMenu.java
@@ -336,16 +336,18 @@ public abstract class ActivityStreamCont
                 telemetryExtraBuilder.build()
         );
 
         dismiss();
         return true;
     }
 
     /**
+     * @param anchor A view to anchor the Snackbar on. Don't use items in the recyclerView because these views can be
+     *               removed from the view hierarchy when the recyclerView scrolls.
      * @param shouldOverrideIconWithImageProvider true if the favicon should be replaced with an image provider,
      *                                            if applicable, false otherwise.
      */
     @RobocopTarget
     public static ActivityStreamContextMenu show(Context context,
                                                       View anchor, ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder,
                                                       final MenuMode menuMode, final WebpageModel item,
                                                       final boolean shouldOverrideIconWithImageProvider,
--- a/mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/stream/WebpageItemRow.java
+++ b/mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/stream/WebpageItemRow.java
@@ -9,19 +9,17 @@ import android.content.Context;
 import android.graphics.Color;
 import android.support.annotation.UiThread;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 import org.mozilla.gecko.R;
-import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
 import org.mozilla.gecko.activitystream.Utils;
-import org.mozilla.gecko.activitystream.homepanel.StreamHighlightItemRowContextMenuListener;
 import org.mozilla.gecko.activitystream.homepanel.model.WebpageRowModel;
 import org.mozilla.gecko.util.DrawableUtil;
 import org.mozilla.gecko.util.StringUtils;
 import org.mozilla.gecko.util.TouchTargetUtil;
 import org.mozilla.gecko.util.URIUtils;
 import org.mozilla.gecko.util.ViewUtil;
 
 import java.lang.ref.WeakReference;
@@ -38,37 +36,37 @@ public class WebpageItemRow extends Stre
     private WebpageRowModel webpageModel;
     private int position;
 
     private final StreamOverridablePageIconLayout pageIconLayout;
     private final TextView pageDomainView;
     private final TextView pageTitleView;
     private final ImageView pageSourceIconView;
     private final TextView pageSourceView;
-    private final ImageView menuButton;
 
-    public WebpageItemRow(final View itemView, final StreamHighlightItemRowContextMenuListener contextMenuListener) {
+    public WebpageItemRow(final View itemView, final OnMenuButtonClickListener onMenuButtonClickListener) {
         super(itemView);
 
         pageTitleView = (TextView) itemView.findViewById(R.id.page_title);
         pageIconLayout = (StreamOverridablePageIconLayout) itemView.findViewById(R.id.page_icon);
         pageSourceView = (TextView) itemView.findViewById(R.id.page_source);
         pageDomainView = (TextView) itemView.findViewById(R.id.page_domain);
         pageSourceIconView = (ImageView) itemView.findViewById(R.id.page_source_icon);
 
-        menuButton = (ImageView) itemView.findViewById(R.id.menu);
+        final ImageView menuButton = (ImageView) itemView.findViewById(R.id.menu);
         menuButton.setImageDrawable(
                 DrawableUtil.tintDrawable(menuButton.getContext(), R.drawable.menu, Color.LTGRAY));
         TouchTargetUtil.ensureTargetHitArea(menuButton, itemView);
         ViewUtil.enableTouchRipple(menuButton);
         menuButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                contextMenuListener.openContextMenu(WebpageItemRow.this, position,
-                        ActivityStreamTelemetry.Contract.INTERACTION_MENU_BUTTON);
+                if (onMenuButtonClickListener != null) {
+                    onMenuButtonClickListener.onMenuButtonClicked(WebpageItemRow.this, position);
+                }
             }
         });
     }
 
     public void bind(WebpageRowModel model, int position, int tilesWidth) {
         this.webpageModel = model;
         this.position = position;
 
@@ -120,20 +118,16 @@ public class WebpageItemRow extends Stre
             return;
         }
 
         final UpdatePageDomainAsyncTask updatePageDomainTask = new UpdatePageDomainAsyncTask(itemView.getContext(),
                 highlightURI, pageDomainView);
         updatePageDomainTask.execute();
     }
 
-    public View getContextMenuAnchor() {
-        return menuButton;
-    }
-
     public int getTileWidth() {
         return pageIconLayout.getWidth();
     }
 
     public int getTileHeight() {
         return pageIconLayout.getHeight();
     }
 
@@ -171,9 +165,13 @@ public class WebpageItemRow extends Stre
          * Returns true if the tag on the given view matches the tag from the constructor. We do this to ensure
          * the View we're making this request for hasn't been re-used by the time this request completes.
          */
         @UiThread
         private boolean isTagSameAsStartTag(final View viewToCheck) {
             return viewTagAtStart.equals(viewToCheck.getTag(VIEW_TAG_ID));
         }
     }
+
+    public interface OnMenuButtonClickListener {
+        void onMenuButtonClicked(WebpageItemRow row, int position);
+    }
 }