Bug 1049136 - Hook up touch event handling for apz-fennec. r=wesj,snorp
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 08 Aug 2014 18:15:37 -0400
changeset 198688 4ffa223f053fae18fa2c940bbd2860ad34bb6841
parent 198687 cabf76d115b6a06c03bcc1279151cdf94575fdbc
child 198689 6432653640cba93b61acdb754860dadafcb3b50e
push idunknown
push userunknown
push dateunknown
reviewerswesj, snorp
bugs1049136
milestone34.0a1
Bug 1049136 - Hook up touch event handling for apz-fennec. r=wesj,snorp
mobile/android/base/gfx/NativePanZoomController.java
mozglue/android/jni-stubs.inc
widget/android/APZCCallbackHandler.cpp
widget/android/APZCCallbackHandler.h
widget/android/AndroidJNI.cpp
widget/android/AndroidJavaWrappers.cpp
widget/android/AndroidJavaWrappers.h
widget/android/nsAppShell.cpp
widget/android/nsWindow.cpp
--- a/mobile/android/base/gfx/NativePanZoomController.java
+++ b/mobile/android/base/gfx/NativePanZoomController.java
@@ -36,18 +36,17 @@ class NativePanZoomController implements
         if ("Gecko:Ready".equals(event)) {
             mDispatcher.unregisterGeckoThreadListener(this, "Gecko:Ready");
             init();
         }
     }
 
     public boolean onTouchEvent(MotionEvent event) {
         GeckoEvent wrapped = GeckoEvent.createMotionEvent(event, true);
-        handleTouchEvent(wrapped);
-        return false;
+        return handleTouchEvent(wrapped);
     }
 
     public boolean onMotionEvent(MotionEvent event) {
         // FIXME implement this
         return false;
     }
 
     public boolean onKeyEvent(KeyEvent event) {
@@ -63,24 +62,29 @@ class NativePanZoomController implements
     public void pageRectUpdated() {
         // no-op in APZC, I think
     }
 
     public void abortPanning() {
         // no-op in APZC, I think
     }
 
+    public void notifyDefaultActionPrevented(boolean prevented) {
+        // This should never get called; there is a different
+        // codepath that notifies the APZ code of this.
+        throw new IllegalStateException("APZCCallbackHandler::NotifyDefaultPrevented should be getting called, not this!");
+    }
+
     public native void abortAnimation();
 
     private native void init();
-    private native void handleTouchEvent(GeckoEvent event);
+    private native boolean handleTouchEvent(GeckoEvent event);
     private native void handleMotionEvent(GeckoEvent event);
 
     public native void destroy();
-    public native void notifyDefaultActionPrevented(boolean prevented);
     public native boolean getRedrawHint();
     public native void setOverScrollMode(int overscrollMode);
     public native int getOverScrollMode();
 
     @WrapElementForJNI(allowMultithread = true, stubName = "RequestContentRepaintWrapper")
     private void requestContentRepaint(float x, float y, float width, float height, float resolution) {
         mTarget.forceRedraw(new DisplayPortMetrics(x, y, x + width, y + height, resolution));
     }
--- a/mozglue/android/jni-stubs.inc
+++ b/mozglue/android/jni-stubs.inc
@@ -433,26 +433,26 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
 #endif
 
 #ifdef JNI_BINDINGS
   xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_init", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_init);
 #endif
 
 #ifdef JNI_STUBS
 
-typedef void (*Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent_t)(JNIEnv *, jobject, jobject);
+typedef jboolean (*Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent_t)(JNIEnv *, jobject, jobject);
 static Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent;
-extern "C" NS_EXPORT void JNICALL
+extern "C" NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv * arg0, jobject arg1, jobject arg2) {
     if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent) {
         arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
                        "JNI Function called before it was loaded");
-        return ;
+        return false;
     }
-     f_Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(arg0, arg1, arg2);
+    return f_Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(arg0, arg1, arg2);
 }
 #endif
 
 #ifdef JNI_BINDINGS
   xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent);
 #endif
 
 #ifdef JNI_STUBS
@@ -490,35 +490,16 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
 #endif
 
 #ifdef JNI_BINDINGS
   xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy);
 #endif
 
 #ifdef JNI_STUBS
 
