Bug 839641 - Add a stub NativePanZoomController class to start Java bindings to APZC. r=Cwiiis
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 26 Apr 2013 13:24:28 -0400
changeset 130089 b5ffa6b0d9276e554815faf7d387c7ac62677097
parent 130088 2c1cdf681fffbd0e0a7fc93cb0d4cd0ad0982f42
child 130090 7e093f07dd05703e195e0d1201a161a55e93d09b
push idunknown
push userunknown
push dateunknown
reviewersCwiiis
bugs839641
milestone23.0a1
Bug 839641 - Add a stub NativePanZoomController class to start Java bindings to APZC. r=Cwiiis
mobile/android/base/Makefile.in
mobile/android/base/gfx/GeckoLayerClient.java
mobile/android/base/gfx/NativePanZoomController.java
mobile/android/base/jni-generator.py
mozglue/android/jni-stubs.inc
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJNI.cpp
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -189,21 +189,22 @@ FENNEC_JAVA_FILES = \
   gfx/ImmutableViewportMetrics.java \
   gfx/InputConnectionHandler.java \
   gfx/IntSize.java \
   gfx/JavaPanZoomController.java \
   gfx/Layer.java \
   gfx/LayerMarginsAnimator.java \
   gfx/LayerRenderer.java \
   gfx/LayerView.java \
-  gfx/PluginLayer.java \
+  gfx/NativePanZoomController.java \
   gfx/NinePatchTileLayer.java \
   gfx/PanningPerfAPI.java \
   gfx/PanZoomController.java \
   gfx/PanZoomTarget.java \
+  gfx/PluginLayer.java \
   gfx/PointUtils.java \
   gfx/ProgressiveUpdateData.java \
   gfx/RectUtils.java \
   gfx/ScrollbarLayer.java \
   gfx/SimpleScaleGestureDetector.java \
   gfx/SingleTileLayer.java \
   gfx/SubdocumentScrollHelper.java \
   gfx/TextLayer.java \
