Bug 1271998 - Part 4 - Use a touch delegate to increase the clickable area of the URL bar. r=jwu
authorJan Henning <jh+bugzilla@buttercookie.de>
Tue, 29 Aug 2017 20:34:17 +0200
changeset 429522 ecae1c71816b6d2aa21e520cb444f2cefb21ff91
parent 429521 953adb3e5e838f53df4a3a590a40b4c6f2c62949
child 429523 8be3c451ff86b00894d66754f1975b8343440abd
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwu
bugs1271998, 1389164
milestone57.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 1271998 - Part 4 - Use a touch delegate to increase the clickable area of the URL bar. r=jwu Originally, the listeners that trigger editing mode and the URL bar's context menu were attached to the BrowserToolbar itself. As this doesn't work properly in conjunction with wrapping the URL TextView into a ScrollView, the listeners were moved onto the TextView itself. Bug 1389164 reduced the height of the TextView in order to better support lightweight themes with the new toolbar design, which in conjunction with the changes to support the ScrollView has the unfortunate side effect of also reducing the URL bar's hit target area. Therefore, we increase it back to its old levels by using a TouchDelegate on the ScrollView. Because Android's ScrollView implementation doesn't support TouchDelegates, we have to add the missing bits of logic back in from the default View implementation. MozReview-Commit-ID: 1nTrrNGvBza
mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
mobile/android/base/java/org/mozilla/gecko/widget/FadedHorizontalScrollView.java
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.toolbar;
 
 import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.List;
 
+import android.graphics.Rect;
 import android.support.annotation.Nullable;
 import android.support.v4.content.ContextCompat;
 import org.mozilla.gecko.BrowserApp;
 import org.mozilla.gecko.GeckoSharedPrefs;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.Telemetry;
@@ -31,16 +32,17 @@ import org.mozilla.gecko.tabs.TabHistory
 import org.mozilla.gecko.toolbar.ToolbarDisplayLayout.OnStopListener;
 import org.mozilla.gecko.toolbar.ToolbarDisplayLayout.OnTitleChangeListener;
 import org.mozilla.gecko.toolbar.ToolbarDisplayLayout.UpdateFlags;
 import org.mozilla.gecko.util.Clipboard;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.MenuUtils;
 import org.mozilla.gecko.util.WindowUtil;
 import org.mozilla.gecko.widget.AnimatedProgressBar;
+import org.mozilla.gecko.widget.TouchDelegateWithReset;
 import org.mozilla.gecko.widget.themed.ThemedImageButton;
 import org.mozilla.gecko.widget.themed.ThemedRelativeLayout;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.drawable.Drawable;
@@ -214,16 +216,33 @@ public abstract class BrowserToolbar ext
 
         prefs = new ToolbarPrefs();
         urlDisplayLayout.setToolbarPrefs(prefs);
         urlEditLayout.setToolbarPrefs(prefs);
 
         // ScrollViews are allowed to have only one child.
         final View scrollChild = urlDisplayScroll.getChildAt(0);
 
+        urlDisplayScroll.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+            @Override
+            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                final int width = urlDisplayScroll.getWidth();
+                final int height = urlDisplayScroll.getHeight();
+                final int oldWidth = oldRight - oldLeft;
+                final int oldHeight = oldBottom - oldTop;
+
+                if (width != oldWidth || height != oldHeight) {
+                    final Rect r = new Rect();
+                    r.right = width;
+                    r.bottom = height;
+                    urlDisplayScroll.setTouchDelegate(new TouchDelegateWithReset(r, scrollChild));
+                }
+            }
+        });
+
         scrollChild.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
             @Override
             public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
                 // Do not show the context menu while editing
                 if (isEditing()) {
                     return;
                 }
 
--- a/mobile/android/base/java/org/mozilla/gecko/widget/FadedHorizontalScrollView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/FadedHorizontalScrollView.java
@@ -11,39 +11,46 @@ import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.LinearGradient;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Shader;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.TouchDelegate;
 import android.view.View;
 import android.widget.HorizontalScrollView;
 
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.R;
 
 /**
  * A {@link HorizontalScrollView} implementation with a more efficient fadingEdge drawing strategy
  * than the built-in version provided by Android. The width of the fade effect can be controlled via
  * <code>gecko:fadeWidth</code>. To control in how far the fading effect should affect any views
  * further up in the View hierarchy, place this view or one of its parents onto a separate layer
  * using <code>android:layerType</code>. Currently, only horizontal fading is supported.
+ * <p>
+ * Additionally, {@link TouchDelegate} support (which isn't provided for in Android's ScrollView
+ * implementation) has been enabled.
  */
 public class FadedHorizontalScrollView extends HorizontalScrollView {
     // Width of the fade effect from end of the view.
     private final int mFadeWidth;
     private final boolean mPreMarshmallow;
 
     private final FadePaint mFadePaint;
     private float mFadeTop;
     private float mFadeBottom;
     private boolean mVerticalFadeBordersDirty;
 
+    private boolean mInterceptingTouchEvents;
+
     public FadedHorizontalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mPreMarshmallow = Versions.preMarshmallow;
 
         mFadePaint = new FadePaint();
         mVerticalFadeBordersDirty = true;
         addOnLayoutChangeListener(new OnLayoutChangeListener() {
             @Override
@@ -151,9 +158,35 @@ public class FadedHorizontalScrollView e
 
         public FadePaint() {
             matrix = new Matrix();
             fade = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
             setShader(fade);
             setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
         }
     }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        // Once we intercept an event, this method stops being called until the intercept state
+        // is reset at the start of the following gesture. Therefore we can reset the tracking
+        // variable to false each time this method is being called.
+        mInterceptingTouchEvents = false;
+
+        final boolean intercept = super.onInterceptTouchEvent(ev);
+        if (intercept) {
+            mInterceptingTouchEvents = true;
+        }
+        return intercept;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (!mInterceptingTouchEvents) {
+            final TouchDelegate touchDelegate = getTouchDelegate();
+            if (touchDelegate != null && touchDelegate.onTouchEvent(ev)) {
+                return true;
+            }
+        }
+
+        return super.onTouchEvent(ev);
+    }
 }