-typedef void (*Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented_t)(JNIEnv *, jobject, jboolean);
-static Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented;
-extern "C" NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented(JNIEnv * arg0, jobject arg1, jboolean arg2) {
-    if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented) {
-        arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
-                       "JNI Function called before it was loaded");
-        return ;
-    }
-     f_Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented(arg0, arg1, arg2);
-}
-#endif
-
-#ifdef JNI_BINDINGS
-  xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented);
-#endif
-
-#ifdef JNI_STUBS
-
 typedef jboolean (*Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint_t)(JNIEnv *, jobject);
 static Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint;
 extern "C" NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint(JNIEnv * arg0, jobject arg1) {
     if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint) {
         arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
                        "JNI Function called before it was loaded");
         return false;
--- a/widget/android/APZCCallbackHandler.cpp
+++ b/widget/android/APZCCallbackHandler.cpp
@@ -11,16 +11,17 @@
 #include "nsPrintfCString.h"
 #include "nsThreadUtils.h"
 #include "base/message_loop.h"
 #include "nsWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "AndroidBridge.h"
 
 using mozilla::layers::APZCCallbackHelper;
+using mozilla::layers::APZCTreeManager;
 using mozilla::layers::FrameMetrics;
 using mozilla::layers::ScrollableLayerGuid;
 
 namespace mozilla {
 namespace widget {
 namespace android {
 
 StaticRefPtr<APZCCallbackHandler> APZCCallbackHandler::sInstance;
@@ -28,16 +29,37 @@ StaticRefPtr<APZCCallbackHandler> APZCCa
 NativePanZoomController*
 APZCCallbackHandler::SetNativePanZoomController(jobject obj)
 {
     NativePanZoomController* old = mNativePanZoomController;
     mNativePanZoomController = NativePanZoomController::Wrap(obj);
     return old;
 }
 
+void
+APZCCallbackHandler::NotifyDefaultPrevented(const ScrollableLayerGuid& aGuid,
+                                            bool aDefaultPrevented)
+{
+    if (NS_IsMainThread()) {
+        // The notification must reach the APZ on the Java UI thread (aka the
+        // APZ "controller" thread) but we get it from the Gecko thread, so we
+        // have to throw it onto the other thread.
+        AndroidBridge::Bridge()->PostTaskToUiThread(NewRunnableMethod(
+            this, &APZCCallbackHandler::NotifyDefaultPrevented,
+            aGuid, aDefaultPrevented), 0);
+        return;
+    }
+
+    // This should be running on the Java UI thread
+    APZCTreeManager* controller = nsWindow::GetAPZCTreeManager();
+    if (controller) {
+        controller->ContentReceivedTouch(aGuid, aDefaultPrevented);
+    }
+}
+
 nsIDOMWindowUtils*
 APZCCallbackHandler::GetDOMWindowUtils()
 {
     nsIAndroidBrowserApp* browserApp = nullptr;
     if (!nsAppShell::gAppShell) {
         return nullptr;
     }
     nsAppShell::gAppShell->GetBrowserApp(&browserApp);
--- a/widget/android/APZCCallbackHandler.h
+++ b/widget/android/APZCCallbackHandler.h
@@ -33,16 +33,17 @@ public:
     static APZCCallbackHandler* GetInstance() {
         if (sInstance.get() == nullptr) {
             sInstance = new APZCCallbackHandler();
         }
         return sInstance.get();
     }
 
     NativePanZoomController* SetNativePanZoomController(jobject obj);
+    void NotifyDefaultPrevented(const mozilla::layers::ScrollableLayerGuid& aGuid, bool aDefaultPrevented);
 
 public: // GeckoContentController methods
     void RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
     void AcknowledgeScrollUpdate(const mozilla::layers::FrameMetrics::ViewID& aScrollId,
                                  const uint32_t& aScrollGeneration) MOZ_OVERRIDE;
     void HandleDoubleTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
                          const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
     void HandleSingleTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -877,28 +877,38 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
 
     NativePanZoomController* oldRef = APZCCallbackHandler::GetInstance()->SetNativePanZoomController(instance);
     if (oldRef && !oldRef->isNull()) {
         MOZ_ASSERT(false, "Registering a new NPZC when we already have one");
         delete oldRef;
     }
 }
 
-NS_EXPORT void JNICALL
+NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv* env, jobject instance, jobject event)
 {
     APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
-    if (controller) {
-        AndroidGeckoEvent* wrapper = AndroidGeckoEvent::MakeFromJavaObject(env, event);
-        MultiTouchInput input = wrapper->MakeMultiTouchInput(nsWindow::TopWindow());
-        delete wrapper;
-        if (input.mType >= 0) {
-            controller->ReceiveInputEvent(input, nullptr);
-        }
+    if (!controller) {
+        return false;
     }
+
+    AndroidGeckoEvent* wrapper = AndroidGeckoEvent::MakeFromJavaObject(env, event);
+    MultiTouchInput input = wrapper->MakeMultiTouchInput(nsWindow::TopWindow());
+    delete wrapper;
+
+    if (input.mType < 0 || !nsAppShell::gAppShell) {
+        return false;
+    }
+
+    ScrollableLayerGuid guid;
+    nsEventStatus status = controller->ReceiveInputEvent(input, &guid);
+    if (status != nsEventStatus_eConsumeNoDefault) {
+        nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeApzInputEvent(input, guid));
+    }
+    return true;
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent(JNIEnv* env, jobject instance, jobject event)
 {
     // FIXME implement this
 }
 
@@ -912,26 +922,16 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
     NativePanZoomController* oldRef = APZCCallbackHandler::GetInstance()->SetNativePanZoomController(nullptr);
     if (!oldRef || oldRef->isNull()) {
         MOZ_ASSERT(false, "Clearing a non-existent NPZC");
     } else {
         delete oldRef;
     }
 }
 
-NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented(JNIEnv* env, jobject instance, jboolean prevented)
-{
-    APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
-    if (controller) {
-        // TODO: Pass in correct values for presShellId and viewId.
-        controller->ContentReceivedTouch(ScrollableLayerGuid(nsWindow::RootLayerTreeId(), 0, 0), prevented);
-    }
-}
-
 NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint(JNIEnv* env, jobject instance)
 {
     // FIXME implement this
     return true;
 }
 
 NS_EXPORT void JNICALL
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -650,19 +650,43 @@ AndroidGeckoEvent::Init(AndroidGeckoEven
     NS_ASSERTION(aResizeEvent->Type() == SIZE_CHANGED, "Init called on non-SIZE_CHANGED event");
 
     mType = FORCED_RESIZE;
     mAckNeeded = false;
     mTime = aResizeEvent->mTime;
     mPoints = aResizeEvent->mPoints; // x,y coordinates
 }
 
+bool
+AndroidGeckoEvent::CanCoalesceWith(AndroidGeckoEvent* ae)
+{
+    if (Type() == MOTION_EVENT && ae->Type() == MOTION_EVENT) {
+        return Action() == AndroidMotionEvent::ACTION_MOVE
+            && ae->Action() == AndroidMotionEvent::ACTION_MOVE;
+    } else if (Type() == APZ_INPUT_EVENT && ae->Type() == APZ_INPUT_EVENT) {
+        return mApzInput.mType == MultiTouchInput::MULTITOUCH_MOVE
+            && ae->mApzInput.mType == MultiTouchInput::MULTITOUCH_MOVE;
+    }
+    return false;
+}
+
+mozilla::layers::ScrollableLayerGuid
+AndroidGeckoEvent::ApzGuid()
+{
+    MOZ_ASSERT(Type() == APZ_INPUT_EVENT);
+    return mApzGuid;
+}
+
 WidgetTouchEvent
 AndroidGeckoEvent::MakeTouchEvent(nsIWidget* widget)
 {
+    if (Type() == APZ_INPUT_EVENT) {
+        return mApzInput.ToWidgetTouchEvent(widget);
+    }
+
     int type = NS_EVENT_NULL;
     int startIndex = 0;
     int endIndex = Count();
 
     switch (Action()) {
         case AndroidMotionEvent::ACTION_DOWN:
         case AndroidMotionEvent::ACTION_POINTER_DOWN: {
             type = NS_TOUCH_START;
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -16,16 +16,17 @@
 #include "nsTArray.h"
 #include "nsIObserver.h"
 #include "nsIAndroidBridge.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/dom/Touch.h"
 #include "mozilla/EventForwards.h"
 #include "InputData.h"
 #include "Units.h"
+#include "FrameMetrics.h"
 
 //#define FORCE_ALOG 1
 
 class nsIAndroidDisplayport;
 class nsIAndroidViewport;
 class nsIWidget;
 
 namespace mozilla {
@@ -476,16 +477,24 @@ public:
     static AndroidGeckoEvent* MakeAddObserver(const nsAString &key, nsIObserver *observer) {
         AndroidGeckoEvent *event = new AndroidGeckoEvent();
         event->Init(ADD_OBSERVER);
         event->mCharacters.Assign(key);
         event->mObserver = observer;
         return event;
     }
 
+    static AndroidGeckoEvent* MakeApzInputEvent(const MultiTouchInput& aInput, const mozilla::layers::ScrollableLayerGuid& aGuid) {
+        AndroidGeckoEvent* event = new AndroidGeckoEvent();
+        event->Init(APZ_INPUT_EVENT);
+        event->mApzInput = aInput;
+        event->mApzGuid = aGuid;
+        return event;
+    }
+
     int Action() { return mAction; }
     int Type() { return mType; }
     bool AckNeeded() { return mAckNeeded; }
     int64_t Time() { return mTime; }
     const nsTArray<nsIntPoint>& Points() { return mPoints; }
     const nsTArray<int>& PointIndicies() { return mPointIndicies; }
     const nsTArray<float>& Pressures() { return mPressures; }
     const nsTArray<float>& Orientations() { return mOrientations; }
@@ -532,21 +541,23 @@ public:
     int Width() { return mWidth; }
     int Height() { return mHeight; }
     int ID() { return mID; }
     int GamepadButton() { return mGamepadButton; }
     bool GamepadButtonPressed() { return mGamepadButtonPressed; }
     float GamepadButtonValue() { return mGamepadButtonValue; }
     const nsTArray<float>& GamepadValues() { return mGamepadValues; }
     int RequestId() { return mCount; } // for convenience
+    bool CanCoalesceWith(AndroidGeckoEvent* ae);
     WidgetTouchEvent MakeTouchEvent(nsIWidget* widget);
     MultiTouchInput MakeMultiTouchInput(nsIWidget* widget);
     WidgetMouseEvent MakeMouseEvent(nsIWidget* widget);
     void UnionRect(nsIntRect const& aRect);
     nsIObserver *Observer() { return mObserver; }
+    mozilla::layers::ScrollableLayerGuid ApzGuid();
 
 protected:
     int mAction;
     int mType;
     bool mAckNeeded;
     int64_t mTime;
     nsTArray<nsIntPoint> mPoints;
     nsTArray<nsIntPoint> mPointRadii;
@@ -576,16 +587,18 @@ protected:
     int mWidth, mHeight;
     int mID;
     int mGamepadButton;
     bool mGamepadButtonPressed;
     float mGamepadButtonValue;
     nsTArray<float> mGamepadValues;
     nsCOMPtr<nsIObserver> mObserver;
     nsTArray<nsString> mPrefNames;
+    MultiTouchInput mApzInput;
+    mozilla::layers::ScrollableLayerGuid mApzGuid;
 
     void ReadIntArray(nsTArray<int> &aVals,
                       JNIEnv *jenv,
                       jfieldID field,
                       int32_t count);
     void ReadFloatArray(nsTArray<float> &aVals,
                         JNIEnv *jenv,
                         jfieldID field,
@@ -676,16 +689,17 @@ public:
         LOCATION_EVENT = 5,
         IME_EVENT = 6,
         SIZE_CHANGED = 8,
         APP_BACKGROUNDING = 9,
         APP_FOREGROUNDING = 10,
         LOAD_URI = 12,
         NOOP = 15,
         FORCED_RESIZE = 16, // used internally in nsAppShell/nsWindow
+        APZ_INPUT_EVENT = 17, // used internally in AndroidJNI/nsAppShell/nsWindow
         BROADCAST = 19,
         VIEWPORT = 20,
         VISITED = 21,
         NETWORK_CHANGED = 22,
         THUMBNAIL = 25,
         SCREENORIENTATION_CHANGED = 27,
         COMPOSITOR_CREATE = 28,
         COMPOSITOR_PAUSE = 29,
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -736,26 +736,25 @@ nsAppShell::PostEvent(AndroidGeckoEvent 
             }
             mQueuedViewportEvent = ae;
             allowCoalescingNextViewport = true;
 
             mEventQueue.AppendElement(ae);
             break;
 
         case AndroidGeckoEvent::MOTION_EVENT:
-            if (ae->Action() == AndroidMotionEvent::ACTION_MOVE && mAllowCoalescingTouches) {
+        case AndroidGeckoEvent::APZ_INPUT_EVENT:
+            if (mAllowCoalescingTouches && mEventQueue.Length() > 0) {
                 int len = mEventQueue.Length();
-                if (len > 0) {
-                    AndroidGeckoEvent* event = mEventQueue[len - 1];
-                    if (event->Type() == AndroidGeckoEvent::MOTION_EVENT && event->Action() == AndroidMotionEvent::ACTION_MOVE) {
-                        // consecutive motion-move events; drop the last one before adding the new one
-                        EVLOG("nsAppShell: Dropping old move event at %p in favour of new move event %p", event, ae);
-                        mEventQueue.RemoveElementAt(len - 1);
-                        delete event;
-                    }
+                AndroidGeckoEvent* event = mEventQueue[len - 1];
+                if (ae->CanCoalesceWith(event)) {
+                    // consecutive motion-move events; drop the last one before adding the new one
+                    EVLOG("nsAppShell: Dropping old move event at %p in favour of new move event %p", event, ae);
+                    mEventQueue.RemoveElementAt(len - 1);
+                    delete event;
                 }
             }
             mEventQueue.AppendElement(ae);
             break;
 
         case AndroidGeckoEvent::NATIVE_POKE:
             allowCoalescingNextViewport = true;
             // fall through
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -828,16 +828,17 @@ nsWindow::OnGlobalAndroidEvent(AndroidGe
                 if (NS_SUCCEEDED(obs->AddObserver(notifier, "xpcom-shutdown", false)))
                     gContentCreationNotifier = notifier;
                 else
                     obs->RemoveObserver(notifier, "ipc:content-created");
             }
             break;
         }
 
+        case AndroidGeckoEvent::APZ_INPUT_EVENT:
         case AndroidGeckoEvent::MOTION_EVENT: {
             win->UserActivity();
             if (!gTopLevelWindows.IsEmpty()) {
                 nsIntPoint pt(0,0);
                 const nsTArray<nsIntPoint>& points = ae->Points();
                 if (points.Length() > 0) {
                     pt = points[0];
                 }
@@ -1027,26 +1028,34 @@ bool nsWindow::OnMultitouchEvent(Android
 
     // if the last event we got was a down event, then by now we know for sure whether
     // this block has been default-prevented or not. if we haven't already sent the
     // notification for this block, do so now.
     if (sLastWasDownEvent && !sDefaultPreventedNotified) {
         // if this event is a down event, that means it's the start of a new block, and the
         // previous block should not be default-prevented
         bool defaultPrevented = isDownEvent ? false : preventDefaultActions;
-        mozilla::widget::android::GeckoAppShell::NotifyDefaultPrevented(defaultPrevented);
+        if (ae->Type() == AndroidGeckoEvent::APZ_INPUT_EVENT) {
+            mozilla::widget::android::APZCCallbackHandler::GetInstance()->NotifyDefaultPrevented(ae->ApzGuid(), defaultPrevented);
+        } else {
+            mozilla::widget::android::GeckoAppShell::NotifyDefaultPrevented(defaultPrevented);
+        }
         sDefaultPreventedNotified = true;
     }
 
     // now, if this event is a down event, then we might already know that it has been
     // default-prevented. if so, we send the notification right away; otherwise we wait
     // for the next event.
     if (isDownEvent) {
         if (preventDefaultActions) {
-            mozilla::widget::android::GeckoAppShell::NotifyDefaultPrevented(true);
+            if (ae->Type() == AndroidGeckoEvent::APZ_INPUT_EVENT) {
+                mozilla::widget::android::APZCCallbackHandler::GetInstance()->NotifyDefaultPrevented(ae->ApzGuid(), true);
+            } else {
+                mozilla::widget::android::GeckoAppShell::NotifyDefaultPrevented(true);
+            }
             sDefaultPreventedNotified = true;
         } else {
             sDefaultPreventedNotified = false;
         }
     }
     sLastWasDownEvent = isDownEvent;
 
     return preventDefaultActions;