@@ -1113,17 +1114,18 @@ jars/webrtc.jar: $(addprefix $(srcdir)/,
 endif
 
 jars:
 	@echo "MKDIR jars"
 	$(NSINSTALL) -D jars
 
 CLASSES_WITH_JNI= \
     org.mozilla.gecko.GeckoAppShell \
-		org.mozilla.gecko.GeckoJavaSampler \
+    org.mozilla.gecko.GeckoJavaSampler \
+    org.mozilla.gecko.gfx.NativePanZoomController \
     $(NULL)
 
 ifdef MOZ_WEBSMS_BACKEND
 # Note: if you are building with MOZ_WEBSMS_BACKEND turned on, then
 # you will get a build error because the generated jni-stubs.inc will
 # be different than the one checked in (i.e. it will have the sms-related
 # JNI stubs as well). Just copy the generated file to mozglue/android/
 # like the error message says and rebuild. All should be well after that.
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/gfx/GeckoLayerClient.java
@@ -108,16 +108,17 @@ public class GeckoLayerClient implements
         mProgressiveUpdateDisplayPort = new DisplayPortMetrics();
         mLastProgressiveUpdateWasLowPrecision = false;
         mProgressiveUpdateWasInDanger = false;
 
         mForceRedraw = true;
         DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
         mViewportMetrics = new ImmutableViewportMetrics(displayMetrics)
                            .setViewportSize(view.getWidth(), view.getHeight());
+        mFrameMetrics = mViewportMetrics;
         mZoomConstraints = new ZoomConstraints(false);
 
         mPanZoomController = PanZoomController.Factory.create(this, view, eventDispatcher);
         mMarginsAnimator = new LayerMarginsAnimator(this);
         mView = view;
         mView.setListener(this);
     }
 
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/gfx/NativePanZoomController.java
@@ -0,0 +1,80 @@
+/* -*- 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.gfx;
+
+import org.mozilla.gecko.GeckoEvent;
+import org.mozilla.gecko.GeckoThread;
+import org.mozilla.gecko.util.EventDispatcher;
+import org.mozilla.gecko.util.GeckoEventListener;
+
+import org.json.JSONObject;
+
+import android.graphics.PointF;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+
+class NativePanZoomController implements PanZoomController, GeckoEventListener {
+    private final EventDispatcher mDispatcher;
+
+    NativePanZoomController(PanZoomTarget target, View view, EventDispatcher dispatcher) {
+        mDispatcher = dispatcher;
+        if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
+            init();
+        } else {
+            mDispatcher.registerEventListener("Gecko:Ready", this);
+        }
+    }
+
+    public void handleMessage(String event, JSONObject message) {
+        if ("Gecko:Ready".equals(event)) {
+            mDispatcher.unregisterEventListener("Gecko:Ready", this);
+            init();
+        }
+    }
+
+    public boolean onTouchEvent(MotionEvent event) {
+        // FIXME implement this
+        return false;
+    }
+
+    public boolean onMotionEvent(MotionEvent event) {
+        // FIXME implement this
+        return false;
+    }
+
+    public boolean onKeyEvent(KeyEvent event) {
+        // FIXME implement this
+        return false;
+    }
+
+    public PointF getVelocityVector() {
+        // FIXME implement this
+        return new PointF(0, 0);
+    }
+
+    public void pageRectUpdated() {
+        // no-op in APZC, I think
+    }
+
+    public void abortPanning() {
+        // no-op in APZC, I think
+    }
+
+    public void abortAnimation() {
+        // no-op in APZC, I think
+    }
+
+    private native void init();
+    private native void 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();
+}
--- a/mobile/android/base/jni-generator.py
+++ b/mobile/android/base/jni-generator.py
@@ -66,16 +66,18 @@ class Generator:
                 paramTypes = re.split('\s*,\s*', match.group(1))
                 paramNames = ['arg%d' % i for i in range(0, len(paramTypes))]
                 if returnType == 'void':
                     returnValue = ''
                 elif returnType == 'jobject':
                     returnValue = 'NULL'
                 elif returnType in ('jint', 'jfloat', 'jdouble'):
                     returnValue = '0'
+                elif returnType == 'jboolean':
+                    returnValue = 'false'
                 else:
                     raise Exception(('Unsupported JNI return type %s found; '
                                      + 'please update mobile/android/base/'
                                      + 'jni-generator.py to handle this case!')
                                     % returnType)
 
                 self.write('JNI_STUBS', STUB_TEMPLATE % {
                     'returnType': returnType,
--- a/mozglue/android/jni-stubs.inc
+++ b/mozglue/android/jni-stubs.inc
@@ -393,8 +393,160 @@ Java_org_mozilla_gecko_GeckoJavaSampler_
     return f_Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(arg0, arg1);
 }
 #endif
 
 #ifdef JNI_BINDINGS
   xul_dlsym("Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime", &f_Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime);
 #endif
 
+#ifdef JNI_STUBS
+
+typedef void (*Java_org_mozilla_gecko_gfx_NativePanZoomController_init_t)(JNIEnv *, jobject);
+static Java_org_mozilla_gecko_gfx_NativePanZoomController_init_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_init;
+extern "C" NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_init(JNIEnv * arg0, jobject arg1) {
+    if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_init) {
+        arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
+                       "JNI Function called before it was loaded");
+        return ;
+    }
+     f_Java_org_mozilla_gecko_gfx_NativePanZoomController_init(arg0, arg1);
+}
+#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);
+static Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent;
+extern "C" NS_EXPORT void 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 ;
+    }
+     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
+
+typedef void (*Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent_t)(JNIEnv *, jobject, jobject);
+static Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent;
+extern "C" NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent(JNIEnv * arg0, jobject arg1, jobject arg2) {
+    if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent) {
+        arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
+                       "JNI Function called before it was loaded");
+        return ;
+    }
+     f_Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent(arg0, arg1, arg2);
+}
+#endif
+
+#ifdef JNI_BINDINGS
+  xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent);
+#endif
+
+#ifdef JNI_STUBS
+
+typedef void (*Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy_t)(JNIEnv *, jobject);
+static Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy;
+extern "C" NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy(JNIEnv * arg0, jobject arg1) {
+    if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy) {
+        arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
+                       "JNI Function called before it was loaded");
+        return ;
+    }
+     f_Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy(arg0, arg1);
+}
+#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;
+    }
+    return f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint(arg0, arg1);
+}
+#endif
+
+#ifdef JNI_BINDINGS
+  xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint);
+#endif
+
+#ifdef JNI_STUBS
+
+typedef void (*Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode_t)(JNIEnv *, jobject, jint);
+static Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode;
+extern "C" NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode(JNIEnv * arg0, jobject arg1, jint arg2) {
+    if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode) {
+        arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
+                       "JNI Function called before it was loaded");
+        return ;
+    }
+     f_Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode(arg0, arg1, arg2);
+}
+#endif
+
+#ifdef JNI_BINDINGS
+  xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode);
+#endif
+
+#ifdef JNI_STUBS
+
+typedef jint (*Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode_t)(JNIEnv *, jobject);
+static Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode_t f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode;
+extern "C" NS_EXPORT jint JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv * arg0, jobject arg1) {
+    if (!f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode) {
+        arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
+                       "JNI Function called before it was loaded");
+        return 0;
+    }
+    return f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(arg0, arg1);
+}
+#endif
+
+#ifdef JNI_BINDINGS
+  xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode);
+#endif
+
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -40,17 +40,17 @@
 #else
 #define ALOG_BRIDGE(args...) ((void)0)
 #endif
 
 using namespace mozilla;
 
 NS_IMPL_THREADSAFE_ISUPPORTS0(nsFilePickerCallback)
 
-AndroidBridge *AndroidBridge::sBridge = 0;
+nsRefPtr<AndroidBridge> AndroidBridge::sBridge = nullptr;
 static unsigned sJavaEnvThreadIndex = 0;
 static void JavaThreadDetachFunc(void *arg);
 
 // This is a dummy class that can be used in the template for android::sp
 class AndroidRefable {
     void incStrong(void* thing) { }
     void decStrong(void* thing) { }
 };
@@ -2116,17 +2116,18 @@ AndroidBridge::SyncViewportInfo(const ns
         return;
 
     client->SyncViewportInfo(aDisplayPort, aDisplayResolution, aLayersUpdated,
                              aScrollOffset, aScaleX, aScaleY, aFixedLayerMargins,
                              aOffsetX, aOffsetY);
 }
 
 AndroidBridge::AndroidBridge()
-  : mLayerClient(NULL)
+  : mLayerClient(NULL),
+    mNativePanZoomController(NULL)
 {
 }
 
 AndroidBridge::~AndroidBridge()
 {
 }
 
 /* Implementation file */
