summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/NestedGeckoView.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/NestedGeckoView.java')
-rw-r--r--mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/NestedGeckoView.java169
1 files changed, 169 insertions, 0 deletions
diff --git a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/NestedGeckoView.java b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/NestedGeckoView.java
new file mode 100644
index 0000000000..c165acd3c8
--- /dev/null
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/NestedGeckoView.java
@@ -0,0 +1,169 @@
+/* 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.geckoview_example;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import androidx.core.view.NestedScrollingChild;
+import androidx.core.view.NestedScrollingChildHelper;
+import androidx.core.view.ViewCompat;
+import org.mozilla.geckoview.GeckoView;
+import org.mozilla.geckoview.PanZoomController;
+
+/**
+ * GeckoView that supports nested scrolls (for using in a CoordinatorLayout).
+ *
+ * <p>This code is a simplified version of the NestedScrollView implementation which can be found in
+ * the support library: [android.support.v4.widget.NestedScrollView]
+ *
+ * <p>Based on: https://github.com/takahirom/webview-in-coordinatorlayout
+ */
+public class NestedGeckoView extends GeckoView implements NestedScrollingChild {
+
+ private int mLastY;
+ private final int[] mScrollOffset = new int[2];
+ private final int[] mScrollConsumed = new int[2];
+ private int mNestedOffsetY;
+ private NestedScrollingChildHelper mChildHelper;
+
+ /**
+ * Integer indicating how user's MotionEvent was handled.
+ *
+ * <p>There must be a 1-1 relation between this values and [EngineView.InputResult]'s.
+ */
+ private int mInputResult = PanZoomController.INPUT_RESULT_UNHANDLED;
+
+ public NestedGeckoView(final Context context) {
+ this(context, null);
+ }
+
+ public NestedGeckoView(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ mChildHelper = new NestedScrollingChildHelper(this);
+ setNestedScrollingEnabled(true);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ MotionEvent event = MotionEvent.obtain(ev);
+ final int action = event.getActionMasked();
+ int eventY = (int) event.getY();
+
+ switch (action) {
+ case MotionEvent.ACTION_MOVE:
+ final boolean allowScroll =
+ !shouldPinOnScreen() && mInputResult == PanZoomController.INPUT_RESULT_HANDLED;
+ int deltaY = mLastY - eventY;
+
+ if (allowScroll && dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
+ deltaY -= mScrollConsumed[1];
+ event.offsetLocation(0f, -mScrollOffset[1]);
+ mNestedOffsetY += mScrollOffset[1];
+ }
+
+ mLastY = eventY - mScrollOffset[1];
+
+ if (allowScroll && dispatchNestedScroll(0, mScrollOffset[1], 0, deltaY, mScrollOffset)) {
+ mLastY -= mScrollOffset[1];
+ event.offsetLocation(0f, mScrollOffset[1]);
+ mNestedOffsetY += mScrollOffset[1];
+ }
+ break;
+
+ case MotionEvent.ACTION_DOWN:
+ // A new gesture started. Reset handled status and ask GV if it can handle this.
+ mInputResult = PanZoomController.INPUT_RESULT_UNHANDLED;
+ updateInputResult(event);
+
+ mNestedOffsetY = 0;
+ mLastY = eventY;
+
+ // The event should be handled either by onTouchEvent,
+ // either by onTouchEventForResult, never by both.
+ // Early return if we sent it to updateInputResult(..) which calls onTouchEventForResult.
+ event.recycle();
+ return true;
+
+ // We don't care about other touch events
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ stopNestedScroll();
+ break;
+ }
+
+ // Execute event handler from parent class in all cases
+ final boolean eventHandled = callSuperOnTouchEvent(event);
+
+ // Recycle previously obtained event
+ event.recycle();
+
+ return eventHandled;
+ }
+
+ private boolean callSuperOnTouchEvent(MotionEvent event) {
+ return super.onTouchEvent(event);
+ }
+
+ private void updateInputResult(MotionEvent event) {
+ super.onTouchEventForDetailResult(event)
+ .accept(
+ inputResult -> {
+ mInputResult = inputResult.handledResult();
+ startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
+ });
+ }
+
+ public int getInputResult() {
+ return mInputResult;
+ }
+
+ @Override
+ public void setNestedScrollingEnabled(boolean enabled) {
+ mChildHelper.setNestedScrollingEnabled(enabled);
+ }
+
+ @Override
+ public boolean isNestedScrollingEnabled() {
+ return mChildHelper.isNestedScrollingEnabled();
+ }
+
+ @Override
+ public boolean startNestedScroll(int axes) {
+ return mChildHelper.startNestedScroll(axes);
+ }
+
+ @Override
+ public void stopNestedScroll() {
+ mChildHelper.stopNestedScroll();
+ }
+
+ @Override
+ public boolean hasNestedScrollingParent() {
+ return mChildHelper.hasNestedScrollingParent();
+ }
+
+ @Override
+ public boolean dispatchNestedScroll(
+ int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
+ return mChildHelper.dispatchNestedScroll(
+ dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
+ }
+
+ @Override
+ public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
+ return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
+ }
+
+ @Override
+ public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
+ return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
+ }
+
+ @Override
+ public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
+ return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
+ }
+}