@@ -2688,8 +2689,51 @@ AndroidBridge::UnlockProfile()
     AutoLocalJNIFrame jniFrame(env, 0);
     bool ret = env->CallStaticBooleanMethod(mGeckoAppShellClass, jUnlockProfile);
     if (jniFrame.CheckForException())
         return false;
 
     return ret;
 }
 
+jobject
+AndroidBridge::SetNativePanZoomController(jobject obj)
+{
+    jobject old = mNativePanZoomController;
+    mNativePanZoomController = obj;
+    return old;
+}
+
+void
+AndroidBridge::RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics)
+{
+    // FIXME implement this
+}
+
+void
+AndroidBridge::HandleDoubleTap(const nsIntPoint& aPoint)
+{
+    // FIXME implement this
+}
+
+void
+AndroidBridge::HandleSingleTap(const nsIntPoint& aPoint)
+{
+    // FIXME implement this
+}
+
+void
+AndroidBridge::HandleLongTap(const nsIntPoint& aPoint)
+{
+    // FIXME implement this
+}
+
+void
+AndroidBridge::SendAsyncScrollDOMEvent(const gfx::Rect& aContentRect, const gfx::Size& aScrollableSize)
+{
+    // FIXME implement this
+}
+
+void
+AndroidBridge::PostDelayedTask(Task* task, int delay_ms)
+{
+    // FIXME implement this
+}
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -24,16 +24,17 @@
 #include "nsColor.h"
 #include "gfxRect.h"
 
 #include "nsIAndroidBridge.h"
 #include "nsIMobileMessageCallback.h"
 
 #include "mozilla/Likely.h"
 #include "mozilla/StaticPtr.h"
+#include "mozilla/layers/GeckoContentController.h"
 
 // Some debug #defines
 // #define DEBUG_ANDROID_EVENTS
 // #define DEBUG_ANDROID_WIDGET
 
 class nsWindow;
 class nsIDOMMozSmsMessage;
 
@@ -87,34 +88,34 @@ class nsFilePickerCallback : nsISupports
 public:
     NS_DECL_ISUPPORTS
     virtual void handleResult(nsAString& filePath) = 0;
     nsFilePickerCallback() {}
 protected:
     virtual ~nsFilePickerCallback() {}
 };
 
-class AndroidBridge
+class AndroidBridge : public mozilla::layers::GeckoContentController
 {
 public:
     enum {
         // Values for NotifyIME, in addition to values from the Gecko
         // NotificationToIME enum; use negative values here to prevent conflict
         NOTIFY_IME_REPLY_EVENT = -1,
     };
 
     enum {
         LAYER_CLIENT_TYPE_NONE = 0,
         LAYER_CLIENT_TYPE_GL = 2            // AndroidGeckoGLLayerClient
     };
 
     static void ConstructBridge(JNIEnv *jEnv, jclass jGeckoAppShellClass);
 
     static AndroidBridge *Bridge() {
-        return sBridge;
+        return sBridge.get();
     }
 
     static JavaVM *GetVM() {
         if (MOZ_LIKELY(sBridge))
             return sBridge->mJavaVM;
         return nullptr;
     }
 
@@ -379,17 +380,17 @@ public:
 
     void GetGfxInfoData(nsACString& aRet);
     nsresult GetProxyForURI(const nsACString & aSpec,
                             const nsACString & aScheme,
                             const nsACString & aHost,
                             const int32_t      aPort,
                             nsACString & aResult);
 protected:
-    static AndroidBridge *sBridge;
+    static nsRefPtr<AndroidBridge> sBridge;
     nsTArray<nsCOMPtr<nsIMobileMessageCallback> > mSmsRequests;
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
     // the JNIEnv for the main thread
     JNIEnv *mJNIEnv;
     void *mThread;
@@ -538,16 +539,28 @@ protected:
 
     int (* ANativeWindow_lock)(void *window, void *outBuffer, void *inOutDirtyBounds);
     int (* ANativeWindow_unlockAndPost)(void *window);
 
     int (* Surface_lock)(void* surface, void* surfaceInfo, void* region, bool block);
     int (* Surface_unlockAndPost)(void* surface);
     void (* Region_constructor)(void* region);
     void (* Region_set)(void* region, void* rect);
+
+private:
+    jobject mNativePanZoomController;
+public:
+    jobject SetNativePanZoomController(jobject obj);
+    // GeckoContentController methods
+    void RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
+    void HandleDoubleTap(const nsIntPoint& aPoint) MOZ_OVERRIDE;
+    void HandleSingleTap(const nsIntPoint& aPoint) MOZ_OVERRIDE;
+    void HandleLongTap(const nsIntPoint& aPoint) MOZ_OVERRIDE;
+    void SendAsyncScrollDOMEvent(const gfx::Rect& aContentRect, const gfx::Size& aScrollableSize) MOZ_OVERRIDE;
+    void PostDelayedTask(Task* task, int delay_ms) MOZ_OVERRIDE;
 };
 
 class AutoJObject {
 public:
     AutoJObject(JNIEnv* aJNIEnv = NULL) : mObject(NULL)
     {
         mJNIEnv = aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv();
     }
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -30,24 +30,26 @@
 
 #include "mozilla/unused.h"
 
 #include "mozilla/dom/SmsMessage.h"
 #include "mozilla/dom/mobilemessage/Constants.h"
 #include "mozilla/dom/mobilemessage/Types.h"
 #include "mozilla/dom/mobilemessage/PSms.h"
 #include "mozilla/dom/mobilemessage/SmsParent.h"
+#include "mozilla/layers/AsyncPanZoomController.h"
 #include "nsIMobileMessageDatabaseService.h"
 #include "nsPluginInstanceOwner.h"
 #include "nsSurfaceTexture.h"
 #include "GeckoProfiler.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobilemessage;
+using namespace mozilla::layers;
 
 /* Forward declare all the JNI methods as extern "C" */
 
 extern "C" {
 /*
  * Incoming JNI methods
  */
 
@@ -878,9 +880,78 @@ Java_org_mozilla_gecko_GeckoAppShell_onS
 }
 
 NS_EXPORT jdouble JNICALL
 Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv *jenv, jclass jc)
 {
   return profiler_time();
 }
 
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_init(JNIEnv* env, jobject instance)
+{
+    if (!AndroidBridge::Bridge()) {
+        return;
+    }
+
+    jobject oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(env->NewGlobalRef(instance));
+    if (oldRef) {
+        MOZ_ASSERT(false, "Registering a new NPZC when we already have one");
+        env->DeleteGlobalRef(oldRef);
+    }
+    nsWindow::SetPanZoomController(new AsyncPanZoomController(AndroidBridge::Bridge(), AsyncPanZoomController::USE_GESTURE_DETECTOR));
 }
+
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv* env, jobject instance, jobject event)
+{
+    // FIXME implement this
+}
+
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent(JNIEnv* env, jobject instance, jobject event)
+{
+    // FIXME implement this
+}
+
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy(JNIEnv* env, jobject instance)
+{
+    if (!AndroidBridge::Bridge()) {
+        return;
+    }
+
+    nsWindow::SetPanZoomController(nullptr);
+    jobject oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(NULL);
+    if (!oldRef) {
+        MOZ_ASSERT(false, "Clearing a non-existent NPZC");
+    } else {
+        env->DeleteGlobalRef(oldRef);
+    }
+}
+
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented(JNIEnv* env, jobject instance, jboolean prevented)
+{
+    // FIXME implement this
+}
+
+NS_EXPORT jboolean JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint(JNIEnv* env, jobject instance)
+{
+    // FIXME implement this
+    return true;
+}
+
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode(JNIEnv* env, jobject instance, jint overscrollMode)
+{
+    // FIXME implement this
+}
+
+NS_EXPORT jint JNICALL
+Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv* env, jobject instance)
+{
+    // FIXME implement this
+    return 0;
+}
+
+}