Bug 1116589 - Use templated JNI classes in generated bindings; r=snorp
authorJim Chen <nchen@mozilla.com>
Fri, 09 Jan 2015 19:33:57 -0500
changeset 248922 e706eac29b226646543cbab604a976b28352930a
parent 248921 69654c281aaac7e1724080995386a674847d9c8a
child 248923 5f6cebc36e84fb574d5809ac91bb1a42190658f4
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1116589
milestone37.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 1116589 - Use templated JNI classes in generated bindings; r=snorp
CLOBBER
build/annotationProcessors/AnnotationInfo.java
build/annotationProcessors/AnnotationProcessor.java
build/annotationProcessors/CodeGenerator.java
build/annotationProcessors/SDKProcessor.java
build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
build/annotationProcessors/utils/GeneratableElementIterator.java
build/annotationProcessors/utils/Utils.java
dom/ipc/ContentParent.cpp
dom/media/fmp4/android/AndroidDecoderModule.cpp
dom/media/fmp4/android/AndroidDecoderModule.h
dom/plugins/base/android/ANPSystem.cpp
dom/plugins/base/nsNPAPIPlugin.cpp
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/system/android/AndroidLocationProvider.cpp
dom/system/android/nsHapticFeedback.cpp
gfx/gl/AndroidSurfaceTexture.cpp
gfx/gl/AndroidSurfaceTexture.h
hal/android/AndroidGamepad.cpp
hal/android/AndroidHal.cpp
hal/android/AndroidSensor.cpp
ipc/glue/MessagePump.cpp
mobile/android/base/GeckoAppShell.java
mobile/android/components/build/nsAndroidHistory.cpp
mobile/android/components/build/nsShellService.cpp
mozglue/android/jni-stubs.inc
netwerk/base/src/Tickler.cpp
netwerk/protocol/device/CameraStreamImpl.cpp
netwerk/system/android/nsAndroidNetworkLinkService.cpp
toolkit/components/alerts/nsAlertsService.cpp
toolkit/components/downloads/nsDownloadManager.cpp
toolkit/components/jsdownloads/src/DownloadPlatform.cpp
toolkit/components/parentalcontrols/nsParentalControlsServiceAndroid.cpp
toolkit/xre/nsAndroidStartup.cpp
toolkit/xre/nsAppRunner.cpp
tools/profiler/TableTicker.cpp
tools/profiler/platform.cpp
uriloader/exthandler/android/nsAndroidHandlerApp.cpp
uriloader/exthandler/android/nsExternalSharingAppService.cpp
uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
widget/android/APZCCallbackHandler.cpp
widget/android/APZCCallbackHandler.h
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJNI.cpp
widget/android/AndroidJavaWrappers.cpp
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
widget/android/nsAndroidProtocolHandler.cpp
widget/android/nsAppShell.cpp
widget/android/nsClipboard.cpp
widget/android/nsIMEPicker.cpp
widget/android/nsLookAndFeel.cpp
widget/android/nsScreenManagerAndroid.cpp
widget/android/nsWindow.cpp
xpcom/base/nsSystemInfo.cpp
xpcom/components/ManifestParser.cpp
xpcom/io/nsLocalFileUnix.cpp
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1056337 - Change default compiler for B2G ICS builds.
+Bug 1116589 - Clobber needed to update autogenerated Android library bindings.
--- a/build/annotationProcessors/AnnotationInfo.java
+++ b/build/annotationProcessors/AnnotationInfo.java
@@ -17,14 +17,14 @@ public class AnnotationInfo {
     public AnnotationInfo(String aWrapperName, boolean aIsMultithreaded,
                           boolean aNoThrow, boolean aNarrowChars, boolean aCatchException) {
         wrapperName = aWrapperName;
         isMultithreaded = aIsMultithreaded;
         noThrow = aNoThrow;
         narrowChars = aNarrowChars;
         catchException = aCatchException;
 
-        if (!noThrow && catchException) {
+        if (noThrow && catchException) {
             // It doesn't make sense to have these together
             throw new IllegalArgumentException("noThrow and catchException are not allowed together");
         }
     }
 }
--- a/build/annotationProcessors/AnnotationProcessor.java
+++ b/build/annotationProcessors/AnnotationProcessor.java
@@ -15,19 +15,21 @@ import java.util.Arrays;
 import java.util.Iterator;
 
 public class AnnotationProcessor {
     public static final String OUTFILE = "GeneratedJNIWrappers.cpp";
     public static final String HEADERFILE = "GeneratedJNIWrappers.h";
 
     public static final String GENERATED_COMMENT =
             "// GENERATED CODE\n" +
-            "// Generated by the Java program at /build/annotationProcessors at compile time from\n" +
-            "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" +
-            "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n";
+            "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
+            "// from annotations on Java methods. To update, change the annotations on the\n" +
+            "// corresponding Javamethods and rerun the build. Manually updating this file\n" +
+            "// will cause your build to fail.\n" +
+            "\n";
 
     public static void main(String[] args) {
         // We expect a list of jars on the commandline. If missing, whinge about it.
         if (args.length <= 1) {
             System.err.println("Usage: java AnnotationProcessor jarfiles ...");
             System.exit(1);
         }
 
@@ -39,54 +41,47 @@ public class AnnotationProcessor {
 
         // Start the clock!
         long s = System.currentTimeMillis();
 
         // Get an iterator over the classes in the jar files given...
         Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
 
         StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
-        headerFile.append("#ifndef GeneratedJNIWrappers_h__\n" +
-                          "#define GeneratedJNIWrappers_h__\n\n" +
-                          "#include \"nsXPCOMStrings.h\"\n" +
-                          "#include \"AndroidJavaWrappers.h\"\n" +
-                          "\n" +
-                          "namespace mozilla {\n" +
-                          "namespace widget {\n" +
-                          "namespace android {\n" +
-                          "void InitStubs(JNIEnv *env);\n\n");
+        headerFile.append(
+                "#ifndef GeneratedJNIWrappers_h__\n" +
+                "#define GeneratedJNIWrappers_h__\n" +
+                "\n" +
+                "#include \"mozilla/jni/Refs.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "\n");
 
         StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
-        implementationFile.append("#include \"GeneratedJNIWrappers.h\"\n" +
-                                  "#include \"AndroidBridgeUtilities.h\"\n" +
-                                  "#include \"nsXPCOMStrings.h\"\n" +
-                                  "#include \"AndroidBridge.h\"\n" +
-                                  "\n" +
-                                  "namespace mozilla {\n" +
-                                  "namespace widget {\n" +
-                                  "namespace android {\n");
-
-        // Used to track the calls to the various class-specific initialisation functions.
-        StringBuilder stubInitialiser = new StringBuilder();
-        stubInitialiser.append("void InitStubs(JNIEnv *env) {\n");
+        implementationFile.append(
+                "#include \"GeneratedJNIWrappers.h\"\n" +
+                "#include \"mozilla/jni/Accessors.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "\n");
 
         while (jarClassIterator.hasNext()) {
             ClassWithOptions aClassTuple = jarClassIterator.next();
 
             CodeGenerator generatorInstance;
 
             // Get an iterator over the appropriately generated methods of this class
             Iterator<AnnotatableEntity> methodIterator = new GeneratableElementIterator(aClassTuple.wrappedClass);
 
             if (!methodIterator.hasNext()) {
                 continue;
             }
-            generatorInstance = new CodeGenerator(aClassTuple.wrappedClass, aClassTuple.generatedName);
-
-            stubInitialiser.append("    ").append(aClassTuple.generatedName).append("::InitStubs(env);\n");
+            generatorInstance = new CodeGenerator(aClassTuple);
 
             // Iterate all annotated members in this class..
             while (methodIterator.hasNext()) {
                 AnnotatableEntity aElementTuple = methodIterator.next();
                 switch (aElementTuple.mEntityType) {
                     case METHOD:
                         generatorInstance.generateMethod(aElementTuple);
                         break;
@@ -98,28 +93,26 @@ public class AnnotationProcessor {
                         break;
                 }
             }
 
             headerFile.append(generatorInstance.getHeaderFileContents());
             implementationFile.append(generatorInstance.getWrapperFileContents());
         }
 
-        implementationFile.append('\n');
-        stubInitialiser.append("}");
-        implementationFile.append(stubInitialiser);
+        implementationFile.append(
+                "\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n");
 
-        implementationFile.append("\n} /* android */\n" +
-                                    "} /* widget */\n" +
-                                    "} /* mozilla */\n");
-
-        headerFile.append("\n} /* android */\n" +
-                            "} /* widget */\n" +
-                            "} /* mozilla */\n" +
-                            "#endif\n");
+        headerFile.append(
+                "\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n" +
+                "#endif // GeneratedJNIWrappers_h__\n");
 
         writeOutputFiles(headerFile, implementationFile);
         long e = System.currentTimeMillis();
         System.out.println("Annotation processing complete in " + (e - s) + "ms");
     }
 
     private static void writeOutputFiles(StringBuilder aHeaderFile, StringBuilder aImplementationFile) {
         FileOutputStream headerStream = null;
@@ -153,9 +146,9 @@ public class AnnotationProcessor {
                     outStream.close();
                 } catch (IOException e) {
                     System.err.println("Unable to close outStream due to "+e);
                     e.printStackTrace(System.err);
                 }
             }
         }
     }
-}
\ No newline at end of file
+}
--- a/build/annotationProcessors/CodeGenerator.java
+++ b/build/annotationProcessors/CodeGenerator.java
@@ -1,693 +1,462 @@
 /* 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.annotationProcessors;
 
 import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
 import org.mozilla.gecko.annotationProcessors.utils.Utils;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.HashMap;
 import java.util.HashSet;
 
 public class CodeGenerator {
     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
-    private static final Annotation[][] GETTER_ARGUMENT_ANNOTATIONS = new Annotation[0][0];
-    private static final Annotation[][] SETTER_ARGUMENT_ANNOTATIONS = new Annotation[1][0];
 
     // Buffers holding the strings to ultimately be written to the output files.
-    private final StringBuilder zeroingCode = new StringBuilder();
-    private final StringBuilder wrapperStartupCode = new StringBuilder();
-    private final StringBuilder wrapperMethodBodies = new StringBuilder();
-    private final StringBuilder headerPublic = new StringBuilder();
-    private final StringBuilder headerProtected = new StringBuilder();
+    private final StringBuilder cpp = new StringBuilder();
+    private final StringBuilder header = new StringBuilder();
+
+    private final Class<?> cls;
+    private final String clsName;
 
-    private final HashSet<String> seenClasses = new HashSet<String>();
+    private final HashSet<String> takenMethodNames = new HashSet<String>();
 
-    private final String mCClassName;
-
-    private final Class<?> mClassToWrap;
+    public CodeGenerator(ClassWithOptions annotatedClass) {
+        this.cls = annotatedClass.wrappedClass;
+        this.clsName = annotatedClass.generatedName;
 
-    private boolean mHasEncounteredDefaultConstructor;
+        header.append(
+                "class " + clsName + " : public mozilla::jni::Class<" + clsName + "> {\n" +
+                "\n" +
+                "public:\n" +
+                "    typedef mozilla::jni::Ref<" + clsName + "> Ref;\n" +
+                "    typedef mozilla::jni::LocalRef<" + clsName + "> LocalRef;\n" +
+                "    typedef mozilla::jni::GlobalRef<" + clsName + "> GlobalRef;\n" +
+                "    typedef const typename mozilla::jni::Param<" + clsName + ">::Type& Param;\n" +
+                "\n" +
+                "    static constexpr char name[] =\n" +
+                "            \"" + cls.getName().replace('.', '/') + "\";\n" +
+                "\n" +
+                "protected:\n" +
+                "    " + clsName + "(jobject instance) : Class(instance) {}\n" +
+                "\n");
 
-    // Used for creating unique names for method ID fields in the face of
-    private final HashMap<Member, String> mMembersToIds = new HashMap<Member, String>();
-    private final HashSet<String> mTakenMemberNames = new HashSet<String>();
-    private int mNameMunger;
+        cpp.append(
+                "constexpr char " + clsName + "::name[];\n" +
+                "\n");
+    }
 
-    private final boolean mLazyInit;
+    private String getTraitsName(String uniqueName, boolean includeScope) {
+        return (includeScope ? clsName + "::" : "") + uniqueName + "_t";
+    }
 
-    public CodeGenerator(Class<?> aClass, String aGeneratedName) {
-        this(aClass, aGeneratedName, false);
+    private String getNativeParameterType(Class<?> type, AnnotationInfo info) {
+        if (type == cls) {
+            return clsName + "::Param";
+        }
+        return Utils.getNativeParameterType(type, info);
     }
 
-    public CodeGenerator(Class<?> aClass, String aGeneratedName, boolean aLazyInit) {
-        mClassToWrap = aClass;
-        mCClassName = aGeneratedName;
-        mLazyInit = aLazyInit;
+    private String getNativeReturnType(Class<?> type, AnnotationInfo info) {
+        if (type == cls) {
+            return clsName + "::LocalRef";
+        }
+        return Utils.getNativeReturnType(type, info);
+    }
 
-        // Write the file header things. Includes and so forth.
-        // GeneratedJNIWrappers.cpp is generated as the concatenation of wrapperStartupCode with
-        // wrapperMethodBodies. Similarly, GeneratedJNIWrappers.h is the concatenation of headerPublic
-        // with headerProtected.
-        wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *env) {\n");
+    private void generateMember(AnnotationInfo info, Member member,
+                                String uniqueName, Class<?> type) {
+        header.append(
+                "public:\n" +
+                "    struct " + getTraitsName(uniqueName, /* includeScope */ false) + " {\n" +
+                "        typedef " + clsName + " Owner;\n" +
+                "        typedef " + getNativeReturnType(type, info) + " ReturnType;\n" +
+                "        typedef " + getNativeParameterType(type, info) + " SetterType;\n" +
+                "        static constexpr char name[] = \"" +
+                        Utils.getMemberName(member) + "\";\n" +
+                "        static constexpr char signature[] =\n" +
+                "                \"" + Utils.getSignature(member) + "\";\n" +
+                "        static const bool isStatic = " + Utils.isStatic(member) + ";\n" +
+                "        static const bool isMultithreaded = " + info.isMultithreaded + ";\n" +
+                "        static const mozilla::jni::ExceptionMode exceptionMode = " + (
+                        info.catchException ? "mozilla::jni::ExceptionMode::NSRESULT" :
+                        info.noThrow ?        "mozilla::jni::ExceptionMode::IGNORE" :
+                                              "mozilla::jni::ExceptionMode::ABORT") + ";\n" +
+                "    };\n" +
+                "\n");
 
-        // Now we write the various GetStaticMethodID calls here...
-        headerPublic.append("class ").append(mCClassName).append(" : public AutoGlobalWrappedJavaObject {\n" +
-                            "public:\n" +
-                            "    static void InitStubs(JNIEnv *env);\n");
-        headerProtected.append("protected:");
+        cpp.append(
+                "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
+                        "::name[];\n" +
+                "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
+                        "::signature[];\n" +
+                "\n");
+    }
 
-        generateWrapperMethod();
+    private String getUniqueMethodName(String basename) {
+        String newName = basename;
+        int index = 1;
+
+        while (takenMethodNames.contains(newName)) {
+            newName = basename + (++index);
+        }
+
+        takenMethodNames.add(newName);
+        return newName;
     }
 
     /**
-     * Emit a static method which takes an instance of the class being wrapped and returns an instance
-     * of the C++ wrapper class backed by that object.
+     * Generate a method prototype that includes return and argument types,
+     * without specifiers (static, const, etc.).
      */
-    private void generateWrapperMethod() {
-        headerPublic.append("    static ").append(mCClassName).append("* Wrap(jobject obj);\n" +
-                "    ").append(mCClassName).append("(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {};\n");
+    private String generatePrototype(String name, Class<?>[] argTypes,
+                                     Class<?> returnType, AnnotationInfo info,
+                                     boolean includeScope, boolean includeArgName) {
+
+        final StringBuilder proto = new StringBuilder();
+        int argIndex = 0;
+
+        if (info.catchException) {
+            proto.append("nsresult ");
+        } else {
+            proto.append(getNativeReturnType(returnType, info)).append(' ');
+        }
+
+        if (includeScope) {
+            proto.append(clsName).append("::");
+        }
+
+        proto.append(name).append('(');
 
-        wrapperMethodBodies.append("\n").append(mCClassName).append("* ").append(mCClassName).append("::Wrap(jobject obj) {\n" +
-                "    JNIEnv *env = GetJNIForThread();\n" +
-                "    ").append(mCClassName).append("* ret = new ").append(mCClassName).append("(obj, env);\n" +
-                "    env->DeleteLocalRef(obj);\n" +
-                "    return ret;\n" +
-                "}\n");
+        for (Class<?> argType : argTypes) {
+            proto.append(getNativeParameterType(argType, info));
+            if (includeArgName) {
+                proto.append(" a").append(argIndex++);
+            }
+            proto.append(", ");
+        }
+
+        if (info.catchException && returnType != void.class) {
+            proto.append(getNativeReturnType(returnType, info)).append('*');
+            if (includeArgName) {
+                proto.append(" a").append(argIndex++);
+            }
+            proto.append(", ");
+        }
+
+        if (proto.substring(proto.length() - 2).equals(", ")) {
+            proto.setLength(proto.length() - 2);
+        }
+
+        return proto.append(')').toString();
+    }
+
+    /**
+     * Generate a method declaration that includes the prototype with specifiers,
+     * but without the method body.
+     */
+    private String generateDeclaration(String name, Class<?>[] argTypes,
+                                       Class<?> returnType, AnnotationInfo info,
+                                       boolean isStatic) {
+
+        return (isStatic ? "static " : "") +
+            generatePrototype(name, argTypes, returnType, info,
+                              /* includeScope */ false, /* includeArgName */ false) +
+            (isStatic ? ";" : " const;");
     }
 
-    private void generateMemberCommon(Member theMethod, String aCMethodName, Class<?> aClass) {
-        ensureClassHeaderAndStartup(aClass);
-        writeMemberIdField(theMethod, aCMethodName);
+    /**
+     * Generate a method definition that includes the prototype with specifiers,
+     * and with the method body.
+     */
+    private String generateDefinition(String accessorName, String name, Class<?>[] argTypes,
+                                      Class<?> returnType, AnnotationInfo info, boolean isStatic) {
+
+        final StringBuilder def = new StringBuilder(
+                generatePrototype(name, argTypes, returnType, info,
+                                  /* includeScope */ true, /* includeArgName */ true));
+
+        if (!isStatic) {
+            def.append(" const");
+        }
+        def.append("\n{\n");
+
+
+        // Generate code to handle the return value, if needed.
+        // We initialize rv to NS_OK instead of NS_ERROR_* because loading NS_OK (0) uses
+        // fewer instructions. We are guaranteed to set rv to the correct value later.
+
+        if (info.catchException && returnType == void.class) {
+            def.append(
+                    "    nsresult rv = NS_OK;\n" +
+                    "    ");
 
-        if (!mLazyInit) {
-            writeMemberInit(theMethod, wrapperStartupCode);
+        } else if (info.catchException) {
+            // Non-void return type
+            final String resultArg = "a" + argTypes.length;
+            def.append(
+                    "    MOZ_ASSERT(" + resultArg + ");\n" +
+                    "    nsresult rv = NS_OK;\n" +
+                    "    *" + resultArg + " = ");
+
+        } else {
+            def.append(
+                    "    return ");
         }
+
+
+        // Generate a call, e.g., Method<Traits>::Call(a0, a1, a2);
+
+        def.append(accessorName).append("(")
+           .append(isStatic ? "nullptr" : "this");
+
+        if (info.catchException) {
+            def.append(", &rv");
+        } else {
+            def.append(", nullptr");
+        }
+
+        // Generate the call argument list.
+        for (int argIndex = 0; argIndex < argTypes.length; argIndex++) {
+            def.append(", a").append(argIndex);
+        }
+
+        def.append(");\n");
+
+
+        if (info.catchException) {
+            def.append("    return rv;\n");
+        }
+
+        return def.append("}").toString();
     }
 
     /**
      * Append the appropriate generated code to the buffers for the method provided.
      *
-     * @param aMethodTuple The Java method, plus annotation data.
+     * @param annotatedMethod The Java method, plus annotation data.
      */
-    public void generateMethod(AnnotatableEntity aMethodTuple) {
+    public void generateMethod(AnnotatableEntity annotatedMethod) {
         // Unpack the tuple and extract some useful fields from the Method..
-        Method theMethod = aMethodTuple.getMethod();
-
-        String CMethodName = aMethodTuple.mAnnotationInfo.wrapperName;
-
-        generateMemberCommon(theMethod, CMethodName, mClassToWrap);
-
-        boolean isFieldStatic = Utils.isMemberStatic(theMethod);
-
-        Class<?>[] parameterTypes = theMethod.getParameterTypes();
-        Class<?> returnType = theMethod.getReturnType();
+        final Method method = annotatedMethod.getMethod();
+        final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
+        final String uniqueName = getUniqueMethodName(info.wrapperName);
+        final Class<?> returnType = method.getReturnType();
 
-        // Get the C++ method signature for this method.
-        String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName,
-            mCClassName, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException);
-        String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType,
-            CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException);
-
-        // Add the header signature to the header file.
-        writeSignatureToHeader(headerSignature);
-
-        // Use the implementation signature to generate the method body...
-        writeMethodBody(implementationSignature, theMethod, mClassToWrap,
-                        aMethodTuple.mAnnotationInfo.isMultithreaded,
-                        aMethodTuple.mAnnotationInfo.noThrow,
-                        aMethodTuple.mAnnotationInfo.narrowChars,
-                        aMethodTuple.mAnnotationInfo.catchException);
-    }
-
-    private void generateGetterOrSetterBody(Field aField, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) {
-        StringBuilder argumentContent = null;
-        Class<?> fieldType = aField.getType();
-
-        if (isSetter) {
-            Class<?>[] setterArguments = new Class<?>[]{fieldType};
-            // Marshall the argument..
-            argumentContent = getArgumentMarshalling(setterArguments);
+        if (method.isSynthetic()) {
+            return;
         }
 
-        if (mLazyInit) {
-            writeMemberInit(aField, wrapperMethodBodies);
-        }
+        generateMember(info, method, uniqueName, returnType);
+
+        final Class<?>[] argTypes = method.getParameterTypes();
+        final boolean isStatic = Utils.isStatic(method);
+
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, argTypes,
+                                             returnType, info, isStatic) + "\n" +
+                "\n");
+
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Method<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
+                        info.wrapperName, argTypes, returnType, info, isStatic) + "\n" +
+                "\n");
+    }
 
-        boolean isObjectReturningMethod = Utils.isObjectType(fieldType);
-        wrapperMethodBodies.append("    ");
-        if (isSetter) {
-            wrapperMethodBodies.append("env->Set");
-        } else {
-            wrapperMethodBodies.append("return ");
+    private String getLiteral(Object val, AnnotationInfo info) {
+        final Class<?> type = val.getClass();
+
+        if (type == char.class || type == Character.class) {
+            final char c = (char) val;
+            if (c >= 0x20 && c < 0x7F) {
+                return "'" + c + '\'';
+            }
+            return "u'\\u" + Integer.toHexString(0x10000 | (int) c).substring(1) + '\'';
 
-            if (isObjectReturningMethod) {
-                wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(fieldType, aNarrowChars)).append(">(");
+        } else if (type == CharSequence.class || type == String.class) {
+            final CharSequence str = (CharSequence) val;
+            final StringBuilder out = new StringBuilder(info.narrowChars ? "u8\"" : "u\"");
+            for (int i = 0; i < str.length(); i++) {
+                final char c = str.charAt(i);
+                if (c >= 0x20 && c < 0x7F) {
+                    out.append(c);
+                } else {
+                    out.append("\\u").append(Integer.toHexString(0x10000 | (int) c).substring(1));
+                }
             }
-
-            wrapperMethodBodies.append("env->Get");
+            return out.append('"').toString();
         }
 
-        if (aIsFieldStatic) {
-            wrapperMethodBodies.append("Static");
-        }
-        wrapperMethodBodies.append(Utils.getFieldType(fieldType))
-                           .append("Field(");
-
-        // Static will require the class and the field id. Nonstatic, the object and the field id.
-        if (aIsFieldStatic) {
-            wrapperMethodBodies.append(Utils.getClassReferenceName(mClassToWrap));
-        } else {
-            wrapperMethodBodies.append("wrapped_obj");
-        }
-        wrapperMethodBodies.append(", j")
-                           .append(aFieldName);
-        if (isSetter) {
-            wrapperMethodBodies.append(argumentContent);
-        }
-
-        if (!isSetter && isObjectReturningMethod) {
-            wrapperMethodBodies.append(')');
-        }
-        wrapperMethodBodies.append(");\n" +
-                               "}\n");
+        return String.valueOf(val);
     }
 
-    public void generateField(AnnotatableEntity aFieldTuple) {
-        Field theField = aFieldTuple.getField();
+    public void generateField(AnnotatableEntity annotatedField) {
+        final Field field = annotatedField.getField();
+        final AnnotationInfo info = annotatedField.mAnnotationInfo;
+        final String uniqueName = info.wrapperName;
+        final Class<?> type = field.getType();
 
         // Handles a peculiar case when dealing with enum types. We don't care about this field.
         // It just gets in the way and stops our code from compiling.
-        if (theField.getName().equals("$VALUES")) {
+        if (field.isSynthetic() || field.getName().equals("$VALUES")) {
             return;
         }
 
-        String CFieldName = aFieldTuple.mAnnotationInfo.wrapperName;
+        final boolean isStatic = Utils.isStatic(field);
+        final boolean isFinal = Utils.isFinal(field);
 
-        Class<?> fieldType = theField.getType();
-
-        generateMemberCommon(theField, CFieldName, mClassToWrap);
+        if (isStatic && isFinal && (type.isPrimitive() || type == String.class)) {
+            Object val = null;
+            try {
+                val = field.get(null);
+            } catch (final IllegalAccessException e) {
+            }
 
-        boolean isFieldStatic = Utils.isMemberStatic(theField);
-        boolean isFieldFinal = Utils.isMemberFinal(theField);
+            if (val != null && type.isPrimitive()) {
+                // For static final primitive fields, we can use a "static const" declaration.
+                header.append(
+                    "public:\n" +
+                    "    static const " + Utils.getNativeReturnType(type, info) +
+                            ' ' + info.wrapperName + " = " + getLiteral(val, info) + ";\n" +
+                    "\n");
+                return;
+
+            } else if (val != null && type == String.class) {
+                final String nativeType = info.narrowChars ? "char" : "char16_t";
 
-        String getterName = "get" + CFieldName;
-        String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false);
-        String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false);
+                header.append(
+                    "public:\n" +
+                    "    static const " + nativeType + ' ' + info.wrapperName + "[];\n" +
+                    "\n");
 
-        writeSignatureToHeader(getterHeaderSignature);
-
-        writeFunctionStartupBoilerPlate(getterSignature, true);
+                cpp.append(
+                    "const " + nativeType + ' ' + clsName + "::" + info.wrapperName +
+                            "[] = " + getLiteral(val, info) + ";\n" +
+                    "\n");
+                return;
+            }
 
-        generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars);
+            // Fall back to using accessors if we encounter an exception.
+        }
+
+        generateMember(info, field, uniqueName, type);
 
-        // If field not final, also generate a setter function.
-        if (!isFieldFinal) {
-            String setterName = "set" + CFieldName;
+        final Class<?>[] getterArgs = EMPTY_CLASS_ARRAY;
 
-            Class<?>[] setterArguments = new Class<?>[]{fieldType};
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, getterArgs,
+                                             type, info, isStatic) + "\n" +
+                "\n");
 
-            String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false);
-            String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false);
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Field<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Get",
+                        info.wrapperName, getterArgs, type, info, isStatic) + "\n" +
+                "\n");
 
-            writeSignatureToHeader(setterHeaderSignature);
+        if (isFinal) {
+            return;
+        }
 
-            writeFunctionStartupBoilerPlate(setterSignature, true);
+        final Class<?>[] setterArgs = new Class<?>[] { type };
+
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, setterArgs,
+                                             void.class, info, isStatic) + "\n" +
+                "\n");
 
-            generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars);
-        }
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Field<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Set",
+                        info.wrapperName, setterArgs, void.class, info, isStatic) + "\n" +
+                "\n");
     }
 
-    public void generateConstructor(AnnotatableEntity aCtorTuple) {
+    public void generateConstructor(AnnotatableEntity annotatedConstructor) {
         // Unpack the tuple and extract some useful fields from the Method..
-        Constructor<?> theCtor = aCtorTuple.getConstructor();
-        String CMethodName = mCClassName;
+        final Constructor<?> method = annotatedConstructor.getConstructor();
+        final AnnotationInfo info = annotatedConstructor.mAnnotationInfo;
+        final String wrapperName = "New";
+        final String uniqueName = getUniqueMethodName(wrapperName);
+        final Class<?> returnType = cls;
 
-        generateMemberCommon(theCtor, mCClassName, mClassToWrap);
+        if (method.isSynthetic()) {
+            return;
+        }
 
-        String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName,
-            mCClassName, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException);
-        String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName,
-            mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException);
+        generateMember(info, method, uniqueName, returnType);
 
-        // Slice off the "void " from the start of the constructor declaration.
-        headerSignature = headerSignature.substring(5);
-        implementationSignature = implementationSignature.substring(5);
+        final Class<?>[] argTypes = method.getParameterTypes();
 
-        // Add the header signatures to the header file.
-        writeSignatureToHeader(headerSignature);
+        header.append(
+                "    " + generateDeclaration(wrapperName, argTypes,
+                                             returnType, info, /* isStatic */ true) + "\n" +
+                "\n");
 
-        // Use the implementation signature to generate the method body...
-        writeCtorBody(implementationSignature, theCtor,
-            aCtorTuple.mAnnotationInfo.isMultithreaded,
-            aCtorTuple.mAnnotationInfo.noThrow,
-            aCtorTuple.mAnnotationInfo.catchException);
-
-        if (theCtor.getParameterTypes().length == 0) {
-            mHasEncounteredDefaultConstructor = true;
-        }
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Constructor<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
+                        wrapperName, argTypes, returnType, info, /* isStatic */ true) + "\n" +
+                "\n");
     }
 
     public void generateMembers(Member[] members) {
         for (Member m : members) {
             if (!Modifier.isPublic(m.getModifiers())) {
                 continue;
             }
 
-            String name = m.getName();
+            String name = Utils.getMemberName(m);
             name = name.substring(0, 1).toUpperCase() + name.substring(1);
 
-            AnnotationInfo info = new AnnotationInfo(name, true, true, true, true);
-            AnnotatableEntity entity = new AnnotatableEntity(m, info);
+            final AnnotationInfo info = new AnnotationInfo(name,
+                    /* multithread */ true, /* nothrow */ false,
+                    /* narrow */ false, /* catchException */ true);
+            final AnnotatableEntity entity = new AnnotatableEntity(m, info);
+
             if (m instanceof Constructor) {
                 generateConstructor(entity);
             } else if (m instanceof Method) {
                 generateMethod(entity);
             } else if (m instanceof Field) {
                 generateField(entity);
             } else {
-                throw new IllegalArgumentException("expected member to be Constructor, Method, or Field");
-            }
-        }
-    }
-
-    /**
-     * Writes the appropriate header and startup code to ensure the existence of a reference to the
-     * class specified. If this is already done, does nothing.
-     *
-     * @param aClass The target class.
-     */
-    private void ensureClassHeaderAndStartup(Class<?> aClass) {
-        String className = aClass.getCanonicalName();
-        if (seenClasses.contains(className)) {
-            return;
-        }
-
-        zeroingCode.append("jclass ")
-                   .append(mCClassName)
-                   .append("::")
-                   .append(Utils.getClassReferenceName(aClass))
-                   .append(" = 0;\n");
-
-        // Add a field to hold the reference...
-        headerProtected.append("\n    static jclass ")
-                       .append(Utils.getClassReferenceName(aClass))
-                       .append(";\n");
-
-        // Add startup code to populate it..
-        wrapperStartupCode.append(Utils.getStartupLineForClass(aClass));
-
-        seenClasses.add(className);
-    }
-
-    /**
-     * Writes code for getting the JNIEnv instance.
-     */
-    private void writeFunctionStartupBoilerPlate(String methodSignature, boolean aIsThreaded) {
-        // The start-of-function boilerplate. Does the bridge exist? Does the env exist? etc.
-        wrapperMethodBodies.append('\n')
-                           .append(methodSignature)
-                           .append(" {\n");
-
-        wrapperMethodBodies.append("    JNIEnv *env = ");
-        if (!aIsThreaded) {
-            wrapperMethodBodies.append("AndroidBridge::GetJNIEnv();\n");
-        } else {
-            wrapperMethodBodies.append("GetJNIForThread();\n");
-        }
-    }
-
-    /**
-     * Write out the appropriate JNI frame pushing boilerplate for a call to the member provided (
-     * which must be a constructor or method).
-     *
-     * @param aMethod A constructor/method being wrapped.
-     * @param aIsObjectReturningMethod Does the method being wrapped return an object?
-     */
-    private void writeFramePushBoilerplate(Member aMethod,
-            boolean aIsObjectReturningMethod, boolean aNoThrow) {
-        if (aMethod instanceof Field) {
-            throw new IllegalArgumentException("Tried to push frame for a FIELD?!");
-        }
-
-        Method m;
-        Constructor<?> c;
-
-        Class<?> returnType;
-
-        int localReferencesNeeded;
-        if (aMethod instanceof Method) {
-            m = (Method) aMethod;
-            returnType = m.getReturnType();
-            localReferencesNeeded = Utils.enumerateReferenceArguments(m.getParameterTypes());
-        } else {
-            c = (Constructor<?>) aMethod;
-            returnType = Void.class;
-            localReferencesNeeded = Utils.enumerateReferenceArguments(c.getParameterTypes());
-        }
-
-        // Determine the number of local refs required for our local frame..
-        // AutoLocalJNIFrame is not applicable here due to it's inability to handle return values.
-        if (aIsObjectReturningMethod) {
-            localReferencesNeeded++;
-        }
-        wrapperMethodBodies.append(
-                "    if (env->PushLocalFrame(").append(localReferencesNeeded).append(") != 0) {\n");
-        if (!aNoThrow) {
-            wrapperMethodBodies.append(
-                "        AndroidBridge::HandleUncaughtException(env);\n" +
-                "        MOZ_CRASH(\"Exception should have caused crash.\");\n");
-        } else {
-            wrapperMethodBodies.append(
-                "        return").append(Utils.getFailureReturnForType(returnType)).append(";\n");
-        }
-        wrapperMethodBodies.append(
-                "    }\n\n");
-    }
-
-    private StringBuilder getArgumentMarshalling(Class<?>[] argumentTypes) {
-        StringBuilder argumentContent = new StringBuilder();
-
-        // If we have >2 arguments, use the jvalue[] calling approach.
-        argumentContent.append(", ");
-        if (argumentTypes.length > 2) {
-            wrapperMethodBodies.append("    jvalue args[").append(argumentTypes.length).append("];\n");
-            for (int aT = 0; aT < argumentTypes.length; aT++) {
-                wrapperMethodBodies.append("    args[").append(aT).append("].")
-                                   .append(Utils.getArrayArgumentMashallingLine(argumentTypes[aT], "a" + aT));
-            }
-
-            // The only argument is the array of arguments.
-            argumentContent.append("args");
-            wrapperMethodBodies.append('\n');
-        } else {
-            // Otherwise, use the vanilla calling approach.
-            boolean needsNewline = false;
-            for (int aT = 0; aT < argumentTypes.length; aT++) {
-                // If the argument is a string-esque type, create a jstring from it, otherwise
-                // it can be passed directly.
-                if (Utils.isCharSequence(argumentTypes[aT])) {
-                    wrapperMethodBodies.append("    jstring j").append(aT).append(" = AndroidBridge::NewJavaString(env, a").append(aT).append(");\n");
-                    needsNewline = true;
-                    // Ensure we refer to the newly constructed Java string - not to the original
-                    // parameter to the wrapper function.
-                    argumentContent.append('j').append(aT);
-                } else {
-                    argumentContent.append('a').append(aT);
-                }
-                if (aT != argumentTypes.length - 1) {
-                    argumentContent.append(", ");
-                }
-            }
-            if (needsNewline) {
-                wrapperMethodBodies.append('\n');
+                throw new IllegalArgumentException(
+                        "expected member to be Constructor, Method, or Field");
             }
         }
-
-        return argumentContent;
-    }
-
-    private void writeCatchException() {
-        wrapperMethodBodies.append(
-            "    if (env->ExceptionCheck()) {\n" +
-            "        env->ExceptionClear();\n" +
-            "        if (aResult) {\n" +
-            "            *aResult = NS_ERROR_FAILURE;\n" +
-            "        }\n" +
-            "    } else if (aResult) {\n" +
-            "        *aResult = NS_OK;\n" +
-            "    }\n\n");
-    }
-
-    private void writeCtorBody(String implementationSignature, Constructor<?> theCtor,
-            boolean aIsThreaded, boolean aNoThrow, boolean aCatchException) {
-        Class<?>[] argumentTypes = theCtor.getParameterTypes();
-
-        writeFunctionStartupBoilerPlate(implementationSignature, aIsThreaded);
-
-        writeFramePushBoilerplate(theCtor, false, aNoThrow);
-
-        if (mLazyInit) {
-            writeMemberInit(theCtor, wrapperMethodBodies);
-        }
-
-        // Marshall arguments for this constructor, if any...
-        boolean hasArguments = argumentTypes.length != 0;
-
-        StringBuilder argumentContent = new StringBuilder();
-        if (hasArguments) {
-            argumentContent = getArgumentMarshalling(argumentTypes);
-        }
-
-        // The call into Java
-        wrapperMethodBodies.append("    Init(env->NewObject");
-        if (argumentTypes.length > 2) {
-            wrapperMethodBodies.append('A');
-        }
-
-        wrapperMethodBodies.append('(');
-
-
-        // Call takes class id, method id of constructor method, then arguments.
-        wrapperMethodBodies.append(Utils.getClassReferenceName(mClassToWrap)).append(", ");
-
-        wrapperMethodBodies.append(mMembersToIds.get(theCtor))
-        // Tack on the arguments, if any..
-                           .append(argumentContent)
-                           .append("), env);\n");
-
-        // Check for exception and set aResult
-        if (aCatchException) {
-            writeCatchException();
-        }
-
-        wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n}\n");
-    }
-
-    /**
-     * Generates the method body of the C++ wrapper function for the Java method indicated.
-     *
-     * @param methodSignature The previously-generated C++ method signature for the method to be
-     *                        generated.
-     * @param aMethod         The Java method to be wrapped by the C++ method being generated.
-     * @param aClass          The Java class to which the method belongs.
-     */
-    private void writeMethodBody(String methodSignature, Method aMethod,
-                                 Class<?> aClass, boolean aIsMultithreaded,
-                                 boolean aNoThrow, boolean aNarrowChars,
-                                 boolean aCatchException) {
-        Class<?>[] argumentTypes = aMethod.getParameterTypes();
-        Class<?> returnType = aMethod.getReturnType();
-
-        writeFunctionStartupBoilerPlate(methodSignature, aIsMultithreaded);
-
-        boolean isObjectReturningMethod = !returnType.getCanonicalName().equals("void") && Utils.isObjectType(returnType);
-
-        writeFramePushBoilerplate(aMethod, isObjectReturningMethod, aNoThrow);
-
-        if (mLazyInit) {
-            writeMemberInit(aMethod, wrapperMethodBodies);
-        }
-
-        // Marshall arguments, if we have any.
-        boolean hasArguments = argumentTypes.length != 0;
-
-        // We buffer the arguments to the call separately to avoid needing to repeatedly iterate the
-        // argument list while building this line. In the coming code block, we simultaneously
-        // construct any argument marshalling code (Creation of jstrings, placement of arguments
-        // into an argument array, etc. and the actual argument list passed to the function (in
-        // argumentContent).
-        StringBuilder argumentContent = new StringBuilder();
-        if (hasArguments) {
-            argumentContent = getArgumentMarshalling(argumentTypes);
-        }
-
-        // Allocate a temporary variable to hold the return type from Java.
-        wrapperMethodBodies.append("    ");
-        if (!returnType.getCanonicalName().equals("void")) {
-            if (isObjectReturningMethod) {
-                wrapperMethodBodies.append("jobject");
-            } else {
-                wrapperMethodBodies.append(Utils.getCReturnType(returnType, aNarrowChars));
-            }
-            wrapperMethodBodies.append(" temp = ");
-        }
-
-        boolean isStaticJavaMethod = Utils.isMemberStatic(aMethod);
-
-        // The call into Java
-        wrapperMethodBodies.append("env->")
-                           .append(Utils.getCallPrefix(returnType, isStaticJavaMethod));
-        if (argumentTypes.length > 2) {
-            wrapperMethodBodies.append('A');
-        }
-
-        wrapperMethodBodies.append('(');
-        // If the underlying Java method is nonstatic, we provide the target object to the JNI.
-        if (!isStaticJavaMethod) {
-            wrapperMethodBodies.append("wrapped_obj, ");
-        } else {
-            // If this is a static underlying Java method, we need to use the class reference in our
-            // call.
-            wrapperMethodBodies.append(Utils.getClassReferenceName(aClass)).append(", ");
-        }
-
-        wrapperMethodBodies.append(mMembersToIds.get(aMethod));
-
-        // Tack on the arguments, if any..
-        wrapperMethodBodies.append(argumentContent)
-                           .append(");\n");
-
-        // Check for exception and crash if any...
-        if (!aNoThrow) {
-            wrapperMethodBodies.append("    AndroidBridge::HandleUncaughtException(env);\n");
-        }
-
-        // Check for exception and set aResult
-        if (aCatchException) {
-            writeCatchException();
-        }
-
-        // If we're returning an object, pop the callee's stack frame extracting our ref as the return
-        // value.
-        if (isObjectReturningMethod) {
-            wrapperMethodBodies.append("    ")
-                               .append(Utils.getCReturnType(returnType, aNarrowChars))
-                               .append(" ret = static_cast<").append(Utils.getCReturnType(returnType, aNarrowChars)).append(">(env->PopLocalFrame(temp));\n" +
-                                       "    return ret;\n");
-        } else if (!returnType.getCanonicalName().equals("void")) {
-            // If we're a primitive-returning function, just return the directly-obtained primative
-            // from the call to Java.
-            wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n" +
-                                       "    return temp;\n");
-        } else {
-            // If we don't return anything, just pop the stack frame and move on with life.
-            wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n");
-        }
-        wrapperMethodBodies.append("}\n");
-    }
-
-    /**
-     * Generates the code to get the id of the given member on startup or in the member body if lazy init
-     * is requested.
-     *
-     * @param aMember         The Java member being wrapped.
-     */
-    private void writeMemberInit(Member aMember, StringBuilder aOutput) {
-        if (mLazyInit) {
-            aOutput.append("    if (!" + mMembersToIds.get(aMember) + ") {\n    ");
-        }
-
-        aOutput.append("    " + mMembersToIds.get(aMember)).append(" = AndroidBridge::Get");
-        if (Utils.isMemberStatic(aMember)) {
-            aOutput.append("Static");
-        }
-
-        boolean isField = aMember instanceof Field;
-        if (isField) {
-            aOutput.append("FieldID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \"");
-        } else {
-            aOutput.append("MethodID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \"");
-        }
-
-        if (aMember instanceof Constructor) {
-            aOutput.append("<init>");
-        } else {
-            aOutput.append(aMember.getName());
-        }
-
-        aOutput.append("\", \"")
-                          .append(Utils.getTypeSignatureStringForMember(aMember))
-                          .append("\");\n");
-
-        if (mLazyInit) {
-            aOutput.append("    }\n\n");
-        }
-    }
-
-    private void writeZeroingFor(Member aMember, final String aMemberName) {
-        if (aMember instanceof Field) {
-            zeroingCode.append("jfieldID ");
-        } else {
-            zeroingCode.append("jmethodID ");
-        }
-        zeroingCode.append(mCClassName)
-                   .append("::")
-                   .append(aMemberName)
-                   .append(" = 0;\n");
-    }
-
-    /**
-     * Write the field declaration for the C++ id field of the given member.
-     *
-     * @param aMember Member for which an id field needs to be generated.
-     */
-    private void writeMemberIdField(Member aMember, final String aCMethodName) {
-        String memberName = 'j'+ aCMethodName;
-
-        if (aMember instanceof Field) {
-            headerProtected.append("    static jfieldID ");
-        } else {
-            headerProtected.append("    static jmethodID ");
-        }
-
-        while(mTakenMemberNames.contains(memberName)) {
-            memberName = 'j' + aCMethodName + mNameMunger;
-            mNameMunger++;
-        }
-
-        writeZeroingFor(aMember, memberName);
-        mMembersToIds.put(aMember, memberName);
-        mTakenMemberNames.add(memberName);
-
-        headerProtected.append(memberName)
-                       .append(";\n");
-    }
-
-    /**
-     * Helper function to add a provided method signature to the public section of the generated header.
-     *
-     * @param aSignature The header to add.
-     */
-    private void writeSignatureToHeader(String aSignature) {
-        headerPublic.append("    ")
-                    .append(aSignature)
-                    .append(";\n");
     }
 
     /**
      * Get the finalised bytes to go into the generated wrappers file.
      *
      * @return The bytes to be written to the wrappers file.
      */
     public String getWrapperFileContents() {
-        wrapperStartupCode.append("}\n");
-        zeroingCode.append(wrapperStartupCode)
-                   .append(wrapperMethodBodies);
-        wrapperMethodBodies.setLength(0);
-        wrapperStartupCode.setLength(0);
-        return zeroingCode.toString();
+        return cpp.toString();
     }
 
     /**
      * Get the finalised bytes to go into the generated header file.
      *
      * @return The bytes to be written to the header file.
      */
     public String getHeaderFileContents() {
-        if (!mHasEncounteredDefaultConstructor) {
-            headerPublic.append("    ").append(mCClassName).append("() : AutoGlobalWrappedJavaObject() {};\n");
-        }
-        headerProtected.append("};\n\n");
-        headerPublic.append(headerProtected);
-        headerProtected.setLength(0);
-        return headerPublic.toString();
+        header.append(
+                "};\n" +
+                "\n");
+        return header.toString();
     }
 }
--- a/build/annotationProcessors/SDKProcessor.java
+++ b/build/annotationProcessors/SDKProcessor.java
@@ -31,19 +31,21 @@ import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 
 public class SDKProcessor {
     public static final String GENERATED_COMMENT =
             "// GENERATED CODE\n" +
-            "// Generated by the Java program at /build/annotationProcessors at compile time from\n" +
-            "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" +
-            "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n";
+            "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
+            "// from annotations on Java methods. To update, change the annotations on the\n" +
+            "// corresponding Javamethods and rerun the build. Manually updating this file\n" +
+            "// will cause your build to fail.\n" +
+            "\n";
 
     private static ApiLookup sApiLookup;
     private static int sMaxSdkVersion;
 
     public static void main(String[] args) throws Exception {
         // We expect a list of jars on the commandline. If missing, whinge about it.
         if (args.length < 5) {
             System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version");
@@ -63,74 +65,65 @@ public class SDKProcessor {
 
         // Start the clock!
         long s = System.currentTimeMillis();
 
         // Get an iterator over the classes in the jar files given...
         // Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
 
         StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
-        headerFile.append("#ifndef " + generatedFilePrefix + "_h__\n" +
-                          "#define " + generatedFilePrefix + "_h__\n" +
-                          "#include \"nsXPCOMStrings.h\"\n" +
-                          "#include \"AndroidJavaWrappers.h\"\n" +
-                          "\n" +
-                          "namespace mozilla {\n" +
-                          "namespace widget {\n" +
-                          "namespace android {\n" +
-                          "namespace sdk {\n" +
-                          "void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv);\n\n");
+        headerFile.append(
+                "#ifndef " + generatedFilePrefix + "_h__\n" +
+                "#define " + generatedFilePrefix + "_h__\n" +
+                "\n" +
+                "#include \"mozilla/jni/Refs.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "namespace sdk {\n" +
+                "\n");
 
         StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
-        implementationFile.append("#include \"" + generatedFilePrefix + ".h\"\n" +
-                                  "#include \"AndroidBridgeUtilities.h\"\n" +
-                                  "#include \"nsXPCOMStrings.h\"\n" +
-                                  "#include \"AndroidBridge.h\"\n" +
-                                  "\n" +
-                                  "namespace mozilla {\n" +
-                                  "namespace widget {\n" +
-                                  "namespace android {\n" +
-                                  "namespace sdk {\n");
+        implementationFile.append(
+                "#include \"" + generatedFilePrefix + ".h\"\n" +
+                "#include \"mozilla/jni/Accessors.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "namespace sdk {\n" +
+                "\n");
 
         // Used to track the calls to the various class-specific initialisation functions.
-        StringBuilder stubInitializer = new StringBuilder();
-        stubInitializer.append("void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv) {\n");
-
         ClassLoader loader = null;
         try {
             loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) },
                                                 SDKProcessor.class.getClassLoader());
         } catch (Exception e) {
-            System.out.println(e);
+            throw new RuntimeException(e.toString());
         }
 
         for (Iterator<String> i = classes.iterator(); i.hasNext(); ) {
             String className = i.next();
             System.out.println("Looking up: " + className);
 
             generateClass(Class.forName(className, true, loader),
-                          stubInitializer,
                           implementationFile,
                           headerFile);
         }
 
-        implementationFile.append('\n');
-        stubInitializer.append("}");
-        implementationFile.append(stubInitializer);
+        implementationFile.append(
+                "} /* sdk */\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n");
 
-        implementationFile.append("\n} /* sdk */\n" +
-                                    "} /* android */\n" +
-                                    "} /* widget */\n" +
-                                    "} /* mozilla */\n");
-
-        headerFile.append("\n} /* sdk */\n" +
-                            "} /* android */\n" +
-                            "} /* widget */\n" +
-                            "} /* mozilla */\n" +
-                            "#endif\n");
+        headerFile.append(
+                "} /* sdk */\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n" +
+                "#endif\n");
 
         writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
         long e = System.currentTimeMillis();
         System.out.println("SDK processing complete in " + (e - s) + "ms");
     }
 
     private static Member[] sortAndFilterMembers(Member[] members) {
         Arrays.sort(members, new Comparator<Member>() {
@@ -140,22 +133,23 @@ public class SDKProcessor {
             }
         });
 
         ArrayList<Member> list = new ArrayList<>();
         for (Member m : members) {
             int version = 0;
 
             if (m instanceof Method || m instanceof Constructor) {
-                version = sApiLookup.getCallVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()),
-                                                    m.getName(),
-                                                    Utils.getTypeSignatureStringForMember(m));
+                version = sApiLookup.getCallVersion(
+                        Utils.getClassDescriptor(m.getDeclaringClass()),
+                        m.getName(),
+                        Utils.getSignature(m));
             } else if (m instanceof Field) {
-                version = sApiLookup.getFieldVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()),
-                                                     m.getName());
+                version = sApiLookup.getFieldVersion(
+                        Utils.getClassDescriptor(m.getDeclaringClass()), m.getName());
             } else {
                 throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
             }
 
             if (version > sMaxSdkVersion) {
                 System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() +
                     ", version " + version + " > " + sMaxSdkVersion);
                 continue;
@@ -163,23 +157,21 @@ public class SDKProcessor {
 
             list.add(m);
         }
 
         return list.toArray(new Member[list.size()]);
     }
 
     private static void generateClass(Class<?> clazz,
-                                      StringBuilder stubInitializer,
                                       StringBuilder implementationFile,
                                       StringBuilder headerFile) {
         String generatedName = clazz.getSimpleName();
 
-        CodeGenerator generator = new CodeGenerator(clazz, generatedName, true);
-        stubInitializer.append("    ").append(generatedName).append("::InitStubs(jEnv);\n");
+        CodeGenerator generator = new CodeGenerator(new ClassWithOptions(clazz, generatedName));
 
         generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredConstructors()));
         generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredMethods()));
         generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredFields()));
 
         headerFile.append(generator.getHeaderFileContents());
         implementationFile.append(generator.getWrapperFileContents());
     }
--- a/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
+++ b/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
@@ -52,26 +52,26 @@ public class AlphabeticAnnotatableEntity
         String rName = aRhs.getName();
 
         int ret = lName.compareTo(rName);
         if (ret != 0) {
             return ret;
         }
 
         // The names were the same, so we need to compare signatures to find their uniqueness..
-        lName = Utils.getTypeSignatureStringForMethod(aLhs);
-        rName = Utils.getTypeSignatureStringForMethod(aRhs);
+        lName = Utils.getSignature(aLhs);
+        rName = Utils.getSignature(aRhs);
 
         return lName.compareTo(rName);
     }
 
     private static int compare(Constructor<?> aLhs, Constructor<?> aRhs) {
         // The names will be the same, so we need to compare signatures to find their uniqueness..
-        String lName = Utils.getTypeSignatureString(aLhs);
-        String rName = Utils.getTypeSignatureString(aRhs);
+        String lName = Utils.getSignature(aLhs);
+        String rName = Utils.getSignature(aRhs);
 
         return lName.compareTo(rName);
     }
 
     private static int compare(Field aLhs, Field aRhs) {
         // Compare field names..
         String lName = aLhs.getName();
         String rName = aRhs.getName();
--- a/build/annotationProcessors/utils/GeneratableElementIterator.java
+++ b/build/annotationProcessors/utils/GeneratableElementIterator.java
@@ -114,32 +114,35 @@ public class GeneratableElementIterator 
                     } catch (InvocationTargetException e) {
                         System.err.println("InvocationTargetException reading fields on WrapElementForJNI annotation. This really shouldn't happen.");
                         e.printStackTrace(System.err);
                         System.exit(5);
                     }
 
                     // If the method name was not explicitly given in the annotation generate one...
                     if (stubName.isEmpty()) {
-                        String aMethodName = candidateElement.getName();
-                        stubName = aMethodName.substring(0, 1).toUpperCase() + aMethodName.substring(1);
+                        stubName = Utils.getNativeName(candidateElement);
                     }
 
                     AnnotationInfo annotationInfo = new AnnotationInfo(
                         stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
                     mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
                     return;
                 }
             }
 
-            // If no annotation found, we might be expected to generate anyway using default arguments,
-            // thanks to the "Generate everything" annotation.
+            // If no annotation found, we might be expected to generate anyway
+            // using default arguments, thanks to the "Generate everything" annotation.
             if (mIterateEveryEntry) {
                 AnnotationInfo annotationInfo = new AnnotationInfo(
-                    candidateElement.getName(), false, false, false, false);
+                    Utils.getNativeName(candidateElement),
+                    /* multithreaded */ true,
+                    /* noThrow */ false,
+                    /* narrowChars */ false,
+                    /* catchException */ false);
                 mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
                 return;
             }
         }
         mNextReturnValue = null;
     }
 
     @Override
--- a/build/annotationProcessors/utils/Utils.java
+++ b/build/annotationProcessors/utils/Utils.java
@@ -1,664 +1,247 @@
 /* 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.annotationProcessors.utils;
 
-import java.lang.annotation.Annotation;
+import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
+
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.HashMap;
 
 /**
  * A collection of utility methods used by CodeGenerator. Largely used for translating types.
  */
 public class Utils {
 
     // A collection of lookup tables to simplify the functions to follow...
-    private static final HashMap<String, String> sBasicCTypes = new HashMap<String, String>();
-
-    static {
-        sBasicCTypes.put("void", "void");
-        sBasicCTypes.put("int", "int32_t");
-        sBasicCTypes.put("boolean", "bool");
-        sBasicCTypes.put("long", "int64_t");
-        sBasicCTypes.put("double", "jdouble");
-        sBasicCTypes.put("float", "jfloat");
-        sBasicCTypes.put("char", "uint16_t");
-        sBasicCTypes.put("byte", "int8_t");
-        sBasicCTypes.put("short", "int16_t");
-    }
-
-    private static final HashMap<String, String> sArrayCTypes = new HashMap<String, String>();
+    private static final HashMap<String, String> NATIVE_TYPES = new HashMap<String, String>();
 
     static {
-        sArrayCTypes.put("int", "jintArray");
-        sArrayCTypes.put("boolean", "jbooleanArray");
-        sArrayCTypes.put("long", "jlongArray");
-        sArrayCTypes.put("double", "jdoubleArray");
-        sArrayCTypes.put("float", "jfloatArray");
-        sArrayCTypes.put("char", "jcharArray");
-        sArrayCTypes.put("byte", "jbyteArray");
-        sArrayCTypes.put("short", "jshortArray");
-    }
-
-    private static final HashMap<String, String> sStaticCallTypes = new HashMap<String, String>();
-
-    static {
-        sStaticCallTypes.put("void", "CallStaticVoidMethod");
-        sStaticCallTypes.put("int", "CallStaticIntMethod");
-        sStaticCallTypes.put("boolean", "CallStaticBooleanMethod");
-        sStaticCallTypes.put("long", "CallStaticLongMethod");
-        sStaticCallTypes.put("double", "CallStaticDoubleMethod");
-        sStaticCallTypes.put("float", "CallStaticFloatMethod");
-        sStaticCallTypes.put("char", "CallStaticCharMethod");
-        sStaticCallTypes.put("byte", "CallStaticByteMethod");
-        sStaticCallTypes.put("short", "CallStaticShortMethod");
-    }
-
-    private static final HashMap<String, String> sInstanceCallTypes = new HashMap<String, String>();
-
-    static {
-        sInstanceCallTypes.put("void", "CallVoidMethod");
-        sInstanceCallTypes.put("int", "CallIntMethod");
-        sInstanceCallTypes.put("boolean", "CallBooleanMethod");
-        sInstanceCallTypes.put("long", "CallLongMethod");
-        sInstanceCallTypes.put("double", "CallDoubleMethod");
-        sInstanceCallTypes.put("float", "CallFloatMethod");
-        sInstanceCallTypes.put("char", "CallCharMethod");
-        sInstanceCallTypes.put("byte", "CallByteMethod");
-        sInstanceCallTypes.put("short", "CallShortMethod");
+        NATIVE_TYPES.put("void", "void");
+        NATIVE_TYPES.put("boolean", "bool");
+        NATIVE_TYPES.put("byte", "int8_t");
+        NATIVE_TYPES.put("char", "char16_t");
+        NATIVE_TYPES.put("short", "int16_t");
+        NATIVE_TYPES.put("int", "int32_t");
+        NATIVE_TYPES.put("long", "int64_t");
+        NATIVE_TYPES.put("float", "float");
+        NATIVE_TYPES.put("double", "double");
     }
 
-    private static final HashMap<String, String> sFieldTypes = new HashMap<String, String>();
+    private static final HashMap<String, String> NATIVE_ARRAY_TYPES = new HashMap<String, String>();
 
     static {
-        sFieldTypes.put("int", "Int");
-        sFieldTypes.put("boolean", "Boolean");
-        sFieldTypes.put("long", "Long");
-        sFieldTypes.put("double", "Double");
-        sFieldTypes.put("float", "Float");
-        sFieldTypes.put("char", "Char");
-        sFieldTypes.put("byte", "Byte");
-        sFieldTypes.put("short", "Short");
-    }
-
-    private static final HashMap<String, String> sFailureReturns = new HashMap<String, String>();
-
-    static {
-        sFailureReturns.put("java.lang.Void", "");
-        sFailureReturns.put("void", "");
-        sFailureReturns.put("int", " 0");
-        sFailureReturns.put("boolean", " false");
-        sFailureReturns.put("long", " 0");
-        sFailureReturns.put("double", " 0.0");
-        sFailureReturns.put("float", " 0.0");
-        sFailureReturns.put("char", " 0");
-        sFailureReturns.put("byte", " 0");
-        sFailureReturns.put("short", " 0");
+        NATIVE_ARRAY_TYPES.put("boolean", "mozilla::jni::BooleanArray");
+        NATIVE_ARRAY_TYPES.put("byte", "mozilla::jni::ByteArray");
+        NATIVE_ARRAY_TYPES.put("char", "mozilla::jni::CharArray");
+        NATIVE_ARRAY_TYPES.put("short", "mozilla::jni::ShortArray");
+        NATIVE_ARRAY_TYPES.put("int", "mozilla::jni::IntArray");
+        NATIVE_ARRAY_TYPES.put("long", "mozilla::jni::LongArray");
+        NATIVE_ARRAY_TYPES.put("float", "mozilla::jni::FloatArray");
+        NATIVE_ARRAY_TYPES.put("double", "mozilla::jni::DoubleArray");
     }
 
-    private static final HashMap<String, String> sCanonicalSignatureParts = new HashMap<String, String>();
+    private static final HashMap<String, String> CLASS_DESCRIPTORS = new HashMap<String, String>();
 
     static {
-        sCanonicalSignatureParts.put("java/lang/Void", "V");
-        sCanonicalSignatureParts.put("void", "V");
-        sCanonicalSignatureParts.put("int", "I");
-        sCanonicalSignatureParts.put("boolean", "Z");
-        sCanonicalSignatureParts.put("long", "J");
-        sCanonicalSignatureParts.put("double", "D");
-        sCanonicalSignatureParts.put("float", "F");
-        sCanonicalSignatureParts.put("char", "C");
-        sCanonicalSignatureParts.put("byte", "B");
-        sCanonicalSignatureParts.put("short", "S");
-    }
-
-
-    private static final HashMap<String, String> sDefaultParameterValues = new HashMap<String, String>();
-
-    static {
-        sDefaultParameterValues.put("int", "0");
-        sDefaultParameterValues.put("boolean", "false");
-        sDefaultParameterValues.put("long", "0");
-        sDefaultParameterValues.put("double", "0");
-        sDefaultParameterValues.put("float", "0.0");
-        sDefaultParameterValues.put("char", "0");
-        sDefaultParameterValues.put("byte", "0");
-        sDefaultParameterValues.put("short", "0");
+        CLASS_DESCRIPTORS.put("void", "V");
+        CLASS_DESCRIPTORS.put("boolean", "Z");
+        CLASS_DESCRIPTORS.put("byte", "B");
+        CLASS_DESCRIPTORS.put("char", "C");
+        CLASS_DESCRIPTORS.put("short", "S");
+        CLASS_DESCRIPTORS.put("int", "I");
+        CLASS_DESCRIPTORS.put("long", "J");
+        CLASS_DESCRIPTORS.put("float", "F");
+        CLASS_DESCRIPTORS.put("double", "D");
     }
 
     /**
-     * Get the C type corresponding to the provided type parameter. Used for generating argument
-     * types for the wrapper method.
+     * Get the C++ type corresponding to the provided type parameter.
      *
      * @param type Class to determine the corresponding JNI type for.
-     * @return true if the type an object type, false otherwise.
+     * @return C++ type as a String
      */
-    public static String getCParameterType(Class<?> type, boolean aNarrowChars) {
-        String name = type.getCanonicalName();
-        if (sBasicCTypes.containsKey(name)) {
-            return sBasicCTypes.get(name);
-        }
-        // Are we dealing with an array type?
-        int len = name.length();
-        if (name.endsWith("[]")) {
-            // Determine if it is a 2D array - these map to jobjectArrays
-            name = name.substring(0, len - 2);
-            if (name.endsWith("[]")) {
-                return "jobjectArray";
-            } else {
-                // Which flavour of Array is it?
-                if (sArrayCTypes.containsKey(name)) {
-                    return sArrayCTypes.get(name);
-                }
-                return "jobjectArray";
-            }
-        }
-        // Not an array type, check the remaining possibilities before we fall back to jobject
+    public static String getNativeParameterType(Class<?> type, AnnotationInfo info) {
+        final String name = type.getName().replace('.', '/');
 
-        // Check for CharSequences (Strings and things that are string-like)
-        if (isCharSequence(type)) {
-            if (aNarrowChars) {
-                return "const nsACString&";
-            }
-            return "const nsAString&";
+        if (NATIVE_TYPES.containsKey(name)) {
+            return NATIVE_TYPES.get(name);
         }
 
-        if (name.equals("java.lang.Class")) {
+        if (type.isArray()) {
+            final String compName = type.getComponentType().getName();
+            if (NATIVE_ARRAY_TYPES.containsKey(compName)) {
+                return NATIVE_ARRAY_TYPES.get(compName) + "::Param";
+            }
+            return "mozilla::jni::ObjectArray::Param";
+        }
+
+        if (type == String.class || type == CharSequence.class) {
+            return "mozilla::jni::String::Param";
+        }
+
+        if (type == Class.class) {
             // You're doing reflection on Java objects from inside C, returning Class objects
             // to C, generating the corresponding code using this Java program. Really?!
-            return "jclass";
-        }
-        if (name.equals("java.lang.Throwable")) {
-            return "jthrowable";
-        }
-        return "jobject";
-    }
-
-    /**
-     * For a given Java type, get the corresponding C++ type if we're returning it from a function.
-     *
-     * @param type The Java return type.
-     * @return A string representation of the C++ return type.
-     */
-     public static String getCReturnType(Class<?> type, boolean aNarrowChars) {
-        if (type.getCanonicalName().equals("java.lang.Void")) {
-            return "void";
+            return "mozilla::jni::ClassObject::Param";
         }
-        String cParameterType = getCParameterType(type, aNarrowChars);
-        if (cParameterType.equals("const nsAString&") || cParameterType.equals("const nsACString&")) {
-            return "jstring";
-        } else {
-            return cParameterType;
-        }
-    }
 
-    /**
-     * Gets the type-specific part of the  JNI function to use to get or set a field of a given type.
-     *
-     * @param aFieldType The Java type of the field.
-     * @return A string representation of the JNI call function substring to use.
-     */
-    public static String getFieldType(Class<?> aFieldType) {
-        String name = aFieldType.getCanonicalName();
+        if (type == Throwable.class) {
+            return "mozilla::jni::Throwable::Param";
+        }
 
-        if (sFieldTypes.containsKey(name)) {
-            return sFieldTypes.get(name);
-        }
-        return "Object";
+        return "mozilla::jni::Object::Param";
     }
 
-    /**
-     * Gets the appropriate JNI call function to use to invoke a Java method with the given return
-     * type. This, plus a call postfix (Such as "A") forms a complete JNI call function name.
-     *
-     * @param aReturnType The Java return type of the method being generated.
-     * @param isStatic Boolean indicating if the underlying Java method is declared static.
-     * @return A string representation of the JNI call function prefix to use.
-     */
-    public static String getCallPrefix(Class<?> aReturnType, boolean isStatic) {
-        String name = aReturnType.getCanonicalName();
-        if (isStatic) {
-            if (sStaticCallTypes.containsKey(name)) {
-                return sStaticCallTypes.get(name);
-            }
-            return "CallStaticObjectMethod";
-        } else {
-            if (sInstanceCallTypes.containsKey(name)) {
-                return sInstanceCallTypes.get(name);
-            }
-            return "CallObjectMethod";
-        }
-    }
+    public static String getNativeReturnType(Class<?> type, AnnotationInfo info) {
+        final String name = type.getName().replace('.', '/');
 
-    /**
-     * On failure, the generated method returns a null-esque value. This helper method gets the
-     * appropriate failure return value for a given Java return type, plus a leading space.
-     *
-     * @param type Java return type of method being generated
-     * @return String representation of the failure return value to be used in the generated code.
-     */
-    public static String getFailureReturnForType(Class<?> type) {
-        String name = type.getCanonicalName();
-        if (sFailureReturns.containsKey(name)) {
-            return sFailureReturns.get(name);
+        if (NATIVE_TYPES.containsKey(name)) {
+            return NATIVE_TYPES.get(name);
         }
-        return " nullptr";
-    }
-
-    /**
-     * Helper method to get the type signature for methods, given argument and return type.
-     * Allows for the near-identical logic needed for constructors and methods to be shared.
-     * (Alas, constructor does not extend method)
-     *
-     * @param arguments Argument types of the underlying method.
-     * @param returnType Return type of the underlying method.
-     * @return The canonical Java type string for the method. eg. (IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;
-     */
-    private static String getTypeSignatureInternal(Class<?>[] arguments, Class<?> returnType) {
-        StringBuilder sb = new StringBuilder();
-        sb.append('(');
-
-        // For each argument, write its signature component to the buffer..
-        for (int i = 0; i < arguments.length; i++) {
-            writeTypeSignature(sb, arguments[i]);
-        }
-        sb.append(')');
 
-        // Write the return value's signature..
-        writeTypeSignature(sb, returnType);
-        return sb.toString();
-    }
-
-    /**
-     * Get the canonical JNI type signature for a Field.
-     *
-     * @param aField The field to generate a signature for.
-     * @return The canonical JNI type signature for this method.
-     */
-    protected static String getTypeSignatureStringForField(Field aField) {
-        StringBuilder sb = new StringBuilder();
-        writeTypeSignature(sb, aField.getType());
-        return sb.toString();
-    }
-
-    /**
-     * Get the canonical JNI type signature for a method.
-     *
-     * @param aMethod The method to generate a signature for.
-     * @return The canonical JNI type signature for this method.
-     */
-    protected static String getTypeSignatureStringForMethod(Method aMethod) {
-        Class<?>[] arguments = aMethod.getParameterTypes();
-        Class<?> returnType = aMethod.getReturnType();
-        return getTypeSignatureInternal(arguments, returnType);
-    }
-
-    /**
-     * Get the canonical JNI type signature for a Constructor.
-     *
-     * @param aConstructor The Constructor to generate a signature for.
-     * @return The canonical JNI type signature for this method.
-     */
-    protected static String getTypeSignatureStringForConstructor(Constructor<?> aConstructor) {
-        Class<?>[] arguments = aConstructor.getParameterTypes();
-        return getTypeSignatureInternal(arguments, Void.class);
-    }
-
-    public static String getTypeSignatureStringForMember(Member aMember) {
-        if (aMember instanceof Method) {
-            return getTypeSignatureStringForMethod((Method) aMember);
-        } else if (aMember instanceof Field) {
-            return getTypeSignatureStringForField((Field) aMember);
-        } else {
-            return getTypeSignatureStringForConstructor((Constructor<?>) aMember);
-        }
-    }
-
-    public static String getTypeSignatureStringForClass(Class<?> clazz) {
-        return clazz.getCanonicalName().replace('.', '/');
-    }
-
-    public static String getTypeSignatureString(Constructor<?> aConstructor) {
-        Class<?>[] arguments = aConstructor.getParameterTypes();
-        StringBuilder sb = new StringBuilder();
-        sb.append('(');
-
-        // For each argument, write its signature component to the buffer..
-        for (int i = 0; i < arguments.length; i++) {
-            writeTypeSignature(sb, arguments[i]);
+        if (type.isArray()) {
+            final String compName = type.getComponentType().getName();
+            if (NATIVE_ARRAY_TYPES.containsKey(compName)) {
+                return NATIVE_ARRAY_TYPES.get(compName) + "::LocalRef";
+            }
+            return "mozilla::jni::ObjectArray::LocalRef";
         }
 
-        // Constructors always return Void.
-        sb.append(")V");
-        return sb.toString();
+        if (type == String.class) {
+            return "mozilla::jni::String::LocalRef";
+        }
+
+        if (type == Class.class) {
+            // You're doing reflection on Java objects from inside C, returning Class objects
+            // to C, generating the corresponding code using this Java program. Really?!
+            return "mozilla::jni::ClassObject::LocalRef";
+        }
+
+        if (type == Throwable.class) {
+            return "mozilla::jni::Throwable::LocalRef";
+        }
+
+        return "mozilla::jni::Object::LocalRef";
     }
 
     /**
-     * Helper method used by getTypeSignatureStringForMethod to build the signature. Write the subsignature
-     * of a given type into the buffer.
+     * Get the JNI class descriptor corresponding to the provided type parameter.
      *
-     * @param sb The buffer to write into.
-     * @param c  The type of the element to write the subsignature of.
+     * @param type Class to determine the corresponding JNI descriptor for.
+     * @return Class descripor as a String
      */
-    private static void writeTypeSignature(StringBuilder sb, Class<?> c) {
-        String name = Utils.getTypeSignatureStringForClass(c);
+    public static String getClassDescriptor(Class<?> type) {
+        final String name = type.getName().replace('.', '/');
 
-        // Determine if this is an array type and, if so, peel away the array operators..
-        int len = name.length();
-        while (name.endsWith("[]")) {
-            sb.append('[');
-            name = name.substring(0, len - 2);
-            len = len - 2;
+        if (CLASS_DESCRIPTORS.containsKey(name)) {
+            return CLASS_DESCRIPTORS.get(name);
         }
 
-        if (c.isArray()) {
-            c = c.getComponentType();
-        }
-
-        Class<?> containerClass = c.getDeclaringClass();
-        if (containerClass != null) {
-            // Is an inner class. Add the $ symbol.
-            final int lastSlash = name.lastIndexOf('/');
-            name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
+        if (type.isArray()) {
+            // Array names are already in class descriptor form.
+            return name;
         }
 
-        // Look in the hashmap for the remainder...
-        if (sCanonicalSignatureParts.containsKey(name)) {
-            // It was a primitive type, so lookup was a success.
-            sb.append(sCanonicalSignatureParts.get(name));
-        } else {
-            // It was a reference type - generate.
-            sb.append('L');
-            sb.append(name);
-            sb.append(';');
-        }
+        return "L" + name + ';';
     }
 
     /**
-     * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
-     * generating header files and method bodies.
+     * Get the JNI signaure for a member.
      *
-     * @param aArgumentTypes Argument types of the Java method being wrapped.
-     * @param aReturnType Return type of the Java method being wrapped.
-     * @param aCMethodName Name of the method to generate in the C++ class.
-     * @param aCClassName Name of the C++ class into which the method is declared.
-     * @return The C++ method implementation signature for the method described.
+     * @param member Member to get the signature for.
+     * @return JNI signature as a string
      */
-    public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType,
-        String aCMethodName, String aCClassName, boolean aNarrowChars, boolean aCatchException) {
-        StringBuilder retBuffer = new StringBuilder();
-
-        retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
-        retBuffer.append(' ');
-        retBuffer.append(aCClassName);
-        retBuffer.append("::");
-        retBuffer.append(aCMethodName);
-        retBuffer.append('(');
-
-        // Write argument types...
-        for (int aT = 0; aT < aArgumentTypes.length; aT++) {
-            retBuffer.append(getCParameterType(aArgumentTypes[aT], aNarrowChars));
-            retBuffer.append(" a");
-            // We, imaginatively, call our arguments a1, a2, a3...
-            // The only way to preserve the names from Java would be to parse the
-            // Java source, which would be computationally hard.
-            retBuffer.append(aT);
-            if (aT != aArgumentTypes.length - 1) {
-                retBuffer.append(", ");
-            }
-        }
-
-        if (aCatchException) {
-            if (aArgumentTypes.length > 0) {
-                retBuffer.append(", ");
-            }
-            retBuffer.append("nsresult* aResult");
-        }
-
-        retBuffer.append(')');
-        return retBuffer.toString();
+    public static String getSignature(Member member) {
+        return member instanceof Field ?  getSignature((Field) member) :
+               member instanceof Method ? getSignature((Method) member) :
+                                          getSignature((Constructor<?>) member);
     }
 
     /**
-     * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
-     * generating header files and method bodies.
+     * Get the JNI signaure for a field.
      *
-     * @param aArgumentTypes Argument types of the Java method being wrapped.
-     * @param aArgumentAnnotations The annotations on the Java method arguments. Used to specify
-     *                             default values etc.
-     * @param aReturnType Return type of the Java method being wrapped.
-     * @param aCMethodName Name of the method to generate in the C++ class.
-     * @param aCClassName Name of the C++ class into which the method is declared.e
-     * @param aIsStaticStub true if the generated C++ method should be static, false otherwise.
-     * @return The generated C++ header method signature for the method described.
+     * @param member Field to get the signature for.
+     * @return JNI signature as a string
      */
-    public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType,
-        String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars, boolean aCatchException) {
-        StringBuilder retBuffer = new StringBuilder();
-
-        // Add the static keyword, if applicable.
-        if (aIsStaticStub) {
-            retBuffer.append("static ");
-        }
-
-        // Write return type..
-        retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
-        retBuffer.append(' ');
-        retBuffer.append(aCMethodName);
-        retBuffer.append('(');
+    public static String getSignature(Field member) {
+        return getClassDescriptor(member.getType());
+    }
 
-        // Write argument types...
-        for (int aT = 0; aT < aArgumentTypes.length; aT++) {
-            retBuffer.append(getCParameterType(aArgumentTypes[aT], aNarrowChars));
-            retBuffer.append(" a");
-            // We, imaginatively, call our arguments a1, a2, a3...
-            // The only way to preserve the names from Java would be to parse the
-            // Java source, which would be computationally hard.
-            retBuffer.append(aT);
-
-            // Append the default value, if there is one..
-            retBuffer.append(getDefaultValueString(aArgumentTypes[aT], aArgumentAnnotations[aT]));
-
-            if (aT != aArgumentTypes.length - 1) {
-                retBuffer.append(", ");
-            }
+    private static String getSignature(Class<?>[] args, Class<?> ret) {
+        final StringBuilder sig = new StringBuilder("(");
+        for (int i = 0; i < args.length; i++) {
+            sig.append(getClassDescriptor(args[i]));
         }
-
-        if (aCatchException) {
-            if (aArgumentTypes.length > 0) {
-                retBuffer.append(", ");
-            }
-            retBuffer.append("nsresult* aResult = nullptr");
-        }
-
-        retBuffer.append(')');
-        return retBuffer.toString();
+        return sig.append(')').append(getClassDescriptor(ret)).toString();
     }
 
     /**
-     * If the given Annotation[] contains an OptionalGeneratedParameter annotation then return a
-     * string assigning an argument of type aArgumentType to the default value for that type.
-     * Otherwise, return the empty string.
+     * Get the JNI signaure for a method.
      *
-     * @param aArgumentType        The type of the argument to consider.
-     * @param aArgumentAnnotations The annotations on the argument to consider.
-     * @return An appropriate string to append to the signature of this argument assigning it to a
-     *         default value (Or not, as applicable).
+     * @param member Method to get the signature for.
+     * @return JNI signature as a string
      */
-    public static String getDefaultValueString(Class<?> aArgumentType, Annotation[] aArgumentAnnotations) {
-        for (int i = 0; i < aArgumentAnnotations.length; i++) {
-            Class<? extends Annotation> annotationType = aArgumentAnnotations[i].annotationType();
-            final String annotationTypeName = annotationType.getName();
-            if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter")) {
-                return " = " + getDefaultParameterValueForType(aArgumentType);
-            }
-        }
-        return "";
+    public static String getSignature(Method member) {
+        return getSignature(member.getParameterTypes(), member.getReturnType());
     }
 
     /**
-     * Helper method to return an appropriate default parameter value for an argument of a given type.
-     * The lookup table contains values for primitive types and strings. All other object types default
-     * to null pointers.
+     * Get the JNI signaure for a constructor.
      *
-     * @param aArgumentType The parameter type for which a default value is desired.
-     * @return An appropriate string representation of the default value selected, for use in generated
-     *         C++ code.
+     * @param member Constructor to get the signature for.
+     * @return JNI signature as a string
      */
-    private static String getDefaultParameterValueForType(Class<?> aArgumentType) {
-        String typeName = aArgumentType.getCanonicalName();
-        if (sDefaultParameterValues.containsKey(typeName)) {
-            return sDefaultParameterValues.get(typeName);
-        } else if (isCharSequence(aArgumentType)) {
-            return "EmptyString()";
-        } else {
-            return "nullptr";
-        }
+    public static String getSignature(Constructor<?> member) {
+        return getSignature(member.getParameterTypes(), void.class);
     }
 
     /**
-     * Helper method that returns the number of reference types in the arguments of m.
+     * Get the C++ name for a member.
      *
-     * @param aArgs The method arguments to consider.
-     * @return How many of the arguments of m are nonprimitive.
+     * @param member Member to get the name for.
+     * @return JNI name as a string
      */
-    public static int enumerateReferenceArguments(Class<?>[] aArgs) {
-        int ret = 0;
-        for (int i = 0; i < aArgs.length; i++) {
-            String name = aArgs[i].getCanonicalName();
-            if (!sBasicCTypes.containsKey(name)) {
-                ret++;
-            }
-        }
-        return ret;
-    }
-
-    /**
-     * Helper method that returns true iff the given method has a string argument.
-     *
-     * @param m The method to consider.
-     * @return True if the given method has a string argument, false otherwise.
-     */
-    public static boolean hasStringArgument(Method m) {
-        Class<?>[] args = m.getParameterTypes();
-        for (int i = 0; i < args.length; i++) {
-            if (isCharSequence(args[i])) {
-                return true;
-            }
-        }
-        return false;
+    public static String getNativeName(Member member) {
+        final String name = getMemberName(member);
+        return name.substring(0, 1).toUpperCase() + name.substring(1);
     }
 
     /**
-     * Write the argument array assignment line for the given argument type. Does not support array
-     * types.
+     * Get the JNI name for a member.
      *
-     * @param type    Type of this argument according to the target Java method's signature.
-     * @param argName Wrapper function argument name corresponding to this argument.
+     * @param member Member to get the name for.
+     * @return JNI name as a string
      */
-    public static String getArrayArgumentMashallingLine(Class<?> type, String argName) {
-        StringBuilder sb = new StringBuilder();
-
-        String name = type.getCanonicalName();
-        if (sCanonicalSignatureParts.containsKey(name)) {
-            sb.append(sCanonicalSignatureParts.get(name).toLowerCase());
-            sb.append(" = ").append(argName).append(";\n");
-        } else {
-            if (isCharSequence(type)) {
-                sb.append("l = AndroidBridge::NewJavaString(env, ").append(argName).append(");\n");
-            } else {
-                sb.append("l = ").append(argName).append(";\n");
-            }
+    public static String getMemberName(Member member) {
+        if (member instanceof Constructor) {
+            return "<init>";
         }
-
-        return sb.toString();
-    }
-
-    /**
-     * Returns true if the type provided is an object type. Returns false otherwise
-     *
-     * @param aType The type to consider.
-     * @return true if the method provided is an object type, false otherwise.
-     */
-    public static boolean isObjectType(Class<?> aType) {
-        return !sBasicCTypes.containsKey(aType.getCanonicalName());
-    }
-
-    /**
-     * For a given Java class, get the name of the value in C++ which holds a reference to it.
-     *
-     * @param aClass Target Java class.
-     * @return The name of the C++ jclass entity referencing the given class.
-     */
-    public static String getClassReferenceName(Class<?> aClass) {
-        String className = aClass.getSimpleName();
-        return 'm' + className + "Class";
+        return member.getName();
     }
 
     /**
-     * Generate a line to get a global reference to the Java class given.
+     * Determine if a member is declared static.
      *
-     * @param aClass The target Java class.
-     * @return The generated code to populate the reference to the class.
+     * @param member The Member to check.
+     * @return true if the member is declared static, false otherwise.
      */
-    public static String getStartupLineForClass(Class<?> aClass) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("    ");
-        sb.append(getClassReferenceName(aClass));
-        sb.append(" = AndroidBridge::GetClassGlobalRef(env, \"");
-
-        String name = Utils.getTypeSignatureStringForClass(aClass);
-        Class<?> containerClass = aClass.getDeclaringClass();
-        if (containerClass != null) {
-            // Is an inner class. Add the $ symbol.
-            final int lastSlash = name.lastIndexOf('/');
-            name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
-        }
-
-        sb.append(name);
-        sb.append("\");\n");
-        return sb.toString();
+    public static boolean isStatic(final Member member) {
+        return Modifier.isStatic(member.getModifiers());
     }
 
     /**
-     * Helper method to determine if this object implements CharSequence
-     * @param aClass Class to check for CharSequence-esqueness
-     * @return True if the given class implements CharSequence, false otherwise.
+     * Determine if a member is declared final.
+     *
+     * @param member The Member to check.
+     * @return true if the member is declared final, false otherwise.
      */
-    public static boolean isCharSequence(Class<?> aClass) {
-        if (aClass.getCanonicalName().equals("java.lang.CharSequence")) {
-            return true;
-        }
-        Class<?>[] interfaces = aClass.getInterfaces();
-        for (Class<?> c : interfaces) {
-            if (c.getCanonicalName().equals("java.lang.CharSequence")) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Helper method to read the modifier bits of the given method to determine if it is static.
-     * @param aMember The Member to check.
-     * @return true of the method is declared static, false otherwise.
-     */
-    public static boolean isMemberStatic(Member aMember) {
-        int aMethodModifiers = aMember.getModifiers();
-        return Modifier.isStatic(aMethodModifiers);
-    }
-
-    /**
-     * Helper method to read the modifier bits of the given method to determine if it is static.
-     * @param aMember The Member to check.
-     * @return true of the method is declared static, false otherwise.
-     */
-    public static boolean isMemberFinal(Member aMember) {
-        int aMethodModifiers = aMember.getModifiers();
-        return Modifier.isFinal(aMethodModifiers);
+    public static boolean isFinal(final Member member) {
+        return Modifier.isFinal(member.getModifiers());
     }
 }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2488,17 +2488,17 @@ ContentParent::RecvGetIconForExtension(c
 bool
 ContentParent::RecvGetShowPasswordSetting(bool* showPassword)
 {
     // default behavior is to show the last password character
     *showPassword = true;
 #ifdef MOZ_WIDGET_ANDROID
     NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available");
 
-    *showPassword = mozilla::widget::android::GeckoAppShell::GetShowPasswordSetting();
+    *showPassword = mozilla::widget::GeckoAppShell::GetShowPasswordSetting();
 #endif
     return true;
 }
 
 bool
 ContentParent::RecvFirstIdle()
 {
     // When the ContentChild goes idle, it sends us a FirstIdle message
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -19,35 +19,35 @@
 #include "nsThreadUtils.h"
 #include "nsAutoPtr.h"
 
 #include <jni.h>
 #include <string.h>
 
 using namespace mozilla;
 using namespace mozilla::gl;
-using namespace mozilla::widget::android::sdk;
+using namespace mozilla::widget::sdk;
 
 namespace mozilla {
 
-static MediaCodec* CreateDecoder(JNIEnv* aEnv, const char* aMimeType)
+static MediaCodec::LocalRef CreateDecoder(const char* aMimeType)
 {
   if (!aMimeType) {
     return nullptr;
   }
 
-  jobject decoder = MediaCodec::CreateDecoderByType(nsCString(aMimeType));
-
-  return new MediaCodec(decoder, aEnv);
+  MediaCodec::LocalRef codec;
+  NS_ENSURE_SUCCESS(MediaCodec::CreateDecoderByType(aMimeType, &codec), nullptr);
+  return codec;
 }
 
 class VideoDataDecoder : public MediaCodecDataDecoder {
 public:
   VideoDataDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
-                   MediaFormat* aFormat, MediaDataDecoderCallback* aCallback,
+                   MediaFormat::Param aFormat, MediaDataDecoderCallback* aCallback,
                    layers::ImageContainer* aImageContainer)
     : MediaCodecDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mime_type, aFormat, aCallback)
     , mImageContainer(aImageContainer)
     , mConfig(aConfig)
   {
 
   }
 
@@ -103,17 +103,17 @@ public:
     EGLImage eglImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext,
                                                  LOCAL_EGL_GL_TEXTURE_2D_KHR,
                                                  (EGLClientBuffer)tex, attribs);
     mGLContext->fDeleteTextures(1, &tex);
 
     return eglImage;
   }
 
-  virtual nsresult PostOutput(BufferInfo* aInfo, MediaFormat* aFormat, Microseconds aDuration) MOZ_OVERRIDE {
+  virtual nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat, Microseconds aDuration) MOZ_OVERRIDE {
     VideoInfo videoInfo;
     videoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
 
     EGLImage eglImage = CopySurface();
     if (!eglImage) {
       return NS_ERROR_FAILURE;
     }
 
@@ -138,23 +138,33 @@ public:
     data.mSync = eglSync;
     data.mOwns = true;
     data.mSize = gfx::IntSize(mConfig.display_width, mConfig.display_height);
     data.mOriginPos = gl::OriginPos::BottomLeft;
 
     layers::EGLImageImage* typedImg = static_cast<layers::EGLImageImage*>(img.get());
     typedImg->SetData(data);
 
-    bool isSync = !!(MediaCodec::getBUFFER_FLAG_SYNC_FRAME() & aInfo->getFlags());
+    nsresult rv;
+    int32_t flags;
+    NS_ENSURE_SUCCESS(rv = aInfo->Flags(&flags), rv);
+
+    bool isSync = !!(flags & MediaCodec::BUFFER_FLAG_SYNC_FRAME);
 
-    nsRefPtr<VideoData> v = VideoData::CreateFromImage(videoInfo, mImageContainer, aInfo->getOffset(),
-                                                       aInfo->getPresentationTimeUs(),
+    int32_t offset;
+    NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv);
+
+    int64_t presentationTimeUs;
+    NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
+
+    nsRefPtr<VideoData> v = VideoData::CreateFromImage(videoInfo, mImageContainer, offset,
+                                                       presentationTimeUs,
                                                        aDuration,
                                                        img, isSync,
-                                                       aInfo->getPresentationTimeUs(),
+                                                       presentationTimeUs,
                                                        gfx::IntRect(0, 0,
                                                          mConfig.display_width,
                                                          mConfig.display_height));
     mCallback->Output(v);
     return NS_OK;
   }
 
 protected:
@@ -169,129 +179,131 @@ protected:
 
   layers::ImageContainer* mImageContainer;
   const mp4_demuxer::VideoDecoderConfig& mConfig;
   RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
   nsRefPtr<GLContext> mGLContext;
 };
 
 class AudioDataDecoder : public MediaCodecDataDecoder {
+private:
+  uint8_t csd0[2];
+
 public:
-  AudioDataDecoder(const char* aMimeType, MediaFormat* aFormat, MediaDataDecoderCallback* aCallback)
-  : MediaCodecDataDecoder(MediaData::Type::AUDIO_DATA, aMimeType, aFormat, aCallback)
+  AudioDataDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig, MediaFormat::Param aFormat, MediaDataDecoderCallback* aCallback)
+    : MediaCodecDataDecoder(MediaData::Type::AUDIO_DATA, aConfig.mime_type, aFormat, aCallback)
   {
+    JNIEnv* env = GetJNIForThread();
+
+    jni::Object::LocalRef buffer(env);
+    NS_ENSURE_SUCCESS_VOID(aFormat->GetByteBuffer(NS_LITERAL_STRING("csd-0"), &buffer));
+
+    if (!buffer) {
+      csd0[0] = (*aConfig.audio_specific_config)[0];
+      csd0[1] = (*aConfig.audio_specific_config)[1];
+
+      buffer = jni::Object::LocalRef::Adopt(env, env->NewDirectByteBuffer(csd0, 2));
+      NS_ENSURE_SUCCESS_VOID(aFormat->SetByteBuffer(NS_LITERAL_STRING("csd-0"), buffer));
+    }
   }
 
-  nsresult Output(BufferInfo* aInfo, void* aBuffer, MediaFormat* aFormat, Microseconds aDuration) {
+  nsresult Output(BufferInfo::Param aInfo, void* aBuffer, MediaFormat::Param aFormat, Microseconds aDuration) {
     // The output on Android is always 16-bit signed
 
-    uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_CSTRING("channel-count"));
-    uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_CSTRING("sample-rate"));
-    uint32_t numFrames = (aInfo->getSize() / numChannels) / 2;
+    nsresult rv;
+    int32_t numChannels;
+    NS_ENSURE_SUCCESS(rv =
+        aFormat->GetInteger(NS_LITERAL_STRING("channel-count"), &numChannels), rv);
+
+    int32_t sampleRate;
+    NS_ENSURE_SUCCESS(rv =
+        aFormat->GetInteger(NS_LITERAL_STRING("sample-rate"), &sampleRate), rv);
+
+    int32_t size;
+    NS_ENSURE_SUCCESS(rv = aInfo->Size(&size), rv);
 
-    AudioDataValue* audio = new AudioDataValue[aInfo->getSize()];
-    PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), aInfo->getSize());
+    const int32_t numFrames = (size / numChannels) / 2;
+    AudioDataValue* audio = new AudioDataValue[size];
+    PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), size);
 
-    nsRefPtr<AudioData> data = new AudioData(aInfo->getOffset(), aInfo->getPresentationTimeUs(),
+    int32_t offset;
+    NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv);
+
+    int64_t presentationTimeUs;
+    NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
+
+    nsRefPtr<AudioData> data = new AudioData(offset, presentationTimeUs,
                                              aDuration,
                                              numFrames,
                                              audio,
                                              numChannels,
                                              sampleRate);
     mCallback->Output(data);
     return NS_OK;
   }
 };
 
 
 bool AndroidDecoderModule::SupportsAudioMimeType(const char* aMimeType) {
-  JNIEnv* env = GetJNIForThread();
-  MediaCodec* decoder = CreateDecoder(env, aMimeType);
-  bool supports = (decoder != nullptr);
-  delete decoder;
-  return supports;
+  return static_cast<bool>(CreateDecoder(aMimeType));
 }
 
 already_AddRefed<MediaDataDecoder>
 AndroidDecoderModule::CreateVideoDecoder(
                                 const mp4_demuxer::VideoDecoderConfig& aConfig,
                                 layers::LayersBackend aLayersBackend,
                                 layers::ImageContainer* aImageContainer,
                                 MediaTaskQueue* aVideoTaskQueue,
                                 MediaDataDecoderCallback* aCallback)
 {
-  jobject jFormat = MediaFormat::CreateVideoFormat(nsCString(aConfig.mime_type),
-                                                   aConfig.display_width,
-                                                   aConfig.display_height);
+  MediaFormat::LocalRef format;
 
-  if (!jFormat) {
-    return nullptr;
-  }
-
-  MediaFormat* format = MediaFormat::Wrap(jFormat);
-
-  if (!format) {
-    return nullptr;
-  }
+  NS_ENSURE_SUCCESS(MediaFormat::CreateVideoFormat(
+      aConfig.mime_type,
+      aConfig.display_width,
+      aConfig.display_height,
+      &format), nullptr);
 
   nsRefPtr<MediaDataDecoder> decoder =
     new VideoDataDecoder(aConfig, format, aCallback, aImageContainer);
 
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
                                          MediaTaskQueue* aAudioTaskQueue,
                                          MediaDataDecoderCallback* aCallback)
 {
   MOZ_ASSERT(aConfig.bits_per_sample == 16, "We only handle 16-bit audio!");
 
-  jobject jFormat = MediaFormat::CreateAudioFormat(nsCString(aConfig.mime_type),
-                                                   aConfig.samples_per_second,
-                                                   aConfig.channel_count);
-
-  if (jFormat == nullptr)
-    return nullptr;
-
-  MediaFormat* format = MediaFormat::Wrap(jFormat);
-
-  if(format == nullptr)
-    return nullptr;
+  MediaFormat::LocalRef format;
 
-  JNIEnv* env = GetJNIForThread();
-
-  if (!format->GetByteBuffer(NS_LITERAL_CSTRING("csd-0"))) {
-    uint8_t* csd0 = new uint8_t[2];
-
-    csd0[0] = (*aConfig.audio_specific_config)[0];
-    csd0[1] = (*aConfig.audio_specific_config)[1];
-
-    jobject buffer = env->NewDirectByteBuffer(csd0, 2);
-    format->SetByteBuffer(NS_LITERAL_CSTRING("csd-0"), buffer);
-
-    env->DeleteLocalRef(buffer);
-  }
+  NS_ENSURE_SUCCESS(MediaFormat::CreateAudioFormat(
+      aConfig.mime_type,
+      aConfig.samples_per_second,
+      aConfig.channel_count,
+      &format), nullptr);
 
   nsRefPtr<MediaDataDecoder> decoder =
-    new AudioDataDecoder(aConfig.mime_type, format, aCallback);
+    new AudioDataDecoder(aConfig, format, aCallback);
 
   return decoder.forget();
 
 }
 
 
 nsresult AndroidDecoderModule::Shutdown()
 {
   return NS_OK;
 }
 
 MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
                                              const char* aMimeType,
-                                             MediaFormat* aFormat,
+                                             MediaFormat::Param aFormat,
                                              MediaDataDecoderCallback* aCallback)
   : mType(aType)
   , mMimeType(strdup(aMimeType))
   , mFormat(aFormat)
   , mCallback(aCallback)
   , mInputBuffers(nullptr)
   , mOutputBuffers(nullptr)
   , mMonitor("MediaCodecDataDecoder::mMonitor")
@@ -299,65 +311,38 @@ MediaCodecDataDecoder::MediaCodecDataDec
   , mDraining(false)
   , mStopping(false)
 {
 
 }
 
 MediaCodecDataDecoder::~MediaCodecDataDecoder()
 {
-  JNIEnv* env = GetJNIForThread();
-
   Shutdown();
-
-  if (mInputBuffers) {
-    env->DeleteGlobalRef(mInputBuffers);
-    mInputBuffers = nullptr;
-  }
-
-  if (mOutputBuffers) {
-    env->DeleteGlobalRef(mOutputBuffers);
-    mOutputBuffers = nullptr;
-  }
 }
 
 nsresult MediaCodecDataDecoder::Init()
 {
-  return InitDecoder();
+  return InitDecoder(nullptr);
 }
 
-nsresult MediaCodecDataDecoder::InitDecoder(jobject aSurface)
+nsresult MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface)
 {
-  JNIEnv* env = GetJNIForThread();
-  mDecoder = CreateDecoder(env, mMimeType);
+  mDecoder = CreateDecoder(mMimeType);
   if (!mDecoder) {
     mCallback->Error();
     return NS_ERROR_FAILURE;
   }
 
-  nsresult res;
-  mDecoder->Configure(mFormat->wrappedObject(), aSurface, nullptr, 0, &res);
-  if (NS_FAILED(res)) {
-    return res;
-  }
+  nsresult rv;
+  NS_ENSURE_SUCCESS(rv = mDecoder->Configure(mFormat, aSurface, nullptr, 0), rv);
+  NS_ENSURE_SUCCESS(rv = mDecoder->Start(), rv);
 
-  mDecoder->Start(&res);
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  res = ResetInputBuffers();
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  res = ResetOutputBuffers();
-  if (NS_FAILED(res)) {
-    return res;
-  }
+  NS_ENSURE_SUCCESS(rv = ResetInputBuffers(), rv);
+  NS_ENSURE_SUCCESS(rv = ResetOutputBuffers(), rv);
 
   NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread),
                     NS_NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop));
 
   return NS_OK;
 }
 
 // This is in usec, so that's 10ms
@@ -372,20 +357,20 @@ nsresult MediaCodecDataDecoder::InitDeco
 
 void MediaCodecDataDecoder::DecoderLoop()
 {
   bool outputDone = false;
 
   bool draining = false;
   bool waitingEOF = false;
 
-  JNIEnv* env = GetJNIForThread();
+  AutoLocalJNIFrame frame(GetJNIForThread(), 1);
   mp4_demuxer::MP4Sample* sample = nullptr;
 
-  nsAutoPtr<MediaFormat> outputFormat;
+  MediaFormat::LocalRef outputFormat(frame.GetEnv());
   nsresult res;
 
   for (;;) {
     {
       MonitorAutoLock lock(mMonitor);
       while (!mStopping && !mDraining && !mFlushing && mQueue.empty()) {
         if (mQueue.empty()) {
           // We could be waiting here forever if we don't signal that we need more input
@@ -415,80 +400,92 @@ void MediaCodecDataDecoder::DecoderLoop(
       if (!mQueue.empty()) {
         sample = mQueue.front();
       }
     }
 
     if (draining && !waitingEOF) {
       MOZ_ASSERT(!sample, "Shouldn't have a sample when pushing EOF frame");
 
-      int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &res);
+      int32_t inputIndex;
+      res = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &inputIndex);
       HANDLE_DECODER_ERROR();
 
       if (inputIndex >= 0) {
-        mDecoder->QueueInputBuffer(inputIndex, 0, 0, 0, MediaCodec::getBUFFER_FLAG_END_OF_STREAM(), &res);
+        res = mDecoder->QueueInputBuffer(inputIndex, 0, 0, 0, MediaCodec::BUFFER_FLAG_END_OF_STREAM);
+        HANDLE_DECODER_ERROR();
+
         waitingEOF = true;
       }
     }
 
     if (sample) {
       // We have a sample, try to feed it to the decoder
-      int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &res);
+      int inputIndex;
+      res = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &inputIndex);
       HANDLE_DECODER_ERROR();
 
       if (inputIndex >= 0) {
-        jobject buffer = env->GetObjectArrayElement(mInputBuffers, inputIndex);
-        void* directBuffer = env->GetDirectBufferAddress(buffer);
+        auto buffer = jni::Object::LocalRef::Adopt(
+            frame.GetEnv()->GetObjectArrayElement(mInputBuffers.Get(), inputIndex));
+        void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
 
-        // We're feeding this to the decoder, so remove it from the queue
-        mMonitor.Lock();
-        mQueue.pop();
-        mMonitor.Unlock();
+        MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >= sample->size,
+          "Decoder buffer is not large enough for sample");
 
-        MOZ_ASSERT(env->GetDirectBufferCapacity(buffer) >= sample->size,
-          "Decoder buffer is not large enough for sample");
+        {
+          // We're feeding this to the decoder, so remove it from the queue
+          MonitorAutoLock lock(mMonitor);
+          mQueue.pop();
+        }
 
         PodCopy((uint8_t*)directBuffer, sample->data, sample->size);
 
-        mDecoder->QueueInputBuffer(inputIndex, 0, sample->size, sample->composition_timestamp, 0, &res);
+        res = mDecoder->QueueInputBuffer(inputIndex, 0, sample->size,
+                                         sample->composition_timestamp, 0);
         HANDLE_DECODER_ERROR();
 
         mDurations.push(sample->duration);
-
         delete sample;
         sample = nullptr;
-
         outputDone = false;
-        env->DeleteLocalRef(buffer);
       }
     }
 
     if (!outputDone) {
-      BufferInfo bufferInfo;
+      BufferInfo::LocalRef bufferInfo;
+      res = BufferInfo::New(&bufferInfo);
+      HANDLE_DECODER_ERROR();
 
-      int outputStatus = mDecoder->DequeueOutputBuffer(bufferInfo.wrappedObject(), DECODER_TIMEOUT, &res);
+      int32_t outputStatus;
+      res = mDecoder->DequeueOutputBuffer(bufferInfo, DECODER_TIMEOUT, &outputStatus);
       HANDLE_DECODER_ERROR();
 
-      if (outputStatus == MediaCodec::getINFO_TRY_AGAIN_LATER()) {
+      if (outputStatus == MediaCodec::INFO_TRY_AGAIN_LATER) {
         // We might want to call mCallback->InputExhausted() here, but there seems to be
         // some possible bad interactions here with the threading
-      } else if (outputStatus == MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED()) {
+      } else if (outputStatus == MediaCodec::INFO_OUTPUT_BUFFERS_CHANGED) {
         res = ResetOutputBuffers();
         HANDLE_DECODER_ERROR();
-      } else if (outputStatus == MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED()) {
-        outputFormat = new MediaFormat(mDecoder->GetOutputFormat(), GetJNIForThread());
+      } else if (outputStatus == MediaCodec::INFO_OUTPUT_FORMAT_CHANGED) {
+        res = mDecoder->GetOutputFormat(ReturnTo(&outputFormat));
+        HANDLE_DECODER_ERROR();
       } else if (outputStatus < 0) {
         NS_WARNING("unknown error from decoder!");
         mCallback->Error();
 
         // Don't break here just in case it's recoverable. If it's not, others stuff will fail later and
         // we'll bail out.
       } else {
+        int32_t flags;
+        res = bufferInfo->Flags(&flags);
+        HANDLE_DECODER_ERROR();
+
         // We have a valid buffer index >= 0 here
-        if (bufferInfo.getFlags() & MediaCodec::getBUFFER_FLAG_END_OF_STREAM()) {
+        if (flags & MediaCodec::BUFFER_FLAG_END_OF_STREAM) {
           if (draining) {
             draining = false;
             waitingEOF = false;
 
             mMonitor.Lock();
             mDraining = false;
             mMonitor.Notify();
             mMonitor.Unlock();
@@ -506,42 +503,38 @@ void MediaCodecDataDecoder::DecoderLoop(
         MOZ_ASSERT(!mDurations.empty(), "Should have had a duration queued");
 
         Microseconds duration = 0;
         if (!mDurations.empty()) {
           duration = mDurations.front();
           mDurations.pop();
         }
 
-        jobject buffer = env->GetObjectArrayElement(mOutputBuffers, outputStatus);
+        auto buffer = jni::Object::LocalRef::Adopt(
+            frame.GetEnv()->GetObjectArrayElement(mOutputBuffers.Get(), outputStatus));
         if (buffer) {
           // The buffer will be null on Android L if we are decoding to a Surface
-          void* directBuffer = env->GetDirectBufferAddress(buffer);
-          Output(&bufferInfo, directBuffer, outputFormat, duration);
+          void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
+          Output(bufferInfo, directBuffer, outputFormat, duration);
         }
 
         // The Surface will be updated at this point (for video)
         mDecoder->ReleaseOutputBuffer(outputStatus, true);
 
-        PostOutput(&bufferInfo, outputFormat, duration);
-
-        if (buffer) {
-          env->DeleteLocalRef(buffer);
-        }
+        PostOutput(bufferInfo, outputFormat, duration);
       }
     }
   }
 
   Cleanup();
 
   // We're done
-  mMonitor.Lock();
+  MonitorAutoLock lock(mMonitor);
   mStopping = false;
   mMonitor.Notify();
-  mMonitor.Unlock();
 }
 
 void MediaCodecDataDecoder::ClearQueue()
 {
   mMonitor.AssertCurrentThreadOwns();
   while (!mQueue.empty()) {
     delete mQueue.front();
     mQueue.pop();
@@ -556,46 +549,22 @@ nsresult MediaCodecDataDecoder::Input(mp
   mQueue.push(aSample);
   lock.NotifyAll();
 
   return NS_OK;
 }
 
 nsresult MediaCodecDataDecoder::ResetInputBuffers()
 {
-  JNIEnv* env = GetJNIForThread();
-
-  if (mInputBuffers) {
-    env->DeleteGlobalRef(mInputBuffers);
-  }
-
-  nsresult res;
-  mInputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetInputBuffers(&res));
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  return NS_OK;
+  return mDecoder->GetInputBuffers(ReturnTo(&mInputBuffers));
 }
 
 nsresult MediaCodecDataDecoder::ResetOutputBuffers()
 {
-  JNIEnv* env = GetJNIForThread();
-
-  if (mOutputBuffers) {
-    env->DeleteGlobalRef(mOutputBuffers);
-  }
-
-  nsresult res;
-  mOutputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetOutputBuffers(&res));
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  return NS_OK;
+  return mDecoder->GetOutputBuffers(ReturnTo(&mOutputBuffers));
 }
 
 nsresult MediaCodecDataDecoder::Flush() {
   MonitorAutoLock lock(mMonitor);
   mFlushing = true;
   lock.Notify();
 
   while (mFlushing) {
--- a/dom/media/fmp4/android/AndroidDecoderModule.h
+++ b/dom/media/fmp4/android/AndroidDecoderModule.h
@@ -12,28 +12,16 @@
 #include "mozilla/Monitor.h"
 
 #include <queue>
 
 namespace mozilla {
 
 typedef std::queue<mp4_demuxer::MP4Sample*> SampleQueue;
 
-namespace widget {
-namespace android {
-namespace sdk {
-  class MediaCodec;
-  class MediaFormat;
-  class ByteBuffer;
-}
-}
-}
-
-class MediaCodecDataDecoder;
-
 class AndroidDecoderModule : public PlatformDecoderModule {
 public:
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   virtual already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
@@ -52,57 +40,57 @@ public:
   virtual bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE;
 };
 
 class MediaCodecDataDecoder : public MediaDataDecoder {
 public:
 
   MediaCodecDataDecoder(MediaData::Type aType,
                         const char* aMimeType,
-                        mozilla::widget::android::sdk::MediaFormat* aFormat,
+                        widget::sdk::MediaFormat::Param aFormat,
                         MediaDataDecoderCallback* aCallback);
 
   virtual ~MediaCodecDataDecoder();
 
   virtual nsresult Init() MOZ_OVERRIDE;
   virtual nsresult Flush() MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   virtual nsresult Shutdown() MOZ_OVERRIDE;
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
 
 protected:
   friend class AndroidDecoderModule;
 
   MediaData::Type mType;
 
   nsAutoPtr<char> mMimeType;
-  nsAutoPtr<mozilla::widget::android::sdk::MediaFormat> mFormat;
+  widget::sdk::MediaFormat::GlobalRef mFormat;
 
   MediaDataDecoderCallback* mCallback;
 
-  nsAutoPtr<mozilla::widget::android::sdk::MediaCodec> mDecoder;
+  widget::sdk::MediaCodec::GlobalRef mDecoder;
 
-  jobjectArray mInputBuffers;
-  jobjectArray mOutputBuffers;
+  jni::ObjectArray::GlobalRef mInputBuffers;
+  jni::ObjectArray::GlobalRef mOutputBuffers;
 
   nsCOMPtr<nsIThread> mThread;
 
   // Only these members are protected by mMonitor.
   Monitor mMonitor;
   bool mFlushing;
   bool mDraining;
   bool mStopping;
 
   SampleQueue mQueue;
   std::queue<Microseconds> mDurations;
 
-  virtual nsresult InitDecoder(jobject aSurface = nullptr);
+  virtual nsresult InitDecoder(widget::sdk::Surface::Param aSurface);
 
-  virtual nsresult Output(mozilla::widget::android::sdk::BufferInfo* aInfo, void* aBuffer, mozilla::widget::android::sdk::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
-  virtual nsresult PostOutput(mozilla::widget::android::sdk::BufferInfo* aInfo, mozilla::widget::android::sdk::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
+  virtual nsresult Output(widget::sdk::BufferInfo::Param aInfo, void* aBuffer, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
+  virtual nsresult PostOutput(widget::sdk::BufferInfo::Param aInfo, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
   virtual void Cleanup() {};
 
   nsresult ResetInputBuffers();
   nsresult ResetOutputBuffers();
 
   void DecoderLoop();
   virtual void ClearQueue();
 };
--- a/dom/plugins/base/android/ANPSystem.cpp
+++ b/dom/plugins/base/android/ANPSystem.cpp
@@ -45,30 +45,27 @@ anp_system_getApplicationDataDirectory(N
 }
 
 const char*
 anp_system_getApplicationDataDirectory()
 {
   return anp_system_getApplicationDataDirectory(nullptr);
 }
 
-jclass anp_system_loadJavaClass(NPP instance, const char* classNameStr)
+jclass anp_system_loadJavaClass(NPP instance, const char* className)
 {
   LOG("%s", __PRETTY_FUNCTION__);
 
   nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
   mozilla::PluginPRLibrary* lib = static_cast<mozilla::PluginPRLibrary*>(pinst->GetPlugin()->GetLibrary());
 
-  NS_ConvertUTF8toUTF16 className(classNameStr);
+  nsCString libName;
+  lib->GetLibraryPath(libName);
 
-  nsCString libNameUtf8;
-  lib->GetLibraryPath(libNameUtf8);
-  NS_ConvertUTF8toUTF16 libName(libNameUtf8);
-
-  return mozilla::widget::android::GeckoAppShell::LoadPluginClass(className, libName);
+  return mozilla::widget::GeckoAppShell::LoadPluginClass(className, libName).Forget();
 }
 
 void anp_system_setPowerState(NPP instance, ANPPowerState powerState)
 {
   nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::GetFromNPP(instance);
 
   if (pinst) {
     pinst->SetWakeLock(powerState == kScreenOn_ANPPowerState);
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2264,22 +2264,21 @@ NPError
     case kSupportedDrawingModel_ANPGetValue: {
       LOG("get supported drawing model");
       uint32_t* bits = reinterpret_cast<uint32_t*>(result);
       *bits = kBitmap_ANPDrawingModel && kSurface_ANPDrawingModel;
       return NPERR_NO_ERROR;
     }
 
     case kJavaContext_ANPGetValue: {
-      jobject ret = mozilla::widget::android::GeckoAppShell::GetContext();
+      auto ret = widget::GeckoAppShell::GetContext();
       if (!ret)
         return NPERR_GENERIC_ERROR;
 
-      int32_t* i  = reinterpret_cast<int32_t*>(result);
-      *i = reinterpret_cast<int32_t>(ret);
+      *static_cast<jobject*>(result) = ret.Forget();
       return NPERR_NO_ERROR;
     }
 
     case kAudioTrackInterfaceV1_ANPGetValue: {
       LOG("get audio interface v1");
       ANPAudioTrackInterfaceV1 *i = (ANPAudioTrackInterfaceV1 *) result;
       InitAudioTrackInterfaceV1(i);
       return NPERR_NO_ERROR;
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -844,17 +844,17 @@ void nsNPAPIPluginInstance::NotifyFullSc
 
   if (RUNNING != mRunning || mFullScreen == aFullScreen)
     return;
 
   mFullScreen = aFullScreen;
   SendLifecycleEvent(this, mFullScreen ? kEnterFullScreen_ANPLifecycleAction : kExitFullScreen_ANPLifecycleAction);
 
   if (mFullScreen && mFullScreenOrientation != dom::eScreenOrientation_None) {
-    mozilla::widget::android::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
+    widget::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
   }
 }
 
 void nsNPAPIPluginInstance::NotifySize(nsIntSize size)
 {
   if (kOpenGL_ANPDrawingModel != GetANPDrawingModel() ||
       size == mCurrentSize)
     return;
@@ -901,21 +901,21 @@ void nsNPAPIPluginInstance::SetFullScree
 
   uint32_t oldOrientation = mFullScreenOrientation;
   mFullScreenOrientation = orientation;
 
   if (mFullScreen) {
     // We're already fullscreen so immediately apply the orientation change
 
     if (mFullScreenOrientation != dom::eScreenOrientation_None) {
-      mozilla::widget::android::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
+      widget::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
     } else if (oldOrientation != dom::eScreenOrientation_None) {
       // We applied an orientation when we entered fullscreen, but
       // we don't want it anymore
-      mozilla::widget::android::GeckoAppShell::UnlockScreenOrientation();
+      widget::GeckoAppShell::UnlockScreenOrientation();
     }
   }
 }
 
 void nsNPAPIPluginInstance::PopPostedEvent(PluginEventRunnable* r)
 {
   mPostedEvents.RemoveElement(r);
 }
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1351,17 +1351,18 @@ bool nsPluginInstanceOwner::AddPluginVie
   return true;
 }
 
 void nsPluginInstanceOwner::RemovePluginView()
 {
   if (!mInstance || !mJavaView)
     return;
 
-  mozilla::widget::android::GeckoAppShell::RemovePluginView((jobject)mJavaView, mFullScreen);
+  widget::GeckoAppShell::RemovePluginView(
+      jni::Object::Ref::From(jobject(mJavaView)), mFullScreen);
   AndroidBridge::GetJNIEnv()->DeleteGlobalRef((jobject)mJavaView);
   mJavaView = nullptr;
 
   if (mFullScreen)
     sFullScreenInstance = nullptr;
 }
 
 void
--- a/dom/system/android/AndroidLocationProvider.cpp
+++ b/dom/system/android/AndroidLocationProvider.cpp
@@ -21,34 +21,34 @@ AndroidLocationProvider::AndroidLocation
 AndroidLocationProvider::~AndroidLocationProvider()
 {
     NS_IF_RELEASE(gLocationCallback);
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Startup()
 {
-    mozilla::widget::android::GeckoAppShell::EnableLocation(true);
+    widget::GeckoAppShell::EnableLocation(true);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Watch(nsIGeolocationUpdate* aCallback)
 {
     NS_IF_RELEASE(gLocationCallback);
     gLocationCallback = aCallback;
     NS_IF_ADDREF(gLocationCallback);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Shutdown()
 {
-    mozilla::widget::android::GeckoAppShell::EnableLocation(false);
+    widget::GeckoAppShell::EnableLocation(false);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::SetHighAccuracy(bool enable)
 {
-    mozilla::widget::android::GeckoAppShell::EnableLocationHighAccuracy(enable);
+    widget::GeckoAppShell::EnableLocationHighAccuracy(enable);
     return NS_OK;
 }
--- a/dom/system/android/nsHapticFeedback.cpp
+++ b/dom/system/android/nsHapticFeedback.cpp
@@ -9,11 +9,11 @@
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(nsHapticFeedback, nsIHapticFeedback)
 
 NS_IMETHODIMP
 nsHapticFeedback::PerformSimpleAction(int32_t aType)
 {
-    mozilla::widget::android::GeckoAppShell::PerformHapticFeedback(aType == LongPress);
+    widget::GeckoAppShell::PerformHapticFeedback(aType == LongPress);
     return NS_OK;
 }
--- a/gfx/gl/AndroidSurfaceTexture.cpp
+++ b/gfx/gl/AndroidSurfaceTexture.cpp
@@ -14,18 +14,19 @@
 #include "AndroidBridge.h"
 #include "nsThreadUtils.h"
 #include "mozilla/gfx/Matrix.h"
 #include "GeneratedJNIWrappers.h"
 #include "SurfaceTexture.h"
 #include "GLContext.h"
 
 using namespace mozilla;
-using namespace mozilla::widget::android;
-using namespace mozilla::widget::android::sdk;
+using namespace mozilla::jni;
+using namespace mozilla::widget;
+using namespace mozilla::widget::sdk;
 
 namespace mozilla {
 namespace gl {
 
 // UGH
 static std::map<int, AndroidSurfaceTexture*> sInstances;
 static int sNextID = 0;
 
@@ -98,19 +99,17 @@ AndroidSurfaceTexture::Attach(GLContext*
   }
 
   MOZ_ASSERT(aContext->IsOwningThreadCurrent(), "Trying to attach GLContext from different thread");
 
   mAttachedContext = aContext;
   mAttachedContext->MakeCurrent();
   aContext->fGenTextures(1, &mTexture);
 
-  nsresult res;
-  mSurfaceTexture->AttachToGLContext(mTexture, &res);
-  return res;
+  return mSurfaceTexture->AttachToGLContext(mTexture);
 }
 
 nsresult
 AndroidSurfaceTexture::Detach()
 {
   MonitorAutoLock lock(mMonitor);
 
   if (!IsDetachSupported() ||
@@ -131,81 +130,78 @@ AndroidSurfaceTexture::Detach()
 bool
 AndroidSurfaceTexture::Init(GLContext* aContext, GLuint aTexture)
 {
   if (!aTexture && !IsDetachSupported()) {
     // We have no texture and cannot initialize detached, bail out
     return false;
   }
 
-  nsresult res;
-  mSurfaceTexture = new SurfaceTexture(aTexture, &res);
-  if (NS_FAILED(res)) {
+  if (NS_WARN_IF(NS_FAILED(
+      SurfaceTexture::New(aTexture, ReturnTo(&mSurfaceTexture))))) {
     return false;
   }
 
   if (!aTexture) {
     mSurfaceTexture->DetachFromGLContext();
   }
 
   mAttachedContext = aContext;
 
-  mSurface = new Surface(mSurfaceTexture->wrappedObject(), &res);
-  if (NS_FAILED(res)) {
+  if (NS_WARN_IF(NS_FAILED(
+      Surface::New(mSurfaceTexture, ReturnTo(&mSurface))))) {
     return false;
   }
 
   mNativeWindow = AndroidNativeWindow::CreateFromSurface(GetJNIForThread(),
-                                                         mSurface->wrappedObject());
+                                                         mSurface.Get());
   MOZ_ASSERT(mNativeWindow, "Failed to create native window from surface");
 
   mID = ++sNextID;
   sInstances.insert(std::pair<int, AndroidSurfaceTexture*>(mID, this));
 
   return true;
 }
 
 AndroidSurfaceTexture::AndroidSurfaceTexture()
   : mTexture(0)
-  , mSurfaceTexture(nullptr)
-  , mSurface(nullptr)
+  , mSurfaceTexture()
+  , mSurface()
   , mMonitor("AndroidSurfaceTexture::mContextMonitor")
   , mAttachedContext(nullptr)
 {
 }
 
 AndroidSurfaceTexture::~AndroidSurfaceTexture()
 {
   sInstances.erase(mID);
 
   mFrameAvailableCallback = nullptr;
 
   if (mSurfaceTexture) {
-    GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject());
+    GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
     mSurfaceTexture = nullptr;
   }
 }
 
 void
 AndroidSurfaceTexture::UpdateTexImage()
 {
   mSurfaceTexture->UpdateTexImage();
 }
 
 void
 AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix)
 {
   JNIEnv* env = GetJNIForThread();
 
-  AutoLocalJNIFrame jniFrame(env);
-
-  jfloatArray jarray = env->NewFloatArray(16);
+  auto jarray = FloatArray::LocalRef::Adopt(env, env->NewFloatArray(16));
   mSurfaceTexture->GetTransformMatrix(jarray);
 
-  jfloat* array = env->GetFloatArrayElements(jarray, nullptr);
+  jfloat* array = env->GetFloatArrayElements(jarray.Get(), nullptr);
 
   aMatrix._11 = array[0];
   aMatrix._12 = array[1];
   aMatrix._13 = array[2];
   aMatrix._14 = array[3];
 
   aMatrix._21 = array[4];
   aMatrix._22 = array[5];
@@ -217,26 +213,26 @@ AndroidSurfaceTexture::GetTransformMatri
   aMatrix._33 = array[10];
   aMatrix._34 = array[11];
 
   aMatrix._41 = array[12];
   aMatrix._42 = array[13];
   aMatrix._43 = array[14];
   aMatrix._44 = array[15];
 
-  env->ReleaseFloatArrayElements(jarray, array, 0);
+  env->ReleaseFloatArrayElements(jarray.Get(), array, 0);
 }
 
 void
 AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
 {
   if (aRunnable) {
-    GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject(), mID);
+    GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID);
   } else {
-     GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject());
+     GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
   }
 
   mFrameAvailableCallback = aRunnable;
 }
 
 void
 AndroidSurfaceTexture::SetDefaultSize(mozilla::gfx::IntSize size)
 {
--- a/gfx/gl/AndroidSurfaceTexture.h
+++ b/gfx/gl/AndroidSurfaceTexture.h
@@ -82,26 +82,27 @@ public:
   // if the upstream callback is received on a different thread
   void SetFrameAvailableCallback(nsIRunnable* aRunnable);
 
   // Only should be called by AndroidJNI when we get a
   // callback from the underlying SurfaceTexture instance
   void NotifyFrameAvailable();
 
   GLuint Texture() { return mTexture; }
-  jobject JavaSurface() { return mSurface->wrappedObject(); }
+  const widget::sdk::Surface::Ref& JavaSurface() { return mSurface; }
+
 private:
   AndroidSurfaceTexture();
   ~AndroidSurfaceTexture();
 
   bool Init(GLContext* aContext, GLuint aTexture);
 
   GLuint mTexture;
-  nsAutoPtr<mozilla::widget::android::sdk::SurfaceTexture> mSurfaceTexture;
-  nsAutoPtr<mozilla::widget::android::sdk::Surface> mSurface;
+  widget::sdk::SurfaceTexture::GlobalRef mSurfaceTexture;
+  widget::sdk::Surface::GlobalRef mSurface;
 
   Monitor mMonitor;
   GLContext* mAttachedContext;
 
   RefPtr<AndroidNativeWindow> mNativeWindow;
   int mID;
   nsRefPtr<nsIRunnable> mFrameAvailableCallback;
 };
--- a/hal/android/AndroidGamepad.cpp
+++ b/hal/android/AndroidGamepad.cpp
@@ -9,19 +9,19 @@
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 StartMonitoringGamepadStatus()
 {
-  mozilla::widget::android::GeckoAppShell::StartMonitoringGamepad();
+  widget::GeckoAppShell::StartMonitoringGamepad();
 }
 
 void
 StopMonitoringGamepadStatus()
 {
-  mozilla::widget::android::GeckoAppShell::StopMonitoringGamepad();
+  widget::GeckoAppShell::StopMonitoringGamepad();
 }
 
 } // hal_impl
 } // mozilla
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -9,17 +9,16 @@
 #include "AndroidBridge.h"
 #include "mozilla/dom/network/Constants.h"
 #include "mozilla/dom/ScreenOrientation.h"
 #include "nsIScreenManager.h"
 #include "nsServiceManagerUtils.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::hal;
-using namespace mozilla::widget::android;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 Vibrate(const nsTArray<uint32_t> &pattern, const WindowIdentifier &)
 {
   // Ignore the WindowIdentifier parameter; it's here only because hal::Vibrate,
@@ -50,65 +49,65 @@ Vibrate(const nsTArray<uint32_t> &patter
   b->Vibrate(pattern);
 }
 
 void
 CancelVibrate(const WindowIdentifier &)
 {
   // Ignore WindowIdentifier parameter.
 
-  mozilla::widget::android::GeckoAppShell::CancelVibrate();
+  mozilla::widget::GeckoAppShell::CancelVibrate();
 }
 
 void
 EnableBatteryNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::EnableBatteryNotifications();
+  mozilla::widget::GeckoAppShell::EnableBatteryNotifications();
 }
 
 void
 DisableBatteryNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::DisableBatteryNotifications();
+  mozilla::widget::GeckoAppShell::DisableBatteryNotifications();
 }
 
 void
 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
 {
   AndroidBridge::Bridge()->GetCurrentBatteryInformation(aBatteryInfo);
 }
 
 void
 EnableNetworkNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::EnableNetworkNotifications();
+  mozilla::widget::GeckoAppShell::EnableNetworkNotifications();
 }
 
 void
 DisableNetworkNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::DisableNetworkNotifications();
+  mozilla::widget::GeckoAppShell::DisableNetworkNotifications();
 }
 
 void
 GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
 {
   AndroidBridge::Bridge()->GetCurrentNetworkInformation(aNetworkInfo);
 }
 
 void
 EnableScreenConfigurationNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::EnableScreenOrientationNotifications();
+  mozilla::widget::GeckoAppShell::EnableScreenOrientationNotifications();
 }
 
 void
 DisableScreenConfigurationNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::DisableScreenOrientationNotifications();
+  mozilla::widget::GeckoAppShell::DisableScreenOrientationNotifications();
 }
 
 void
 GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration)
 {
   AndroidBridge* bridge = AndroidBridge::Bridge();
   if (!bridge) {
     return;
@@ -144,24 +143,24 @@ LockScreenOrientation(const ScreenOrient
     // The Android backend only supports these orientations.
     case eScreenOrientation_PortraitPrimary:
     case eScreenOrientation_PortraitSecondary:
     case eScreenOrientation_PortraitPrimary | eScreenOrientation_PortraitSecondary:
     case eScreenOrientation_LandscapePrimary:
     case eScreenOrientation_LandscapeSecondary:
     case eScreenOrientation_LandscapePrimary | eScreenOrientation_LandscapeSecondary:
     case eScreenOrientation_Default:
-      mozilla::widget::android::GeckoAppShell::LockScreenOrientation(aOrientation);
+      mozilla::widget::GeckoAppShell::LockScreenOrientation(aOrientation);
       return true;
     default:
       return false;
   }
 }
 
 void
 UnlockScreenOrientation()
 {
-  mozilla::widget::android::GeckoAppShell::UnlockScreenOrientation();
+  mozilla::widget::GeckoAppShell::UnlockScreenOrientation();
 }
 
 } // hal_impl
 } // mozilla
 
--- a/hal/android/AndroidSensor.cpp
+++ b/hal/android/AndroidSensor.cpp
@@ -8,18 +8,18 @@
 
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 EnableSensorNotifications(SensorType aSensor) {
-  mozilla::widget::android::GeckoAppShell::EnableSensor(aSensor);
+  widget::GeckoAppShell::EnableSensor(aSensor);
 }
 
 void
 DisableSensorNotifications(SensorType aSensor) {
-  mozilla::widget::android::GeckoAppShell::DisableSensor(aSensor);
+  widget::GeckoAppShell::DisableSensor(aSensor);
 }
 
 } // hal_impl
 } // mozilla
--- a/ipc/glue/MessagePump.cpp
+++ b/ipc/glue/MessagePump.cpp
@@ -105,17 +105,17 @@ MessagePump::Run(MessagePump::Delegate* 
     // equal priority, we sensitively rely on processing exactly one
     // Task per DoWorkRunnable XPCOM event.
 
 #ifdef MOZ_WIDGET_ANDROID
     // This processes messages in the Android Looper. Note that we only
     // get here if the normal Gecko event loop has been awoken above.
     // Bug 750713
     if (MOZ_LIKELY(AndroidBridge::HasEnv())) {
-        did_work |= mozilla::widget::android::GeckoAppShell::PumpMessageLoop();
+        did_work |= mozilla::widget::GeckoAppShell::PumpMessageLoop();
     }
 #endif
 
     did_work |= aDelegate->DoDelayedWork(&delayed_work_time_);
 
 if (did_work && delayed_work_time_.is_null()
 #ifdef MOZ_NUWA_PROCESS
     && (!IsNuwaReady() || !IsNuwaProcess())
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -250,17 +250,17 @@ public class GeckoAppShell
     static public final int LINK_TYPE_2G = 5;
     static public final int LINK_TYPE_3G = 6;
     static public final int LINK_TYPE_4G = 7;
 
     /* The Android-side API: API methods that Android calls */
 
     // Initialization methods
     public static native void registerJavaUiThread();
-    public static native void nativeInit();
+    public static native void nativeInit(ClassLoader clsLoader);
 
     // helper methods
     public static native void onResume();
     public static void callObserver(String observerKey, String topic, String data) {
         sendEventToGecko(GeckoEvent.createCallObserverEvent(observerKey, topic, data));
     }
     public static void removeObserver(String observerKey) {
         sendEventToGecko(GeckoEvent.createRemoveObserverEvent(observerKey));
@@ -334,18 +334,18 @@ public class GeckoAppShell
                 idleMsg.obj = geckoHandler;
                 geckoHandler.sendMessageAtFrontOfQueue(idleMsg);
                 // Keep this IdleHandler
                 return true;
             }
         };
         Looper.myQueue().addIdleHandler(idleHandler);
 
-        // run gecko -- it will spawn its own thread
-        GeckoAppShell.nativeInit();
+        // Initialize AndroidBridge.
+        nativeInit(GeckoAppShell.class.getClassLoader());
 
         // First argument is the .apk path
         String combinedArgs = apkPath + " -greomni " + apkPath;
         if (args != null)
             combinedArgs += " " + args;
         if (url != null)
             combinedArgs += " -url " + url;
         if (type != null)
--- a/mobile/android/components/build/nsAndroidHistory.cpp
+++ b/mobile/android/components/build/nsAndroidHistory.cpp
@@ -72,17 +72,17 @@ nsAndroidHistory::RegisterVisitedCallbac
   nsTArray<Link*>* list = mListeners.Get(uriString);
   if (! list) {
     list = new nsTArray<Link*>();
     mListeners.Put(uriString, list);
   }
   list->AppendElement(aContent);
 
   if (AndroidBridge::HasEnv()) {
-    mozilla::widget::android::GeckoAppShell::CheckURIVisited(uriString);
+    widget::GeckoAppShell::CheckURIVisited(uriString);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidHistory::UnregisterVisitedCallback(nsIURI *aURI, Link *aContent)
 {
@@ -198,17 +198,17 @@ void
 nsAndroidHistory::SaveVisitURI(nsIURI* aURI) {
   // Add the URI to our cache so we can take a fast path later
   AppendToRecentlyVisitedURIs(aURI);
 
   if (AndroidBridge::HasEnv()) {
     // Save this URI in our history
     nsAutoCString spec;
     (void)aURI->GetSpec(spec);
-    mozilla::widget::android::GeckoAppShell::MarkURIVisited(NS_ConvertUTF8toUTF16(spec));
+    widget::GeckoAppShell::MarkURIVisited(NS_ConvertUTF8toUTF16(spec));
   }
 
   // Finally, notify that we've been visited.
   nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
   if (obsService) {
     obsService->NotifyObservers(aURI, NS_LINK_VISITED_EVENT_TOPIC, nullptr);
   }
 }
@@ -283,17 +283,17 @@ nsAndroidHistory::SetURITitle(nsIURI *aU
     return NS_OK;
   }
 
   if (AndroidBridge::HasEnv()) {
     nsAutoCString uri;
     nsresult rv = aURI->GetSpec(uri);
     if (NS_FAILED(rv)) return rv;
     NS_ConvertUTF8toUTF16 uriString(uri);
-    mozilla::widget::android::GeckoAppShell::SetURITitle(uriString, aTitle);
+    widget::GeckoAppShell::SetURITitle(uriString, aTitle);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidHistory::NotifyVisited(nsIURI *aURI)
 {
   if (aURI && sHistory) {
--- a/mobile/android/components/build/nsShellService.cpp
+++ b/mobile/android/components/build/nsShellService.cpp
@@ -3,28 +3,28 @@
  * 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/. */
 
 #include "nsShellService.h"
 #include "nsString.h"
 
 #include "AndroidBridge.h"
 
-using namespace mozilla::widget::android;
+using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(nsShellService, nsIShellService)
 
 NS_IMETHODIMP
 nsShellService::SwitchTask()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsShellService::CreateShortcut(const nsAString& aTitle, const nsAString& aURI,
                                 const nsAString& aIconData, const nsAString& aIntent)
 {
   if (!aTitle.Length() || !aURI.Length() || !aIconData.Length())
     return NS_ERROR_FAILURE;
 
-  mozilla::widget::android::GeckoAppShell::CreateShortcut(aTitle, aURI, aIconData);
+  widget::GeckoAppShell::CreateShortcut(aTitle, aURI, aIconData);
   return NS_OK;
 }
--- a/mozglue/android/jni-stubs.inc
+++ b/mozglue/android/jni-stubs.inc
@@ -72,26 +72,26 @@ Java_org_mozilla_gecko_GeckoAppShell_reg
 #endif
 
 #ifdef JNI_BINDINGS
   xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_registerJavaUiThread", &f_Java_org_mozilla_gecko_GeckoAppShell_registerJavaUiThread);
 #endif
 
 #ifdef JNI_STUBS
 
-typedef void (*Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t)(JNIEnv *, jclass);
+typedef void (*Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t)(JNIEnv *, jclass, jobject);
 static Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit;
 extern "C" NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv * arg0, jclass arg1) {
+Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv * arg0, jclass arg1, jobject arg2) {
     if (!f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit) {
         arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
                        "JNI Function called before it was loaded");
         return ;
     }
-     f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit(arg0, arg1);
+     f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit(arg0, arg1, arg2);
 }
 #endif
 
 #ifdef JNI_BINDINGS
   xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_nativeInit", &f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit);
 #endif
 
 #ifdef JNI_STUBS
--- a/netwerk/base/src/Tickler.cpp
+++ b/netwerk/base/src/Tickler.cpp
@@ -76,17 +76,17 @@ Tickler::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mTimer);
   MOZ_ASSERT(!mActive);
   MOZ_ASSERT(!mThread);
   MOZ_ASSERT(!mFD);
 
   if (AndroidBridge::HasEnv()) {
-      mozilla::widget::android::GeckoAppShell::EnableNetworkNotifications();
+      widget::GeckoAppShell::EnableNetworkNotifications();
   }
 
   mFD = PR_OpenUDPSocket(PR_AF_INET);
   if (!mFD)
     return NS_ERROR_FAILURE;
 
   // make sure new socket has a ttl of 1
   // failure is not fatal.
--- a/netwerk/protocol/device/CameraStreamImpl.cpp
+++ b/netwerk/protocol/device/CameraStreamImpl.cpp
@@ -85,14 +85,14 @@ bool CameraStreamImpl::Init(const nsCStr
 {
     mCallback = aCallback;
     mWidth = width;
     mHeight = height;
     return AndroidBridge::Bridge()->InitCamera(contentType, camera, &mWidth, &mHeight, &mFps);
 }
 
 void CameraStreamImpl::Close() {
-    mozilla::widget::android::GeckoAppShell::CloseCamera();
+    mozilla::widget::GeckoAppShell::CloseCamera();
     mCallback = nullptr;
 }
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/system/android/nsAndroidNetworkLinkService.cpp
+++ b/netwerk/system/android/nsAndroidNetworkLinkService.cpp
@@ -5,18 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAndroidNetworkLinkService.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/Services.h"
 
 #include "AndroidBridge.h"
 
-using namespace mozilla::widget::android;
-
 NS_IMPL_ISUPPORTS(nsAndroidNetworkLinkService,
                   nsINetworkLinkService)
 
 nsAndroidNetworkLinkService::nsAndroidNetworkLinkService()
 {
 }
 
 nsAndroidNetworkLinkService::~nsAndroidNetworkLinkService()
@@ -28,36 +26,36 @@ nsAndroidNetworkLinkService::GetIsLinkUp
 {
   if (!mozilla::AndroidBridge::Bridge()) {
     // Fail soft here and assume a connection exists
     NS_WARNING("GetIsLinkUp is not supported without a bridge connection");
     *aIsUp = true;
     return NS_OK;
   }
 
-  *aIsUp = mozilla::widget::android::GeckoAppShell::IsNetworkLinkUp();
+  *aIsUp = mozilla::widget::GeckoAppShell::IsNetworkLinkUp();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidNetworkLinkService::GetLinkStatusKnown(bool *aIsKnown)
 {
   NS_ENSURE_TRUE(mozilla::AndroidBridge::Bridge(), NS_ERROR_NOT_IMPLEMENTED);
 
-  *aIsKnown = mozilla::widget::android::GeckoAppShell::IsNetworkLinkKnown();
+  *aIsKnown = mozilla::widget::GeckoAppShell::IsNetworkLinkKnown();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidNetworkLinkService::GetLinkType(uint32_t *aLinkType)
 {
   NS_ENSURE_ARG_POINTER(aLinkType);
 
   if (!mozilla::AndroidBridge::Bridge()) {
     // Fail soft here and assume a connection exists
     NS_WARNING("GetLinkType is not supported without a bridge connection");
     *aLinkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
     return NS_OK;
   }
 
-  *aLinkType = mozilla::widget::android::GeckoAppShell::NetworkLinkType();
+  *aLinkType = mozilla::widget::GeckoAppShell::NetworkLinkType();
   return NS_OK;
 }
--- a/toolkit/components/alerts/nsAlertsService.cpp
+++ b/toolkit/components/alerts/nsAlertsService.cpp
@@ -6,17 +6,16 @@
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "nsXULAppAPI.h"
 
 #include "nsAlertsService.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
-using namespace mozilla::widget::android;
 #else
 
 #include "nsXPCOM.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMWindow.h"
 #include "nsPromiseFlatString.h"
 #include "nsToolkitCompsCID.h"
 
@@ -131,17 +130,17 @@ NS_IMETHODIMP nsAlertsService::CloseAler
 {
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     ContentChild* cpc = ContentChild::GetSingleton();
     cpc->SendCloseAlert(nsAutoString(aAlertName), IPC::Principal(aPrincipal));
     return NS_OK;
   }
 
 #ifdef MOZ_WIDGET_ANDROID
-  mozilla::widget::android::GeckoAppShell::CloseNotification(aAlertName);
+  widget::GeckoAppShell::CloseNotification(aAlertName);
   return NS_OK;
 #else
 
   // Try the system notification service.
   nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID));
   if (sysAlerts) {
     return sysAlerts->CloseAlert(aAlertName, nullptr);
   }
@@ -152,26 +151,26 @@ NS_IMETHODIMP nsAlertsService::CloseAler
 
 
 NS_IMETHODIMP nsAlertsService::OnProgress(const nsAString & aAlertName,
                                           int64_t aProgress,
                                           int64_t aProgressMax,
                                           const nsAString & aAlertText)
 {
 #ifdef MOZ_WIDGET_ANDROID
-  mozilla::widget::android::GeckoAppShell::AlertsProgressListener_OnProgress(aAlertName,
-                                                                             aProgress, aProgressMax,
-                                                                             aAlertText);
+  widget::GeckoAppShell::AlertsProgressListener_OnProgress(aAlertName,
+                                                           aProgress, aProgressMax,
+                                                           aAlertText);
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif // !MOZ_WIDGET_ANDROID
 }
 
 NS_IMETHODIMP nsAlertsService::OnCancel(const nsAString & aAlertName)
 {
 #ifdef MOZ_WIDGET_ANDROID
-  mozilla::widget::android::GeckoAppShell::CloseNotification(aAlertName);
+  widget::GeckoAppShell::CloseNotification(aAlertName);
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif // !MOZ_WIDGET_ANDROID
 }
--- a/toolkit/components/downloads/nsDownloadManager.cpp
+++ b/toolkit/components/downloads/nsDownloadManager.cpp
@@ -52,17 +52,16 @@
 #endif
 
 #ifdef XP_MACOSX
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
-using namespace mozilla::widget::android;
 #endif
 
 #ifdef MOZ_WIDGET_GTK
 #include <gtk/gtk.h>
 #endif
 
 using namespace mozilla;
 using mozilla::downloads::GenerateGUID;
@@ -2782,17 +2781,17 @@ nsDownload::SetState(DownloadState aStat
           if (addToRecentDocs) {
             nsCOMPtr<nsIMIMEInfo> mimeInfo;
             nsAutoCString contentType;
             GetMIMEInfo(getter_AddRefs(mimeInfo));
 
             if (mimeInfo)
               mimeInfo->GetMIMEType(contentType);
 
-            mozilla::widget::android::DownloadsIntegration::ScanMedia(path, NS_ConvertUTF8toUTF16(contentType));
+            mozilla::widget::DownloadsIntegration::ScanMedia(path, NS_ConvertUTF8toUTF16(contentType));
           }
 #else
           if (addToRecentDocs && !mPrivate) {
 #ifdef XP_WIN
             ::SHAddToRecentDocs(SHARD_PATHW, path.get());
 #elif defined(MOZ_WIDGET_GTK)
             GtkRecentManager* manager = gtk_recent_manager_get_default();
 
--- a/toolkit/components/jsdownloads/src/DownloadPlatform.cpp
+++ b/toolkit/components/jsdownloads/src/DownloadPlatform.cpp
@@ -79,17 +79,17 @@ nsresult DownloadPlatform::DownloadDone(
   if (aTarget && NS_SUCCEEDED(aTarget->GetPath(path))) {
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_ANDROID)
     // On Windows and Gtk, add the download to the system's "recent documents"
     // list, with a pref to disable.
     {
       bool addToRecentDocs = Preferences::GetBool(PREF_BDM_ADDTORECENTDOCS);
 #ifdef MOZ_WIDGET_ANDROID
       if (addToRecentDocs) {
-        mozilla::widget::android::DownloadsIntegration::ScanMedia(path, NS_ConvertUTF8toUTF16(aContentType));
+        mozilla::widget::DownloadsIntegration::ScanMedia(path, NS_ConvertUTF8toUTF16(aContentType));
       }
 #else
       if (addToRecentDocs && !aIsPrivate) {
 #ifdef XP_WIN
         ::SHAddToRecentDocs(SHARD_PATHW, path.get());
 #elif defined(MOZ_WIDGET_GTK)
         GtkRecentManager* manager = gtk_recent_manager_get_default();
 
--- a/toolkit/components/parentalcontrols/nsParentalControlsServiceAndroid.cpp
+++ b/toolkit/components/parentalcontrols/nsParentalControlsServiceAndroid.cpp
@@ -9,17 +9,17 @@
 #include "nsIFile.h"
 
 NS_IMPL_ISUPPORTS(nsParentalControlsService, nsIParentalControlsService)
 
 nsParentalControlsService::nsParentalControlsService() :
   mEnabled(false)
 {
   if (mozilla::AndroidBridge::HasEnv()) {
-    mEnabled = mozilla::widget::android::RestrictedProfiles::IsUserRestricted();
+    mEnabled = mozilla::widget::RestrictedProfiles::IsUserRestricted();
   }
 }
 
 nsParentalControlsService::~nsParentalControlsService()
 {
 }
 
 NS_IMETHODIMP
@@ -85,15 +85,15 @@ nsParentalControlsService::IsAllowed(int
 
   if (mozilla::AndroidBridge::HasEnv()) {
     nsAutoCString url;
     if (aUri) {
       rv = aUri->GetSpec(url);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    *_retval = mozilla::widget::android::RestrictedProfiles::IsAllowed(aAction,
+    *_retval = mozilla::widget::RestrictedProfiles::IsAllowed(aAction,
                                                     NS_ConvertUTF8toUTF16(url));
     return rv;
   }
 
   return NS_ERROR_NOT_AVAILABLE;
 }
--- a/toolkit/xre/nsAndroidStartup.cpp
+++ b/toolkit/xre/nsAndroidStartup.cpp
@@ -70,14 +70,14 @@ GeckoStart(void *data, const nsXREAppDat
     }
     targs.AppendElement(static_cast<char *>(nullptr));
 
     int result = XRE_main(targs.Length() - 1, targs.Elements(), appData, 0);
 
     if (result)
         LOG("XRE_main returned %d", result);
 
-    mozilla::widget::android::GeckoAppShell::NotifyXreExit();
+    mozilla::widget::GeckoAppShell::NotifyXreExit();
 
     free(targs[0]);
     nsMemory::Free(data);
     return;
 }
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1696,17 +1696,17 @@ static nsresult LaunchChild(nsINativeApp
     gRestartArgc = 1;
     gRestartArgv[gRestartArgc] = nullptr;
 #endif
   }
 
   SaveToEnv("MOZ_LAUNCHED_CHILD=1");
 
 #if defined(MOZ_WIDGET_ANDROID)
-  mozilla::widget::android::GeckoAppShell::ScheduleRestart();
+  mozilla::widget::GeckoAppShell::ScheduleRestart();
 #else
 #if defined(XP_MACOSX)
   CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
   uint32_t restartMode = 0;
   restartMode = gRestartMode;
   LaunchChildMac(gRestartArgc, gRestartArgv, restartMode);
 #else
   nsCOMPtr<nsIFile> lf;
@@ -1834,17 +1834,17 @@ ProfileLockedDialog(nsIFile* aProfileDir
 
     nsCOMPtr<nsIPromptService> ps
       (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
     NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
 
     if (aUnlocker) {
       int32_t button;
 #ifdef MOZ_WIDGET_ANDROID
-      mozilla::widget::android::GeckoAppShell::KillAnyZombies();
+      mozilla::widget::GeckoAppShell::KillAnyZombies();
       button = 0;
 #else
       const uint32_t flags =
         (nsIPromptService::BUTTON_TITLE_IS_STRING *
          nsIPromptService::BUTTON_POS_0) +
         (nsIPromptService::BUTTON_TITLE_CANCEL *
          nsIPromptService::BUTTON_POS_1);
 
@@ -1863,17 +1863,17 @@ ProfileLockedDialog(nsIFile* aProfileDir
 
         SaveFileToEnv("XRE_PROFILE_PATH", aProfileDir);
         SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", aProfileLocalDir);
 
         return LaunchChild(aNative);
       }
     } else {
 #ifdef MOZ_WIDGET_ANDROID
-      if (mozilla::widget::android::GeckoAppShell::UnlockProfile()) {
+      if (mozilla::widget::GeckoAppShell::UnlockProfile()) {
         return NS_LockProfilePath(aProfileDir, aProfileLocalDir, 
                                   nullptr, aResult);
       }
 #else
       rv = ps->Alert(nullptr, killTitle, killMessage);
       NS_ENSURE_SUCCESS_LOG(rv, rv);
 #endif
     }
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -268,17 +268,17 @@ void BuildJavaThreadJSObject(JSStreamWri
             }
             break;
           }
           // the first time around, open the sample object and frames array
           if (firstRun) {
             firstRun = false;
 
             double sampleTime =
-              mozilla::widget::android::GeckoJavaSampler::GetSampleTimeJavaProfiling(0, sampleId);
+              mozilla::widget::GeckoJavaSampler::GetSampleTimeJavaProfiling(0, sampleId);
 
             b.BeginObject();
               b.NameValue("time", sampleTime);
 
               b.Name("frames");
               b.BeginArray();
           }
           // add a frame to the sample
@@ -345,21 +345,21 @@ void TableTicker::StreamJSObject(JSStrea
         if (os) {
           nsRefPtr<ProfileSaveEvent> pse = new ProfileSaveEvent(SubProcessCallback, &closure);
           os->NotifyObservers(pse, "profiler-subprocess", nullptr);
         }
       }
 
   #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
       if (ProfileJava()) {
-        mozilla::widget::android::GeckoJavaSampler::PauseJavaProfiling();
+        mozilla::widget::GeckoJavaSampler::PauseJavaProfiling();
 
         BuildJavaThreadJSObject(b);
 
-        mozilla::widget::android::GeckoJavaSampler::UnpauseJavaProfiling();
+        mozilla::widget::GeckoJavaSampler::UnpauseJavaProfiling();
       }
   #endif
 
       SetPaused(false);
     b.EndArray();
 
   b.EndObject();
 }
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -22,17 +22,16 @@
 #include "nsProfilerStartParams.h"
 #include "mozilla/Services.h"
 #include "nsThreadUtils.h"
 #include "ProfilerMarkers.h"
 #include "nsXULAppAPI.h"
 
 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   #include "AndroidBridge.h"
-  using namespace mozilla::widget::android;
 #endif
 
 mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack;
 mozilla::ThreadLocal<TableTicker *> tlsTicker;
 mozilla::ThreadLocal<void *> tlsStackTop;
 // We need to track whether we've been initialized otherwise
 // we end up using tlsStack without initializing it.
 // Because tlsStack is totally opaque to us we can't reuse
@@ -784,17 +783,17 @@ void mozilla_sampler_start(int aProfileE
 
 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   if (t->ProfileJava()) {
     int javaInterval = aInterval;
     // Java sampling doesn't accuratly keep up with 1ms sampling
     if (javaInterval < 10) {
       aInterval = 10;
     }
-    mozilla::widget::android::GeckoJavaSampler::StartJavaProfiling(javaInterval, 1000);
+    mozilla::widget::GeckoJavaSampler::StartJavaProfiling(javaInterval, 1000);
   }
 #endif
 
   if (t->AddMainThreadIO()) {
     if (!sInterposeObserver) {
       // Lazily create IO interposer observer
       sInterposeObserver = new mozilla::ProfilerIOInterposeObserver();
     }
--- a/uriloader/exthandler/android/nsAndroidHandlerApp.cpp
+++ b/uriloader/exthandler/android/nsAndroidHandlerApp.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: c++; c-basic-offset: 2; 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/. */
 
 #include "nsAndroidHandlerApp.h"
 #include "AndroidBridge.h"
 
-using namespace mozilla::widget::android;
+using namespace mozilla;
 
 
 NS_IMPL_ISUPPORTS(nsAndroidHandlerApp, nsIHandlerApp, nsISharingHandlerApp)
 
 nsAndroidHandlerApp::nsAndroidHandlerApp(const nsAString& aName,
                                          const nsAString& aDescription,
                                          const nsAString& aPackageName,
                                          const nsAString& aClassName,
@@ -71,20 +71,21 @@ nsAndroidHandlerApp::Equals(nsIHandlerAp
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidHandlerApp::LaunchWithURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext)
 {
   nsCString uriSpec;
   aURI->GetSpec(uriSpec);
-  return mozilla::widget::android::GeckoAppShell::OpenUriExternal
-    (NS_ConvertUTF8toUTF16(uriSpec), NS_ConvertUTF8toUTF16(mMimeType), mPackageName, mClassName, mAction) ?
-    NS_OK : NS_ERROR_FAILURE;
+  return widget::GeckoAppShell::OpenUriExternal(
+          uriSpec, mMimeType, mPackageName, mClassName,
+          mAction, EmptyString()) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsAndroidHandlerApp::Share(const nsAString & data, const nsAString & title)
 {
-  return mozilla::widget::android::GeckoAppShell::OpenUriExternal(data, NS_ConvertUTF8toUTF16(mMimeType),
-                    mPackageName, mClassName, mAction) ? NS_OK : NS_ERROR_FAILURE;
+  return widget::GeckoAppShell::OpenUriExternal(
+          data, mMimeType, mPackageName, mClassName,
+          mAction, EmptyString()) ? NS_OK : NS_ERROR_FAILURE;
 }
 
--- a/uriloader/exthandler/android/nsExternalSharingAppService.cpp
+++ b/uriloader/exthandler/android/nsExternalSharingAppService.cpp
@@ -26,18 +26,18 @@ nsExternalSharingAppService::~nsExternal
 
 NS_IMETHODIMP
 nsExternalSharingAppService::ShareWithDefault(const nsAString & data,
                                               const nsAString & mime,
                                               const nsAString & title)
 {
   NS_NAMED_LITERAL_STRING(sendAction, "android.intent.action.SEND");
   const nsString emptyString = EmptyString();
-  return mozilla::widget::android::GeckoAppShell::OpenUriExternal(data,
-           mime, emptyString,emptyString, sendAction, title) ? NS_OK : NS_ERROR_FAILURE;
+  return widget::GeckoAppShell::OpenUriExternal(data,
+      mime, emptyString, emptyString, sendAction, title) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsExternalSharingAppService::GetSharingApps(const nsAString & aMIMEType,
                                             uint32_t *aLen,
                                             nsISharingHandlerApp ***aHandlers)
 {
   nsresult rv;
--- a/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
+++ b/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
@@ -5,17 +5,17 @@
 #include "nsMIMEInfoAndroid.h"
 #include "AndroidBridge.h"
 #include "nsAndroidHandlerApp.h"
 #include "nsArrayUtils.h"
 #include "nsISupportsUtils.h"
 #include "nsStringEnumerator.h"
 #include "nsNetUtil.h"
 
-using namespace mozilla::widget::android;
+using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(nsMIMEInfoAndroid, nsIMIMEInfo, nsIHandlerInfo)
 
 NS_IMETHODIMP
 nsMIMEInfoAndroid::LaunchDefaultWithFile(nsIFile* aFile)
 {
   return LaunchWithFile(aFile);
 }
@@ -31,17 +31,19 @@ nsMIMEInfoAndroid::LoadUriInternal(nsIUR
 
   nsAutoString mimeType;
   if (mType.Equals(uriScheme) || mType.Equals(uriSpec)) {
     mimeType = EmptyString();
   } else {
     mimeType = NS_ConvertUTF8toUTF16(mType);
   }
 
-  if (GeckoAppShell::OpenUriExternal(NS_ConvertUTF8toUTF16(uriSpec), mimeType)) {
+  if (widget::GeckoAppShell::OpenUriExternal(
+      NS_ConvertUTF8toUTF16(uriSpec), mimeType, EmptyString(),
+      EmptyString(), EmptyString(), EmptyString())) {
     return NS_OK;
   }
   return NS_ERROR_FAILURE;
 }
 
 bool
 nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType,
                                           nsMIMEInfoAndroid** aMimeInfo)
--- a/widget/android/APZCCallbackHandler.cpp
+++ b/widget/android/APZCCallbackHandler.cpp
@@ -22,21 +22,21 @@ using mozilla::layers::FrameMetrics;
 using mozilla::layers::ScrollableLayerGuid;
 
 namespace mozilla {
 namespace widget {
 namespace android {
 
 StaticRefPtr<APZCCallbackHandler> APZCCallbackHandler::sInstance;
 
-NativePanZoomController*
-APZCCallbackHandler::SetNativePanZoomController(jobject obj)
+NativePanZoomController::LocalRef
+APZCCallbackHandler::SetNativePanZoomController(NativePanZoomController::Param obj)
 {
-    NativePanZoomController* old = mNativePanZoomController;
-    mNativePanZoomController = NativePanZoomController::Wrap(obj);
+    NativePanZoomController::LocalRef old = mNativePanZoomController;
+    mNativePanZoomController = obj;
     return old;
 }
 
 void
 APZCCallbackHandler::NotifyDefaultPrevented(uint64_t aInputBlockId,
                                             bool aDefaultPrevented)
 {
     if (!AndroidBridge::IsJavaUiThread()) {
--- a/widget/android/APZCCallbackHandler.h
+++ b/widget/android/APZCCallbackHandler.h
@@ -2,47 +2,48 @@
  * 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/. */
 
 #ifndef APZCCallbackHandler_h__
 #define APZCCallbackHandler_h__
 
 #include "mozilla/layers/GeckoContentController.h"
+#include "mozilla/StaticPtr.h"
 #include "mozilla/TimeStamp.h"
 #include "GeneratedJNIWrappers.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace widget {
 namespace android {
 
 class APZCCallbackHandler MOZ_FINAL : public mozilla::layers::GeckoContentController
 {
 private:
     static StaticRefPtr<APZCCallbackHandler> sInstance;
-    NativePanZoomController* mNativePanZoomController;
+    NativePanZoomController::GlobalRef mNativePanZoomController;
 
 private:
     APZCCallbackHandler()
       : mNativePanZoomController(nullptr)
     {}
 
     nsIDOMWindowUtils* GetDOMWindowUtils();
 
 public:
     static APZCCallbackHandler* GetInstance() {
         if (sInstance.get() == nullptr) {
             sInstance = new APZCCallbackHandler();
         }
         return sInstance.get();
     }
 
-    NativePanZoomController* SetNativePanZoomController(jobject obj);
+    NativePanZoomController::LocalRef SetNativePanZoomController(NativePanZoomController::Param obj);
     void NotifyDefaultPrevented(uint64_t aInputBlockId, 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;
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -41,18 +41,19 @@
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsIHttpChannel.h"
 
 #include "MediaCodec.h"
 #include "SurfaceTexture.h"
 
 using namespace mozilla;
-using namespace mozilla::widget::android;
 using namespace mozilla::gfx;
+using namespace mozilla::jni;
+using namespace mozilla::widget;
 
 AndroidBridge* AndroidBridge::sBridge;
 pthread_t AndroidBridge::sJavaUiThread = -1;
 static unsigned sJavaEnvThreadIndex = 0;
 static jobject sGlobalContext = nullptr;
 static void JavaThreadDetachFunc(void *arg);
 
 // This is a dummy class that can be used in the template for android::sp
@@ -61,32 +62,39 @@ class AndroidRefable {
     void decStrong(void* thing) { }
 };
 
 // This isn't in AndroidBridge.h because including StrongPointer.h there is gross
 static android::sp<AndroidRefable> (*android_SurfaceTexture_getNativeWindow)(JNIEnv* env, jobject surfaceTexture) = nullptr;
 
 jclass AndroidBridge::GetClassGlobalRef(JNIEnv* env, const char* className)
 {
-    jobject classLocalRef = env->FindClass(className);
-    if (!classLocalRef) {
-        ALOG(">>> FATAL JNI ERROR! FindClass(className=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
+    // First try the default class loader.
+    auto classRef = ClassObject::LocalRef::Adopt(
+            env, env->FindClass(className));
+
+    if (!classRef && sBridge && sBridge->mClassLoader) {
+        // If the default class loader failed but we have an app class loader, try that.
+        // Clear the pending exception from failed FindClass call above.
+        env->ExceptionClear();
+        classRef = ClassObject::LocalRef::Adopt(env,
+                env->CallObjectMethod(sBridge->mClassLoader.Get(),
+                                      sBridge->mClassLoaderLoadClass,
+                                      Param<String>::Type(className, env).Get()));
+    }
+
+    if (!classRef) {
+        ALOG(">>> FATAL JNI ERROR! FindClass(className=\"%s\") failed. "
+             "Did ProGuard optimize away something it shouldn't have?",
              className);
         env->ExceptionDescribe();
         MOZ_CRASH();
     }
-    jobject classGlobalRef = env->NewGlobalRef(classLocalRef);
-    if (!classGlobalRef) {
-        env->ExceptionDescribe();
-        MOZ_CRASH();
-    }
-    // Local ref no longer necessary because we have a global ref.
-    env->DeleteLocalRef(classLocalRef);
-    classLocalRef = nullptr;
-    return static_cast<jclass>(classGlobalRef);
+
+    return ClassObject::GlobalRef(env, classRef).Forget();
 }
 
 jmethodID AndroidBridge::GetMethodID(JNIEnv* env, jclass jClass,
                               const char* methodName, const char* methodType)
 {
    jmethodID methodID = env->GetMethodID(jClass, methodName, methodType);
    if (!methodID) {
        ALOG(">>> FATAL JNI ERROR! GetMethodID(methodName=\"%s\", "
@@ -136,46 +144,51 @@ jfieldID AndroidBridge::GetStaticFieldID
              fieldName, fieldType);
         env->ExceptionDescribe();
         MOZ_CRASH();
     }
     return fieldID;
 }
 
 void
-AndroidBridge::ConstructBridge(JNIEnv *jEnv)
+AndroidBridge::ConstructBridge(JNIEnv *jEnv, Object::Param clsLoader)
 {
     /* NSS hack -- bionic doesn't handle recursive unloads correctly,
      * because library finalizer functions are called with the dynamic
      * linker lock still held.  This results in a deadlock when trying
      * to call dlclose() while we're already inside dlclose().
      * Conveniently, NSS has an env var that can prevent it from unloading.
      */
     putenv("NSS_DISABLE_UNLOAD=1");
 
     PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
 
     AndroidBridge *bridge = new AndroidBridge();
-    if (!bridge->Init(jEnv)) {
+    if (!bridge->Init(jEnv, clsLoader)) {
         delete bridge;
     }
     sBridge = bridge;
 }
 
 bool
-AndroidBridge::Init(JNIEnv *jEnv)
+AndroidBridge::Init(JNIEnv *jEnv, Object::Param clsLoader)
 {
     ALOG_BRIDGE("AndroidBridge::Init");
     jEnv->GetJavaVM(&mJavaVM);
     if (!mJavaVM) {
         MOZ_CRASH(); // Nothing we can do here
     }
 
     AutoLocalJNIFrame jniFrame(jEnv);
 
+    mClassLoader = Object::GlobalRef(jEnv, clsLoader);
+    mClassLoaderLoadClass = GetMethodID(
+            jEnv, jEnv->GetObjectClass(clsLoader.Get()),
+            "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+
     mJNIEnv = nullptr;
     mThread = -1;
     mGLControllerObj = nullptr;
     mOpenedGraphicsLibraries = false;
     mHasNativeBitmapAccess = false;
     mHasNativeWindowAccess = false;
     mHasNativeWindowFallback = false;
 
@@ -223,24 +236,16 @@ AndroidBridge::Init(JNIEnv *jEnv)
 
     AutoJNIClass inputStream(jEnv, "java/io/InputStream");
     jInputStream = inputStream.getGlobalRef();
     jClose = inputStream.getMethod("close", "()V");
     jAvailable = inputStream.getMethod("available", "()I");
 
     InitAndroidJavaWrappers(jEnv);
 
-    if (mAPIVersion >= 16 /* Jelly Bean */) {
-        sdk::InitMediaCodecStubs(jEnv);
-    }
-
-    if (mAPIVersion >= 14 /* ICS */) {
-        sdk::InitSurfaceTextureStubs(jEnv);
-    }
-
     // jEnv should NOT be cached here by anything -- the jEnv here
     // is not valid for the real gecko main thread, which is set
     // at SetMainThread time.
 
     return true;
 }
 
 bool
@@ -429,138 +434,119 @@ getHandlersFromStringArray(JNIEnv *aJNIE
 bool
 AndroidBridge::GetHandlersForMimeType(const nsAString& aMimeType,
                                       nsIMutableArray *aHandlersArray,
                                       nsIHandlerApp **aDefaultApp,
                                       const nsAString& aAction)
 {
     ALOG_BRIDGE("AndroidBridge::GetHandlersForMimeType");
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jobjectArray arr =
-      mozilla::widget::android::GeckoAppShell::GetHandlersForMimeTypeWrapper(aMimeType, aAction);
+    auto arr = GeckoAppShell::GetHandlersForMimeTypeWrapper(aMimeType, aAction);
     if (!arr)
         return false;
 
-    jsize len = env->GetArrayLength(arr);
+    JNIEnv* const env = arr.Env();
+    jsize len = env->GetArrayLength(arr.Get());
 
     if (!aHandlersArray)
         return len > 0;
 
-    getHandlersFromStringArray(env, arr, len, aHandlersArray,
+    getHandlersFromStringArray(env, arr.Get(), len, aHandlersArray,
                                aDefaultApp, aAction,
                                NS_ConvertUTF16toUTF8(aMimeType));
     return true;
 }
 
 bool
 AndroidBridge::GetHandlersForURL(const nsAString& aURL,
                                  nsIMutableArray* aHandlersArray,
                                  nsIHandlerApp **aDefaultApp,
                                  const nsAString& aAction)
 {
     ALOG_BRIDGE("AndroidBridge::GetHandlersForURL");
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jobjectArray arr = mozilla::widget::android::GeckoAppShell::GetHandlersForURLWrapper(aURL, aAction);
+    auto arr = GeckoAppShell::GetHandlersForURLWrapper(aURL, aAction);
     if (!arr)
         return false;
 
-    jsize len = env->GetArrayLength(arr);
+    JNIEnv* const env = arr.Env();
+    jsize len = env->GetArrayLength(arr.Get());
 
     if (!aHandlersArray)
         return len > 0;
 
-    getHandlersFromStringArray(env, arr, len, aHandlersArray,
+    getHandlersFromStringArray(env, arr.Get(), len, aHandlersArray,
                                aDefaultApp, aAction);
     return true;
 }
 
 void
 AndroidBridge::GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType)
 {
     ALOG_BRIDGE("AndroidBridge::GetMimeTypeFromExtensions");
 
-    JNIEnv *env = GetJNIEnv();
+    auto jstrType = GeckoAppShell::GetMimeTypeFromExtensionsWrapper(aFileExt);
 
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jstring jstrType = mozilla::widget::android::GeckoAppShell::GetMimeTypeFromExtensionsWrapper
-                                                                (NS_ConvertUTF8toUTF16(aFileExt));
-    if (!jstrType) {
-        return;
+    if (jstrType) {
+        aMimeType = jstrType;
     }
-    nsJNIString jniStr(jstrType, env);
-    CopyUTF16toUTF8(jniStr.get(), aMimeType);
 }
 
 void
 AndroidBridge::GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt)
 {
     ALOG_BRIDGE("AndroidBridge::GetExtensionFromMimeType");
 
-    JNIEnv *env = GetJNIEnv();
+    auto jstrExt = GeckoAppShell::GetExtensionFromMimeTypeWrapper(aMimeType);
 
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jstring jstrExt = mozilla::widget::android::GeckoAppShell::GetExtensionFromMimeTypeWrapper
-                                                             (NS_ConvertUTF8toUTF16(aMimeType));
-    if (!jstrExt) {
-        return;
+    if (jstrExt) {
+        aFileExt = nsCString(jstrExt);
     }
-    nsJNIString jniStr(jstrExt, env);
-    CopyUTF16toUTF8(jniStr.get(), aFileExt);
 }
 
 bool
 AndroidBridge::GetClipboardText(nsAString& aText)
 {
     ALOG_BRIDGE("AndroidBridge::GetClipboardText");
 
-    JNIEnv *env = GetJNIEnv();
+    auto text = Clipboard::GetClipboardTextWrapper();
 
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jstring result = Clipboard::GetClipboardTextWrapper();
-    if (!result)
-        return false;
-
-    nsJNIString jniStr(result, env);
-    aText.Assign(jniStr);
-    return true;
+    if (text) {
+        aText = nsString(text);
+    }
+    return !!text;
 }
 
 void
 AndroidBridge::ShowAlertNotification(const nsAString& aImageUrl,
                                      const nsAString& aAlertTitle,
                                      const nsAString& aAlertText,
                                      const nsAString& aAlertCookie,
                                      nsIObserver *aAlertListener,
                                      const nsAString& aAlertName)
 {
     if (nsAppShell::gAppShell && aAlertListener) {
         // This will remove any observers already registered for this id
         nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeAddObserver(aAlertName, aAlertListener));
     }
 
-    mozilla::widget::android::GeckoAppShell::ShowAlertNotificationWrapper
+    GeckoAppShell::ShowAlertNotificationWrapper
            (aImageUrl, aAlertTitle, aAlertText, aAlertCookie, aAlertName);
 }
 
 int
 AndroidBridge::GetDPI()
 {
     static int sDPI = 0;
     if (sDPI)
         return sDPI;
 
     const int DEFAULT_DPI = 160;
 
-    sDPI = mozilla::widget::android::GeckoAppShell::GetDpiWrapper();
+    sDPI = GeckoAppShell::GetDpiWrapper();
     if (!sDPI) {
         return DEFAULT_DPI;
     }
 
     return sDPI;
 }
 
 int
@@ -570,17 +556,17 @@ AndroidBridge::GetScreenDepth()
 
     static int sDepth = 0;
     if (sDepth)
         return sDepth;
 
     const int DEFAULT_DEPTH = 16;
 
     if (HasEnv()) {
-        sDepth = mozilla::widget::android::GeckoAppShell::GetScreenDepthWrapper();
+        sDepth = GeckoAppShell::GetScreenDepthWrapper();
     }
     if (!sDepth)
         return DEFAULT_DEPTH;
 
     return sDepth;
 }
 void
 AndroidBridge::Vibrate(const nsTArray<uint32_t>& aPattern)
@@ -588,35 +574,34 @@ AndroidBridge::Vibrate(const nsTArray<ui
     ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
 
     uint32_t len = aPattern.Length();
     if (!len) {
         ALOG_BRIDGE("  invalid 0-length array");
         return;
     }
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
     // It's clear if this worth special-casing, but it creates less
     // java junk, so dodges the GC.
     if (len == 1) {
         jlong d = aPattern[0];
         if (d < 0) {
             ALOG_BRIDGE("  invalid vibration duration < 0");
             return;
         }
-        mozilla::widget::android::GeckoAppShell::Vibrate1(d);
+        GeckoAppShell::Vibrate1(d);
         return;
     }
 
     // First element of the array vibrate() expects is how long to wait
     // *before* vibrating.  For us, this is always 0.
 
+    JNIEnv *env = GetJNIEnv();
+    AutoLocalJNIFrame jniFrame(env, 1);
+
     jlongArray array = env->NewLongArray(len + 1);
     if (!array) {
         ALOG_BRIDGE("  failed to allocate array");
         return;
     }
 
     jlong* elts = env->GetLongArrayElements(array, nullptr);
     elts[0] = 0;
@@ -626,143 +611,126 @@ AndroidBridge::Vibrate(const nsTArray<ui
             ALOG_BRIDGE("  invalid vibration duration < 0");
             env->ReleaseLongArrayElements(array, elts, JNI_ABORT);
             return;
         }
         elts[i + 1] = d;
     }
     env->ReleaseLongArrayElements(array, elts, 0);
 
-    mozilla::widget::android::GeckoAppShell::VibrateA(array, -1/*don't repeat*/);
+    GeckoAppShell::VibrateA(LongArray::Ref::From(array), -1 /* don't repeat */);
 }
 
 void
 AndroidBridge::GetSystemColors(AndroidSystemColors *aColors)
 {
 
     NS_ASSERTION(aColors != nullptr, "AndroidBridge::GetSystemColors: aColors is null!");
     if (!aColors)
         return;
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
-    jintArray arr = mozilla::widget::android::GeckoAppShell::GetSystemColoursWrapper();
+    auto arr = GeckoAppShell::GetSystemColoursWrapper();
     if (!arr)
         return;
 
-    uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr));
-    jint *elements = env->GetIntArrayElements(arr, 0);
+    JNIEnv* const env = arr.Env();
+    uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr.Get()));
+    jint *elements = env->GetIntArrayElements(arr.Get(), 0);
 
     uint32_t colorsCount = sizeof(AndroidSystemColors) / sizeof(nscolor);
     if (len < colorsCount)
         colorsCount = len;
 
     // Convert Android colors to nscolor by switching R and B in the ARGB 32 bit value
     nscolor *colors = (nscolor*)aColors;
 
     for (uint32_t i = 0; i < colorsCount; i++) {
         uint32_t androidColor = static_cast<uint32_t>(elements[i]);
         uint8_t r = (androidColor & 0x00ff0000) >> 16;
         uint8_t b = (androidColor & 0x000000ff);
         colors[i] = (androidColor & 0xff00ff00) | (b << 16) | r;
     }
 
-    env->ReleaseIntArrayElements(arr, elements, 0);
+    env->ReleaseIntArrayElements(arr.Get(), elements, 0);
 }
 
 void
 AndroidBridge::GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf)
 {
     ALOG_BRIDGE("AndroidBridge::GetIconForExtension");
     NS_ASSERTION(aBuf != nullptr, "AndroidBridge::GetIconForExtension: aBuf is null!");
     if (!aBuf)
         return;
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
-    jbyteArray arr = mozilla::widget::android::GeckoAppShell::GetIconForExtensionWrapper
+    auto arr = GeckoAppShell::GetIconForExtensionWrapper
                                              (NS_ConvertUTF8toUTF16(aFileExt), aIconSize);
 
     NS_ASSERTION(arr != nullptr, "AndroidBridge::GetIconForExtension: Returned pixels array is null!");
     if (!arr)
         return;
 
-    uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr));
-    jbyte *elements = env->GetByteArrayElements(arr, 0);
+    JNIEnv* const env = arr.Env();
+    uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr.Get()));
+    jbyte *elements = env->GetByteArrayElements(arr.Get(), 0);
 
     uint32_t bufSize = aIconSize * aIconSize * 4;
     NS_ASSERTION(len == bufSize, "AndroidBridge::GetIconForExtension: Pixels array is incomplete!");
     if (len == bufSize)
         memcpy(aBuf, elements, bufSize);
 
-    env->ReleaseByteArrayElements(arr, elements, 0);
+    env->ReleaseByteArrayElements(arr.Get(), elements, 0);
 }
 
 void
-AndroidBridge::SetLayerClient(JNIEnv* env, jobject jobj)
+AndroidBridge::SetLayerClient(GeckoLayerClient::Param jobj)
 {
     // if resetting is true, that means Android destroyed our GeckoApp activity
     // and we had to recreate it, but all the Gecko-side things were not destroyed.
     // We therefore need to link up the new java objects to Gecko, and that's what
     // we do here.
     bool resetting = (mLayerClient != nullptr);
 
-    if (resetting) {
-        // clear out the old layer client
-        delete mLayerClient;
-        mLayerClient = nullptr;
-    }
-
-    mLayerClient = mozilla::widget::android::GeckoLayerClient::Wrap(jobj);
+    mLayerClient = jobj;
 
     if (resetting) {
         // since we are re-linking the new java objects to Gecko, we need to get
         // the viewport from the compositor (since the Java copy was thrown away)
         // and we do that by setting the first-paint flag.
         nsWindow::ForceIsFirstPaint();
     }
 }
 
 void
 AndroidBridge::RegisterCompositor(JNIEnv *env)
 {
-    if (mGLControllerObj != nullptr && !mGLControllerObj->isNull()) {
+    if (mGLControllerObj != nullptr) {
         // we already have this set up, no need to do it again
         return;
     }
 
-    jobject glController = LayerView::RegisterCompositorWrapper();
-    if (!glController) {
-        return;
-    }
-
-    mGLControllerObj = GLController::Wrap(glController);
+    mGLControllerObj = GLController::LocalRef(
+            LayerView::RegisterCompositorWrapper());
 }
 
 EGLSurface
 AndroidBridge::CreateEGLSurfaceForCompositor()
 {
     if (!jEGLSurfacePointerField) {
         return nullptr;
     }
     MOZ_ASSERT(mGLControllerObj, "AndroidBridge::CreateEGLSurfaceForCompositor called with a null GL controller ref");
 
-    JNIEnv* env = GetJNIForThread(); // called on the compositor thread
+    auto eglSurface = mGLControllerObj->CreateEGLSurfaceForCompositorWrapper();
+    if (!eglSurface) {
+        return nullptr;
+    }
 
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jobject eglSurface = mGLControllerObj->CreateEGLSurfaceForCompositorWrapper();
-    if (!eglSurface)
-        return nullptr;
-
-    EGLSurface ret = reinterpret_cast<EGLSurface>(env->GetIntField(eglSurface, jEGLSurfacePointerField));
-    return ret;
+    JNIEnv* const env = GetJNIForThread(); // called on the compositor thread
+    return reinterpret_cast<EGLSurface>(
+            env->GetIntField(eglSurface.Get(), jEGLSurfacePointerField));
 }
 
 bool
 AndroidBridge::GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* jEnv /* = nullptr */)
 {
     ALOG_BRIDGE("AndroidBridge::GetStaticIntField %s", fieldName);
 
     if (!jEnv) {
@@ -1002,72 +970,67 @@ AndroidBridge::ValidateBitmap(jobject bi
         return false;
 
     return true;
 }
 
 bool
 AndroidBridge::InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps)
 {
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jintArray arr = mozilla::widget::android::GeckoAppShell::InitCameraWrapper
+    auto arr = GeckoAppShell::InitCameraWrapper
       (NS_ConvertUTF8toUTF16(contentType), (int32_t) camera, (int32_t) *width, (int32_t) *height);
 
     if (!arr)
         return false;
 
-    jint *elements = env->GetIntArrayElements(arr, 0);
+    JNIEnv* const env = arr.Env();
+    jint *elements = env->GetIntArrayElements(arr.Get(), 0);
 
     *width = elements[1];
     *height = elements[2];
     *fps = elements[3];
 
     bool res = elements[0] == 1;
 
-    env->ReleaseIntArrayElements(arr, elements, 0);
+    env->ReleaseIntArrayElements(arr.Get(), elements, 0);
 
     return res;
 }
 
 void
 AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
 {
     ALOG_BRIDGE("AndroidBridge::GetCurrentBatteryInformation");
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
     // To prevent calling too many methods through JNI, the Java method returns
     // an array of double even if we actually want a double and a boolean.
-    jdoubleArray arr = mozilla::widget::android::GeckoAppShell::GetCurrentBatteryInformationWrapper();
-    if (!arr || env->GetArrayLength(arr) != 3) {
+    auto arr = GeckoAppShell::GetCurrentBatteryInformationWrapper();
+
+    JNIEnv* const env = arr.Env();
+    if (!arr || env->GetArrayLength(arr.Get()) != 3) {
         return;
     }
 
-    jdouble* info = env->GetDoubleArrayElements(arr, 0);
+    jdouble* info = env->GetDoubleArrayElements(arr.Get(), 0);
 
     aBatteryInfo->level() = info[0];
     aBatteryInfo->charging() = info[1] == 1.0f;
     aBatteryInfo->remainingTime() = info[2];
 
-    env->ReleaseDoubleArrayElements(arr, info, 0);
+    env->ReleaseDoubleArrayElements(arr.Get(), info, 0);
 }
 
 void
 AndroidBridge::HandleGeckoMessage(JSContext* cx, JS::HandleObject object)
 {
     ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
 
     JNIEnv* const env = GetJNIEnv();
-    AutoLocalJNIFrame jniFrame(env, 1);
-    const jobject message =
-        mozilla::widget::CreateNativeJSContainer(env, cx, object);
+    auto message = Object::LocalRef::Adopt(env,
+        mozilla::widget::CreateNativeJSContainer(env, cx, object));
     GeckoAppShell::HandleGeckoMessageWrapper(message);
 }
 
 nsresult
 AndroidBridge::GetSegmentInfoForText(const nsAString& aText,
                                      nsIMobileMessageCallback* aRequest)
 {
 #ifndef MOZ_WEBSMS_BACKEND
@@ -1113,41 +1076,41 @@ AndroidBridge::SendMessage(const nsAStri
                            nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::SendMessage");
 
     uint32_t requestId;
     if (!QueueSmsRequest(aRequest, &requestId))
         return;
 
-    mozilla::widget::android::GeckoAppShell::SendMessageWrapper(aNumber, aMessage, requestId);
+    GeckoAppShell::SendMessageWrapper(aNumber, aMessage, requestId);
 }
 
 void
 AndroidBridge::GetMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::GetMessage");
 
     uint32_t requestId;
     if (!QueueSmsRequest(aRequest, &requestId))
         return;
 
-    mozilla::widget::android::GeckoAppShell::GetMessageWrapper(aMessageId, requestId);
+    GeckoAppShell::GetMessageWrapper(aMessageId, requestId);
 }
 
 void
 AndroidBridge::DeleteMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::DeleteMessage");
 
     uint32_t requestId;
     if (!QueueSmsRequest(aRequest, &requestId))
         return;
 
-    mozilla::widget::android::GeckoAppShell::DeleteMessageWrapper(aMessageId, requestId);
+    GeckoAppShell::DeleteMessageWrapper(aMessageId, requestId);
 }
 
 void
 AndroidBridge::CreateMessageList(const dom::mobilemessage::SmsFilterData& aFilter, bool aReverse,
                                  nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::CreateMessageList");
 
@@ -1168,33 +1131,34 @@ AndroidBridge::CreateMessageList(const d
         jstring elem = NewJavaString(&jniFrame, aFilter.numbers()[i]);
         env->SetObjectArrayElement(numbers, i, elem);
         env->DeleteLocalRef(elem);
     }
 
     int64_t startDate = aFilter.hasStartDate() ? aFilter.startDate() : -1;
     int64_t endDate = aFilter.hasEndDate() ? aFilter.endDate() : -1;
     GeckoAppShell::CreateMessageListWrapper(startDate, endDate,
-                                            numbers, aFilter.numbers().Length(),
+                                            ObjectArray::Ref::From(numbers),
+                                            aFilter.numbers().Length(),
                                             aFilter.delivery(),
                                             aFilter.hasRead(), aFilter.read(),
                                             aFilter.threadId(),
                                             aReverse, requestId);
 }
 
 void
 AndroidBridge::GetNextMessageInList(int32_t aListId, nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::GetNextMessageInList");
 
     uint32_t requestId;
     if (!QueueSmsRequest(aRequest, &requestId))
         return;
 
-    mozilla::widget::android::GeckoAppShell::GetNextMessageInListWrapper(aListId, requestId);
+    GeckoAppShell::GetNextMessageInListWrapper(aListId, requestId);
 }
 
 bool
 AndroidBridge::QueueSmsRequest(nsIMobileMessageCallback* aRequest, uint32_t* aRequestIdOut)
 {
     MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
     MOZ_ASSERT(aRequest && aRequestIdOut);
 
@@ -1227,62 +1191,56 @@ AndroidBridge::DequeueSmsRequest(uint32_
     return mSmsRequests[aRequestId].forget();
 }
 
 void
 AndroidBridge::GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
 {
     ALOG_BRIDGE("AndroidBridge::GetCurrentNetworkInformation");
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
     // To prevent calling too many methods through JNI, the Java method returns
     // an array of double even if we actually want an integer, a boolean, and an integer.
 
-    jdoubleArray arr = mozilla::widget::android::GeckoAppShell::GetCurrentNetworkInformationWrapper();
-    if (!arr || env->GetArrayLength(arr) != 3) {
+    auto arr = GeckoAppShell::GetCurrentNetworkInformationWrapper();
+
+    JNIEnv* const env = arr.Env();
+    if (!arr || env->GetArrayLength(arr.Get()) != 3) {
         return;
     }
 
-    jdouble* info = env->GetDoubleArrayElements(arr, 0);
+    jdouble* info = env->GetDoubleArrayElements(arr.Get(), 0);
 
     aNetworkInfo->type() = info[0];
     aNetworkInfo->isWifi() = info[1] == 1.0f;
     aNetworkInfo->dhcpGateway() = info[2];
 
-    env->ReleaseDoubleArrayElements(arr, info, 0);
+    env->ReleaseDoubleArrayElements(arr.Get(), info, 0);
 }
 
 void *
 AndroidBridge::LockBitmap(jobject bitmap)
 {
     JNIEnv *env = GetJNIEnv();
 
-    AutoLocalJNIFrame jniFrame(env, 0);
-
     int err;
     void *buf;
 
     if ((err = AndroidBitmap_lockPixels(env, bitmap, &buf)) != 0) {
         ALOG_BRIDGE("AndroidBitmap_lockPixels failed! (error %d)", err);
         buf = nullptr;
     }
 
     return buf;
 }
 
 void
 AndroidBridge::UnlockBitmap(jobject bitmap)
 {
     JNIEnv *env = GetJNIEnv();
 
-    AutoLocalJNIFrame jniFrame(env, 0);
-
     int err;
 
     if ((err = AndroidBitmap_unlockPixels(env, bitmap)) != 0)
         ALOG_BRIDGE("AndroidBitmap_unlockPixels failed! (error %d)", err);
 }
 
 
 bool
@@ -1415,47 +1373,47 @@ AndroidBridge::LockWindow(void *window, 
         *stride = info.s;
     } else return false;
 
     return true;
 }
 
 jobject
 AndroidBridge::GetGlobalContextRef() {
-    if (sGlobalContext == nullptr) {
-        JNIEnv *env = GetJNIForThread();
-
-        AutoLocalJNIFrame jniFrame(env, 4);
-
-        jobject context = mozilla::widget::android::GeckoAppShell::GetContext();
-        if (!context) {
-            ALOG_BRIDGE("%s: Could not GetContext()", __FUNCTION__);
-            return 0;
-        }
-        jclass contextClass = env->FindClass("android/content/Context");
-        if (!contextClass) {
-            ALOG_BRIDGE("%s: Could not find Context class.", __FUNCTION__);
-            return 0;
-        }
-        jmethodID mid = env->GetMethodID(contextClass, "getApplicationContext",
-                                         "()Landroid/content/Context;");
-        if (!mid) {
-            ALOG_BRIDGE("%s: Could not find getApplicationContext.", __FUNCTION__);
-            return 0;
-        }
-        jobject appContext = env->CallObjectMethod(context, mid);
-        if (!appContext) {
-            ALOG_BRIDGE("%s: getApplicationContext failed.", __FUNCTION__);
-            return 0;
-        }
-
-        sGlobalContext = env->NewGlobalRef(appContext);
-        MOZ_ASSERT(sGlobalContext);
+    if (sGlobalContext) {
+        return sGlobalContext;
     }
 
+    JNIEnv* const env = GetJNIForThread();
+    AutoLocalJNIFrame jniFrame(env, 4);
+
+    auto context = GeckoAppShell::GetContext();
+    if (!context) {
+        ALOG_BRIDGE("%s: Could not GetContext()", __FUNCTION__);
+        return 0;
+    }
+    jclass contextClass = env->FindClass("android/content/Context");
+    if (!contextClass) {
+        ALOG_BRIDGE("%s: Could not find Context class.", __FUNCTION__);
+        return 0;
+    }
+    jmethodID mid = env->GetMethodID(contextClass, "getApplicationContext",
+                                     "()Landroid/content/Context;");
+    if (!mid) {
+        ALOG_BRIDGE("%s: Could not find getApplicationContext.", __FUNCTION__);
+        return 0;
+    }
+    jobject appContext = env->CallObjectMethod(context.Get(), mid);
+    if (!appContext) {
+        ALOG_BRIDGE("%s: getApplicationContext failed.", __FUNCTION__);
+        return 0;
+    }
+
+    sGlobalContext = env->NewGlobalRef(appContext);
+    MOZ_ASSERT(sGlobalContext);
     return sGlobalContext;
 }
 
 bool
 AndroidBridge::UnlockWindow(void* window)
 {
     int err;
 
@@ -1471,101 +1429,91 @@ AndroidBridge::UnlockWindow(void* window
     }
 
     return true;
 }
 
 void
 AndroidBridge::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect)
 {
-    mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
-    if (!client)
+    if (!mLayerClient) {
         return;
+    }
 
-    client->SetFirstPaintViewport((float)aOffset.x, (float)aOffset.y, aZoom.scale,
-                                  aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
+    mLayerClient->SetFirstPaintViewport(float(aOffset.x), float(aOffset.y), aZoom.scale,
+            aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
 }
 
 void
 AndroidBridge::SetPageRect(const CSSRect& aCssPageRect)
 {
-    mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
-    if (!client)
+    if (!mLayerClient) {
         return;
+    }
 
-    client->SetPageRect(aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
+    mLayerClient->SetPageRect(aCssPageRect.x, aCssPageRect.y,
+                              aCssPageRect.XMost(), aCssPageRect.YMost());
 }
 
 void
 AndroidBridge::SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
                                 bool aLayersUpdated, ParentLayerPoint& aScrollOffset, CSSToParentLayerScale& aScale,
                                 LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
 {
-    mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
-    if (!client) {
+    if (!mLayerClient) {
         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return;
     }
 
-    jobject viewTransformJObj = client->SyncViewportInfo(aDisplayPort.x, aDisplayPort.y,
-                                aDisplayPort.width, aDisplayPort.height,
-                                aDisplayResolution.scale, aLayersUpdated);
-    NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
+    ViewTransform::LocalRef viewTransform = mLayerClient->SyncViewportInfo(
+            aDisplayPort.x, aDisplayPort.y,
+            aDisplayPort.width, aDisplayPort.height,
+            aDisplayResolution.scale, aLayersUpdated);
 
-    if (!viewTransformJObj) {
-        return;
-    }
+    NS_ABORT_IF_FALSE(viewTransform, "No view transform object!");
 
-    ViewTransform* viewTransform = ViewTransform::Wrap(viewTransformJObj);
-    aScrollOffset = ParentLayerPoint(viewTransform->getx(), viewTransform->gety());
-    aScale.scale = viewTransform->getscale();
-    aFixedLayerMargins.top = viewTransform->getfixedLayerMarginTop();
-    aFixedLayerMargins.right = viewTransform->getfixedLayerMarginRight();
-    aFixedLayerMargins.bottom = viewTransform->getfixedLayerMarginBottom();
-    aFixedLayerMargins.left = viewTransform->getfixedLayerMarginLeft();
-    aOffset.x = viewTransform->getoffsetX();
-    aOffset.y = viewTransform->getoffsetY();
-    delete viewTransform;
+    aScrollOffset = ParentLayerPoint(viewTransform->X(), viewTransform->Y());
+    aScale.scale = viewTransform->Scale();
+    aFixedLayerMargins.top = viewTransform->FixedLayerMarginTop();
+    aFixedLayerMargins.right = viewTransform->FixedLayerMarginRight();
+    aFixedLayerMargins.bottom = viewTransform->FixedLayerMarginBottom();
+    aFixedLayerMargins.left = viewTransform->FixedLayerMarginLeft();
+    aOffset.x = viewTransform->OffsetX();
+    aOffset.y = viewTransform->OffsetY();
 }
 
 void AndroidBridge::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
                                      bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
                                      bool aIsFirstPaint, LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
 {
-    mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
-    if (!client) {
+    if (!mLayerClient) {
         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return;
     }
 
     // convert the displayport rect from scroll-relative CSS pixels to document-relative device pixels
     LayerRect dpUnrounded = aDisplayPort * aDisplayResolution;
     dpUnrounded += LayerPoint::FromUnknownPoint(aScrollOffset.ToUnknownPoint());
     LayerIntRect dp = gfx::RoundedToInt(dpUnrounded);
 
-    jobject viewTransformJObj = client->SyncFrameMetrics(aScrollOffset.x, aScrollOffset.y, aZoom,
-                                                         aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(),
-                                                         aLayersUpdated, dp.x, dp.y, dp.width, dp.height, aDisplayResolution.scale,
-                                                         aIsFirstPaint);
+    ViewTransform::LocalRef viewTransform = mLayerClient->SyncFrameMetrics(
+            aScrollOffset.x, aScrollOffset.y, aZoom,
+            aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(),
+            aLayersUpdated, dp.x, dp.y, dp.width, dp.height, aDisplayResolution.scale,
+            aIsFirstPaint);
+
+    NS_ABORT_IF_FALSE(viewTransform, "No view transform object!");
 
-    NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
-    if (!viewTransformJObj) {
-        return;
-    }
-    ViewTransform* viewTransform = ViewTransform::Wrap(viewTransformJObj);
+    aFixedLayerMargins.top = viewTransform->FixedLayerMarginTop();
+    aFixedLayerMargins.right = viewTransform->FixedLayerMarginRight();
+    aFixedLayerMargins.bottom = viewTransform->FixedLayerMarginBottom();
+    aFixedLayerMargins.left = viewTransform->FixedLayerMarginLeft();
 
-    aFixedLayerMargins.top = viewTransform->getfixedLayerMarginTop();
-    aFixedLayerMargins.right = viewTransform->getfixedLayerMarginRight();
-    aFixedLayerMargins.bottom = viewTransform->getfixedLayerMarginBottom();
-    aFixedLayerMargins.left = viewTransform->getfixedLayerMarginLeft();
-
-    aOffset.x = viewTransform->getoffsetX();
-    aOffset.y = viewTransform->getoffsetY();
-
-    delete viewTransform;
+    aOffset.x = viewTransform->OffsetX();
+    aOffset.y = viewTransform->OffsetY();
 }
 
 AndroidBridge::AndroidBridge()
   : mLayerClient(nullptr)
 {
 }
 
 AndroidBridge::~AndroidBridge()
@@ -1659,17 +1607,17 @@ JavaThreadDetachFunc(void *arg)
     vm->DetachCurrentThread();
 }
 
 uint32_t
 AndroidBridge::GetScreenOrientation()
 {
     ALOG_BRIDGE("AndroidBridge::GetScreenOrientation");
 
-    int16_t orientation = mozilla::widget::android::GeckoAppShell::GetScreenOrientationWrapper();
+    int16_t orientation = GeckoAppShell::GetScreenOrientationWrapper();
 
     if (!orientation)
         return dom::eScreenOrientation_None;
 
     return static_cast<dom::ScreenOrientation>(orientation);
 }
 
 void
@@ -1683,30 +1631,23 @@ AndroidBridge::GetProxyForURI(const nsAC
                               const nsACString & aScheme,
                               const nsACString & aHost,
                               const int32_t      aPort,
                               nsACString & aResult)
 {
     if (!HasEnv()) {
         return NS_ERROR_FAILURE;
     }
-    JNIEnv* env = GetJNIEnv();
 
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jstring jstrRet =
-      mozilla::widget::android::GeckoAppShell::GetProxyForURIWrapper(NS_ConvertUTF8toUTF16(aSpec),
-                                                                   NS_ConvertUTF8toUTF16(aScheme),
-                                                                     NS_ConvertUTF8toUTF16(aHost),
-                                                                                           aPort);
+    auto jstrRet = GeckoAppShell::GetProxyForURIWrapper(aSpec, aScheme, aHost, aPort);
 
     if (!jstrRet)
         return NS_ERROR_FAILURE;
 
-    nsJNIString jniStr(jstrRet, env);
-    CopyUTF16toUTF8(jniStr, aResult);
+    aResult = nsCString(jstrRet);
     return NS_OK;
 }
 
 
 /* attribute nsIAndroidBrowserApp browserApp; */
 NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
 {
     if (nsAppShell::gAppShell)
@@ -1723,63 +1664,52 @@ NS_IMETHODIMP nsAndroidBridge::SetBrowse
 
 void
 AndroidBridge::AddPluginView(jobject view, const LayoutDeviceRect& rect, bool isFullScreen) {
     nsWindow* win = nsWindow::TopWindow();
     if (!win)
         return;
 
     CSSRect cssRect = rect / win->GetDefaultScale();
-    mozilla::widget::android::GeckoAppShell::AddPluginViewWrapper(view, cssRect.x, cssRect.y,
-                                                cssRect.width, cssRect.height, isFullScreen);
+    GeckoAppShell::AddPluginViewWrapper(Object::Ref::From(view), cssRect.x, cssRect.y,
+                                        cssRect.width, cssRect.height, isFullScreen);
 }
 
 extern "C"
 __attribute__ ((visibility("default")))
 jobject JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *env, jclass, jlong size);
 
 bool
 AndroidBridge::GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult)
 {
-    JNIEnv* env = GetJNIForThread();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
-    jstring jstrThreadName =
-      mozilla::widget::android::GeckoJavaSampler::GetThreadNameJavaProfilingWrapper(aThreadId);
+    auto jstrThreadName = GeckoJavaSampler::GetThreadNameJavaProfilingWrapper(aThreadId);
 
     if (!jstrThreadName)
         return false;
 
-    nsJNIString jniStr(jstrThreadName, env);
-    CopyUTF16toUTF8(jniStr.get(), aResult);
+    aResult = nsCString(jstrThreadName);
     return true;
 }
 
 bool
 AndroidBridge::GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId,
                                           uint32_t aFrameId, nsCString & aResult)
 {
-    JNIEnv* env = GetJNIForThread();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
-    jstring jstrSampleName = mozilla::widget::android::GeckoJavaSampler::GetFrameNameJavaProfilingWrapper
-      									(aThreadId, aSampleId, aFrameId);
+    auto jstrSampleName = GeckoJavaSampler::GetFrameNameJavaProfilingWrapper
+            (aThreadId, aSampleId, aFrameId);
 
     if (!jstrSampleName)
         return false;
 
-    nsJNIString jniStr(jstrSampleName, env);
-    CopyUTF16toUTF8(jniStr.get(), aResult);
+    aResult = nsCString(jstrSampleName);
     return true;
 }
 
-nsresult AndroidBridge::CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer, bool &shouldStore)
+nsresult AndroidBridge::CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, Object::Param buffer, bool &shouldStore)
 {
     nsresult rv;
     float scale = 1.0;
 
     if (!buffer)
         return NS_ERROR_FAILURE;
 
     // take a screenshot, as wide as possible, proportional to the destination size
@@ -1843,17 +1773,17 @@ nsresult AndroidBridge::CaptureThumbnail
     nsRect r(nsPresContext::CSSPixelsToAppUnits(srcX / scale),
              nsPresContext::CSSPixelsToAppUnits(srcY / scale),
              nsPresContext::CSSPixelsToAppUnits(srcW / scale),
              nsPresContext::CSSPixelsToAppUnits(srcH / scale));
 
     bool is24bit = (GetScreenDepth() == 24);
     uint32_t stride = bufW * (is24bit ? 4 : 2);
 
-    uint8_t* data = static_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
+    uint8_t* data = static_cast<uint8_t*>(env->GetDirectBufferAddress(buffer.Get()));
     if (!data)
         return NS_ERROR_FAILURE;
 
     MOZ_ASSERT(gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO),
                "Need BackendType::CAIRO support");
     RefPtr<DrawTarget> dt =
         Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                          data,
@@ -1877,23 +1807,23 @@ nsresult AndroidBridge::CaptureThumbnail
     return NS_OK;
 }
 
 void
 AndroidBridge::GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort)
 {
 
     ALOG_BRIDGE("Enter: %s", __PRETTY_FUNCTION__);
-    JNIEnv* env = GetJNIEnv();
-    if (!mLayerClient || mLayerClient->isNull()) {
-
+    if (!mLayerClient) {
         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return;
     }
-    AutoLocalJNIFrame jniFrame(env, 0);
+
+    JNIEnv* const env = GetJNIEnv();
+    AutoLocalJNIFrame jniFrame(env, 1);
 
     float x, y, width, height,
         pageLeft, pageTop, pageRight, pageBottom,
         cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
         zoom;
     metrics->GetX(&x);
     metrics->GetY(&y);
     metrics->GetWidth(&width);
@@ -1903,44 +1833,36 @@ AndroidBridge::GetDisplayPort(bool aPage
     metrics->GetPageRight(&pageRight);
     metrics->GetPageBottom(&pageBottom);
     metrics->GetCssPageLeft(&cssPageLeft);
     metrics->GetCssPageTop(&cssPageTop);
     metrics->GetCssPageRight(&cssPageRight);
     metrics->GetCssPageBottom(&cssPageBottom);
     metrics->GetZoom(&zoom);
 
-    ImmutableViewportMetrics jmetrics = ImmutableViewportMetrics(pageLeft, pageTop, pageRight, pageBottom,
-                                                                 cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
-                                                                 x, y, x + width, y + height,
-                                                                 zoom);
+    auto jmetrics = ImmutableViewportMetrics::New(
+            pageLeft, pageTop, pageRight, pageBottom,
+            cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
+            x, y, x + width, y + height,
+            zoom);
 
-    jobject jobj = mLayerClient->GetDisplayPort(aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, jmetrics.wrappedObject());
-    if (!jobj) {
-        ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
-        return;
-    }
-    DisplayPortMetrics* displayPortMetrics = DisplayPortMetrics::Wrap(jobj);
+    DisplayPortMetrics::LocalRef displayPortMetrics = mLayerClient->GetDisplayPort(
+            aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, jmetrics);
 
-    AndroidRectF rect(env, displayPortMetrics->getMPosition());
-    if (jniFrame.CheckForException()) {
+    if (!displayPortMetrics) {
         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return;
     }
 
-    float resolution = displayPortMetrics->getResolution();
-    if (jniFrame.CheckForException()) {
-        ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
-        return;
-    }
+    AndroidRectF rect(env, displayPortMetrics->MPosition().Get());
+    float resolution = displayPortMetrics->Resolution();
 
     *displayPort = new nsAndroidDisplayport(rect, resolution);
     (*displayPort)->AddRef();
 
-    delete displayPortMetrics;
     ALOG_BRIDGE("Exit: %s", __PRETTY_FUNCTION__);
 }
 
 void
 AndroidBridge::ContentDocumentChanged()
 {
     if (!mLayerClient) {
         return;
@@ -1953,45 +1875,40 @@ AndroidBridge::IsContentDocumentDisplaye
 {
     if (!mLayerClient)
         return false;
 
     return mLayerClient->IsContentDocumentDisplayed();
 }
 
 bool
-AndroidBridge::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution,
-                                         bool aDrawingCritical, ParentLayerPoint& aScrollOffset, CSSToParentLayerScale& aZoom)
+AndroidBridge::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
+                                         const LayerRect& aDisplayPort, float aDisplayResolution,
+                                         bool aDrawingCritical, ParentLayerPoint& aScrollOffset,
+                                         CSSToParentLayerScale& aZoom)
 {
-    mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
-    if (!client) {
+    if (!mLayerClient) {
         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return false;
     }
 
-    jobject progressiveUpdateDataJObj = client->ProgressiveUpdateCallback(aHasPendingNewThebesContent,
-                                                                   (float)aDisplayPort.x,
-                                                                   (float)aDisplayPort.y,
-                                                                   (float)aDisplayPort.width,
-                                                                   (float)aDisplayPort.height,
-                                                                          aDisplayResolution,
-                                                                         !aDrawingCritical);
-
-    NS_ABORT_IF_FALSE(progressiveUpdateDataJObj, "No progressive update data!");
+    ProgressiveUpdateData::LocalRef progressiveUpdateData =
+            mLayerClient->ProgressiveUpdateCallback(aHasPendingNewThebesContent,
+                                                    (float)aDisplayPort.x,
+                                                    (float)aDisplayPort.y,
+                                                    (float)aDisplayPort.width,
+                                                    (float)aDisplayPort.height,
+                                                           aDisplayResolution,
+                                                          !aDrawingCritical);
 
-    ProgressiveUpdateData* progressiveUpdateData = ProgressiveUpdateData::Wrap(progressiveUpdateDataJObj);
+    aScrollOffset.x = progressiveUpdateData->X();
+    aScrollOffset.y = progressiveUpdateData->Y();
+    aZoom.scale = progressiveUpdateData->Scale();
 
-    aScrollOffset.x = progressiveUpdateData->getx();
-    aScrollOffset.y = progressiveUpdateData->gety();
-    aZoom.scale = progressiveUpdateData->getscale();
-
-    bool ret = progressiveUpdateData->getabort();
-    delete progressiveUpdateData;
-
-    return ret;
+    return progressiveUpdateData->Abort();
 }
 
 void
 AndroidBridge::PostTaskToUiThread(Task* aTask, int aDelayMs)
 {
     // add the new task into the mDelayedTaskQueue, sorted with
     // the earliest task first in the queue
     DelayedTask* newTask = new DelayedTask(aTask, aDelayMs);
@@ -2035,56 +1952,55 @@ AndroidBridge::RunDelayedUiThreadTasks()
         Task* task = nextTask->GetTask();
         delete nextTask;
 
         task->Run();
     }
     return -1;
 }
 
-jobject AndroidBridge::ChannelCreate(jobject stream) {
-    JNIEnv *env = GetJNIForThread();
-    env->PushLocalFrame(1);
-    jobject channel = env->CallStaticObjectMethod(sBridge->jReadableByteChannel, sBridge->jChannelCreate, stream);
-    return env->PopLocalFrame(channel);
+Object::LocalRef AndroidBridge::ChannelCreate(Object::Param stream) {
+    JNIEnv* const env = GetJNIForThread();
+    auto rv = Object::LocalRef::Adopt(env, env->CallStaticObjectMethod(
+            sBridge->jReadableByteChannel, sBridge->jChannelCreate, stream.Get()));
+    HandleUncaughtException(env);
+    return rv;
 }
 
-void AndroidBridge::InputStreamClose(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    AutoLocalJNIFrame jniFrame(env, 1);
-    env->CallVoidMethod(obj, sBridge->jClose);
+void AndroidBridge::InputStreamClose(Object::Param obj) {
+    JNIEnv* const env = GetJNIForThread();
+    env->CallVoidMethod(obj.Get(), sBridge->jClose);
+    HandleUncaughtException(env);
 }
 
-uint32_t AndroidBridge::InputStreamAvailable(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    AutoLocalJNIFrame jniFrame(env, 1);
-    return env->CallIntMethod(obj, sBridge->jAvailable);
+uint32_t AndroidBridge::InputStreamAvailable(Object::Param obj) {
+    JNIEnv* const env = GetJNIForThread();
+    auto rv = env->CallIntMethod(obj.Get(), sBridge->jAvailable);
+    HandleUncaughtException(env);
+    return rv;
 }
 
-nsresult AndroidBridge::InputStreamRead(jobject obj, char *aBuf, uint32_t aCount, uint32_t *aRead) {
-    JNIEnv *env = GetJNIForThread();
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jobject arr =  env->NewDirectByteBuffer(aBuf, aCount);
-    jint read = env->CallIntMethod(obj, sBridge->jByteBufferRead, arr);
+nsresult AndroidBridge::InputStreamRead(Object::Param obj, char *aBuf, uint32_t aCount, uint32_t *aRead) {
+    JNIEnv* const env = GetJNIForThread();
+    auto arr = Object::LocalRef::Adopt(env, env->NewDirectByteBuffer(aBuf, aCount));
+    jint read = env->CallIntMethod(obj.Get(), sBridge->jByteBufferRead, arr.Get());
 
     if (env->ExceptionCheck()) {
         env->ExceptionClear();
         return NS_ERROR_FAILURE;
     }
 
     if (read <= 0) {
         *aRead = 0;
         return NS_OK;
     }
     *aRead = read;
     return NS_OK;
 }
 
 nsresult AndroidBridge::GetExternalPublicDirectory(const nsAString& aType, nsAString& aPath) {
-    AutoLocalJNIFrame frame(1);
-    const jstring path = GeckoAppShell::GetExternalPublicDirectory(aType);
+    auto path = GeckoAppShell::GetExternalPublicDirectory(aType);
     if (!path) {
         return NS_ERROR_NOT_AVAILABLE;
     }
-    nsJNIString pathStr(path, frame.GetEnv());
-    aPath.Assign(pathStr);
+    aPath = nsString(path);
     return NS_OK;
 }
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -10,16 +10,17 @@
 #include <android/log.h>
 #include <cstdlib>
 #include <pthread.h>
 
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 
 #include "GeneratedJNIWrappers.h"
+#include "AndroidJavaWrappers.h"
 
 #include "nsIMutableArray.h"
 #include "nsIMIMEInfo.h"
 #include "nsColor.h"
 #include "gfxRect.h"
 
 #include "nsIAndroidBridge.h"
 #include "nsIMobileMessageCallback.h"
@@ -132,17 +133,17 @@ public:
     static void RegisterJavaUiThread() {
         sJavaUiThread = pthread_self();
     }
 
     static bool IsJavaUiThread() {
         return pthread_equal(pthread_self(), sJavaUiThread);
     }
 
-    static void ConstructBridge(JNIEnv *jEnv);
+    static void ConstructBridge(JNIEnv *jEnv, jni::Object::Param clsLoader);
 
     static AndroidBridge *Bridge() {
         return sBridge;
     }
 
     static JavaVM *GetVM() {
         MOZ_ASSERT(sBridge);
         return sBridge->mJavaVM;
@@ -182,26 +183,26 @@ public:
     // us to use.  toolkit/xre/nsAndroidStartup.cpp calls
     // SetMainThread.
     bool SetMainThread(pthread_t thr);
 
     /* These are all implemented in Java */
     bool GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult);
     bool GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId, uint32_t aFrameId, nsCString & aResult);
 
-    nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer, bool &shouldStore);
+    nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jni::Object::Param buffer, bool &shouldStore);
     void GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort);
     void ContentDocumentChanged();
     bool IsContentDocumentDisplayed();
 
     bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical,
                                    mozilla::ParentLayerPoint& aScrollOffset, mozilla::CSSToParentLayerScale& aZoom);
 
-    void SetLayerClient(JNIEnv* env, jobject jobj);
-    mozilla::widget::android::GeckoLayerClient* GetLayerClient() { return mLayerClient; }
+    void SetLayerClient(widget::GeckoLayerClient::Param jobj);
+    const widget::GeckoLayerClient::Ref& GetLayerClient() { return mLayerClient; }
 
     bool GetHandlersForURL(const nsAString& aURL,
                            nsIMutableArray* handlersArray = nullptr,
                            nsIHandlerApp **aDefaultApp = nullptr,
                            const nsAString& aAction = EmptyString());
 
     bool GetHandlersForMimeType(const nsAString& aMimeType,
                                 nsIMutableArray* handlersArray = nullptr,
@@ -328,46 +329,46 @@ public:
     static jstring NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string);
 
     static jclass GetClassGlobalRef(JNIEnv* env, const char* className);
     static jfieldID GetFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType);
     static jfieldID GetStaticFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType);
     static jmethodID GetMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType);
     static jmethodID GetStaticMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType);
 
-    static jobject ChannelCreate(jobject);
+    static jni::Object::LocalRef ChannelCreate(jni::Object::Param);
 
-    static void InputStreamClose(jobject obj);
-    static uint32_t InputStreamAvailable(jobject obj);
-    static nsresult InputStreamRead(jobject obj, char *aBuf, uint32_t aCount, uint32_t *aRead);
+    static void InputStreamClose(jni::Object::Param obj);
+    static uint32_t InputStreamAvailable(jni::Object::Param obj);
+    static nsresult InputStreamRead(jni::Object::Param obj, char *aBuf, uint32_t aCount, uint32_t *aRead);
 
     static nsresult GetExternalPublicDirectory(const nsAString& aType, nsAString& aPath);
 
 protected:
     static pthread_t sJavaUiThread;
     static AndroidBridge* sBridge;
     nsTArray<nsCOMPtr<nsIMobileMessageCallback> > mSmsRequests;
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
     // the JNIEnv for the main thread
     JNIEnv *mJNIEnv;
     pthread_t mThread;
 
-    mozilla::widget::android::GeckoLayerClient *mLayerClient;
+    widget::GeckoLayerClient::GlobalRef mLayerClient;
 
     // the android.telephony.SmsMessage class
     jclass mAndroidSmsMessageClass;
 
     AndroidBridge();
     ~AndroidBridge();
 
     void InitStubs(JNIEnv *jEnv);
-    bool Init(JNIEnv *jEnv);
+    bool Init(JNIEnv *jEnv, jni::Object::Param clsLoader);
 
     bool mOpenedGraphicsLibraries;
     void OpenGraphicsLibraries();
     void* GetNativeSurface(JNIEnv* env, jobject surface);
 
     bool mHasNativeBitmapAccess;
     bool mHasNativeWindowAccess;
     bool mHasNativeWindowFallback;
@@ -399,21 +400,24 @@ protected:
 
     // For native surface stuff
     jclass jSurfaceClass;
     jfieldID jSurfacePointerField;
 
     jclass jLayerView;
 
     jfieldID jEGLSurfacePointerField;
-    mozilla::widget::android::GLController *mGLControllerObj;
+    widget::GLController::GlobalRef mGLControllerObj;
 
     // some convinient types to have around
     jclass jStringClass;
 
+    jni::Object::GlobalRef mClassLoader;
+    jmethodID mClassLoaderLoadClass;
+
     // calls we've dlopened from libjnigraphics.so
     int (* AndroidBitmap_getInfo)(JNIEnv *env, jobject bitmap, void *info);
     int (* AndroidBitmap_lockPixels)(JNIEnv *env, jobject bitmap, void **buffer);
     int (* AndroidBitmap_unlockPixels)(JNIEnv *env, jobject bitmap);
 
     void* (*ANativeWindow_fromSurface)(JNIEnv *env, jobject surface);
     void* (*ANativeWindow_fromSurfaceTexture)(JNIEnv *env, jobject surfaceTexture);
     void (*ANativeWindow_release)(void *window);
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -43,35 +43,36 @@
 #include "AndroidSurfaceTexture.h"
 #include "GeckoProfiler.h"
 #include "nsMemoryPressure.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::layers;
+using namespace mozilla::widget;
 using namespace mozilla::widget::android;
 
 /* Forward declare all the JNI methods as extern "C" */
 
 extern "C" {
 /*
  * Incoming JNI methods
  */
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_registerJavaUiThread(JNIEnv *jenv, jclass jc)
 {
     AndroidBridge::RegisterJavaUiThread();
 }
 
 NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *jenv, jclass jc)
+Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *jenv, jclass, jobject clsLoader)
 {
-    AndroidBridge::ConstructBridge(jenv);
+    AndroidBridge::ConstructBridge(jenv, jni::Object::Ref::From(clsLoader));
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifyGeckoOfEvent(JNIEnv *jenv, jclass jc, jobject event)
 {
     // poke the appshell
     if (nsAppShell::gAppShell)
         nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeFromJavaObject(jenv, event));
@@ -895,21 +896,21 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_init(JNIEnv* env, jobject instance)
 {
     if (!AndroidBridge::Bridge()) {
         return;
     }
 
-    NativePanZoomController* oldRef = APZCCallbackHandler::GetInstance()->SetNativePanZoomController(instance);
-    if (oldRef && !oldRef->isNull()) {
-        MOZ_ASSERT(false, "Registering a new NPZC when we already have one");
-        delete oldRef;
-    }
+    const auto& newRef = NativePanZoomController::Ref::From(instance);
+    NativePanZoomController::LocalRef oldRef =
+            APZCCallbackHandler::GetInstance()->SetNativePanZoomController(newRef);
+
+    MOZ_ASSERT(!oldRef, "Registering a new NPZC when we already have one");
 }
 
 NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv* env, jobject instance, jobject event)
 {
     APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
     if (!controller) {
         return false;
@@ -940,22 +941,20 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy(JNIEnv* env, jobject instance)
 {
     if (!AndroidBridge::Bridge()) {
         return;
     }
 
-    NativePanZoomController* oldRef = APZCCallbackHandler::GetInstance()->SetNativePanZoomController(nullptr);
-    if (!oldRef || oldRef->isNull()) {
-        MOZ_ASSERT(false, "Clearing a non-existent NPZC");
-    } else {
-        delete oldRef;
-    }
+    NativePanZoomController::LocalRef oldRef =
+            APZCCallbackHandler::GetInstance()->SetNativePanZoomController(nullptr);
+
+    MOZ_ASSERT(oldRef, "Clearing a non-existent NPZC");
 }
 
 NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint(JNIEnv* env, jobject instance)
 {
     // FIXME implement this
     return true;
 }
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -9,17 +9,16 @@
 #include "nsIDOMKeyEvent.h"
 #include "nsIWidget.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TouchEvents.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
-using namespace mozilla::widget::android;
 
 jclass AndroidGeckoEvent::jGeckoEventClass = 0;
 jfieldID AndroidGeckoEvent::jActionField = 0;
 jfieldID AndroidGeckoEvent::jTypeField = 0;
 jfieldID AndroidGeckoEvent::jAckNeededField = 0;
 jfieldID AndroidGeckoEvent::jTimeField = 0;
 jfieldID AndroidGeckoEvent::jPoints = 0;
 jfieldID AndroidGeckoEvent::jPointIndicies = 0;
@@ -117,17 +116,16 @@ void
 mozilla::InitAndroidJavaWrappers(JNIEnv *jEnv)
 {
     AndroidGeckoEvent::InitGeckoEventClass(jEnv);
     AndroidPoint::InitPointClass(jEnv);
     AndroidLocation::InitLocationClass(jEnv);
     AndroidRect::InitRectClass(jEnv);
     AndroidRectF::InitRectFClass(jEnv);
     AndroidLayerRendererFrame::InitLayerRendererFrameClass(jEnv);
-    InitStubs(jEnv);
 }
 
 void
 AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv)
 {
     AutoJNIClass geckoEvent(jEnv, "org/mozilla/gecko/GeckoEvent");
     jGeckoEventClass = geckoEvent.getGlobalRef();
 
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -1,2479 +1,1304 @@
 // GENERATED CODE
-// Generated by the Java program at /build/annotationProcessors at compile time from
-// annotations on Java methods. To update, change the annotations on the corresponding Java
-// methods and rerun the build. Manually updating this file will cause your build to fail.
+// Generated by the Java program at /build/annotationProcessors at compile time
+// from annotations on Java methods. To update, change the annotations on the
+// corresponding Javamethods and rerun the build. Manually updating this file
+// will cause your build to fail.
 
 #include "GeneratedJNIWrappers.h"
-#include "AndroidBridgeUtilities.h"
-#include "nsXPCOMStrings.h"
-#include "AndroidBridge.h"
+#include "mozilla/jni/Accessors.h"
 
 namespace mozilla {
 namespace widget {
-namespace android {
-jclass DownloadsIntegration::mDownloadsIntegrationClass = 0;
-jmethodID DownloadsIntegration::jScanMedia = 0;
-void DownloadsIntegration::InitStubs(JNIEnv *env) {
-    mDownloadsIntegrationClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/DownloadsIntegration");
-    jScanMedia = AndroidBridge::GetStaticMethodID(env, mDownloadsIntegrationClass, "scanMedia", "(Ljava/lang/String;Ljava/lang/String;)V");
+
+constexpr char DownloadsIntegration::name[];
+
+constexpr char DownloadsIntegration::ScanMedia_t::name[];
+constexpr char DownloadsIntegration::ScanMedia_t::signature[];
+
+void DownloadsIntegration::ScanMedia(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<ScanMedia_t>::Call(nullptr, nullptr, a0, a1);
+}
+
+constexpr char GeckoAppShell::name[];
+
+constexpr char GeckoAppShell::AcknowledgeEvent_t::name[];
+constexpr char GeckoAppShell::AcknowledgeEvent_t::signature[];
+
+void GeckoAppShell::AcknowledgeEvent()
+{
+    return mozilla::jni::Method<AcknowledgeEvent_t>::Call(nullptr, nullptr);
+}
+
+constexpr char GeckoAppShell::AddPluginViewWrapper_t::name[];
+constexpr char GeckoAppShell::AddPluginViewWrapper_t::signature[];
+
+void GeckoAppShell::AddPluginViewWrapper(mozilla::jni::Object::Param a0, float a1, float a2, float a3, float a4, bool a5)
+{
+    return mozilla::jni::Method<AddPluginViewWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4, a5);
+}
+
+constexpr char GeckoAppShell::AlertsProgressListener_OnProgress_t::name[];
+constexpr char GeckoAppShell::AlertsProgressListener_OnProgress_t::signature[];
+
+void GeckoAppShell::AlertsProgressListener_OnProgress(mozilla::jni::String::Param a0, int64_t a1, int64_t a2, mozilla::jni::String::Param a3)
+{
+    return mozilla::jni::Method<AlertsProgressListener_OnProgress_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-DownloadsIntegration* DownloadsIntegration::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    DownloadsIntegration* ret = new DownloadsIntegration(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char GeckoAppShell::CancelVibrate_t::name[];
+constexpr char GeckoAppShell::CancelVibrate_t::signature[];
+
+void GeckoAppShell::CancelVibrate()
+{
+    return mozilla::jni::Method<CancelVibrate_t>::Call(nullptr, nullptr);
+}
+
+constexpr char GeckoAppShell::CheckURIVisited_t::name[];
+constexpr char GeckoAppShell::CheckURIVisited_t::signature[];
+
+void GeckoAppShell::CheckURIVisited(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<CheckURIVisited_t>::Call(nullptr, nullptr, a0);
+}
+
+constexpr char GeckoAppShell::ClearMessageList_t::name[];
+constexpr char GeckoAppShell::ClearMessageList_t::signature[];
+
+void GeckoAppShell::ClearMessageList(int32_t a0)
+{
+    return mozilla::jni::Method<ClearMessageList_t>::Call(nullptr, nullptr, a0);
+}
+
+constexpr char GeckoAppShell::CloseCamera_t::name[];
+constexpr char GeckoAppShell::CloseCamera_t::signature[];
+
+void GeckoAppShell::CloseCamera()
+{
+    return mozilla::jni::Method<CloseCamera_t>::Call(nullptr, nullptr);
+}
+
+constexpr char GeckoAppShell::CloseNotification_t::name[];
+constexpr char GeckoAppShell::CloseNotification_t::signature[];
+
+void GeckoAppShell::CloseNotification(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<CloseNotification_t>::Call(nullptr, nullptr, a0);
 }
 
-void DownloadsIntegration::ScanMedia(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::ConnectionGetMimeType_t::name[];
+constexpr char GeckoAppShell::ConnectionGetMimeType_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
+mozilla::jni::String::LocalRef GeckoAppShell::ConnectionGetMimeType(mozilla::jni::Object::Param a0)
+{
+    return mozilla::jni::Method<ConnectionGetMimeType_t>::Call(nullptr, nullptr, a0);
+}
 
-    env->CallStaticVoidMethod(mDownloadsIntegrationClass, jScanMedia, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+constexpr char GeckoAppShell::CreateInputStream_t::name[];
+constexpr char GeckoAppShell::CreateInputStream_t::signature[];
+
+mozilla::jni::Object::LocalRef GeckoAppShell::CreateInputStream(mozilla::jni::Object::Param a0)
+{
+    return mozilla::jni::Method<CreateInputStream_t>::Call(nullptr, nullptr, a0);
 }
-jclass GeckoAppShell::mGeckoAppShellClass = 0;
-jmethodID GeckoAppShell::jAcknowledgeEvent = 0;
-jmethodID GeckoAppShell::jAddPluginViewWrapper = 0;
-jmethodID GeckoAppShell::jAlertsProgressListener_OnProgress = 0;
-jmethodID GeckoAppShell::jCancelVibrate = 0;
-jmethodID GeckoAppShell::jCheckURIVisited = 0;
-jmethodID GeckoAppShell::jClearMessageList = 0;
-jmethodID GeckoAppShell::jCloseCamera = 0;
-jmethodID GeckoAppShell::jCloseNotification = 0;
-jmethodID GeckoAppShell::jConnectionGetMimeType = 0;
-jmethodID GeckoAppShell::jCreateInputStream = 0;
-jmethodID GeckoAppShell::jCreateMessageListWrapper = 0;
-jmethodID GeckoAppShell::jCreateShortcut = 0;
-jmethodID GeckoAppShell::jDeleteMessageWrapper = 0;
-jmethodID GeckoAppShell::jDisableBatteryNotifications = 0;
-jmethodID GeckoAppShell::jDisableNetworkNotifications = 0;
-jmethodID GeckoAppShell::jDisableScreenOrientationNotifications = 0;
-jmethodID GeckoAppShell::jDisableSensor = 0;
-jmethodID GeckoAppShell::jEnableBatteryNotifications = 0;
-jmethodID GeckoAppShell::jEnableLocation = 0;
-jmethodID GeckoAppShell::jEnableLocationHighAccuracy = 0;
-jmethodID GeckoAppShell::jEnableNetworkNotifications = 0;
-jmethodID GeckoAppShell::jEnableScreenOrientationNotifications = 0;
-jmethodID GeckoAppShell::jEnableSensor = 0;
-jmethodID GeckoAppShell::jGamepadAdded = 0;
-jmethodID GeckoAppShell::jGetConnection = 0;
-jmethodID GeckoAppShell::jGetContext = 0;
-jmethodID GeckoAppShell::jGetCurrentBatteryInformationWrapper = 0;
-jmethodID GeckoAppShell::jGetCurrentNetworkInformationWrapper = 0;
-jmethodID GeckoAppShell::jGetDensity = 0;
-jmethodID GeckoAppShell::jGetDpiWrapper = 0;
-jmethodID GeckoAppShell::jGetExtensionFromMimeTypeWrapper = 0;
-jmethodID GeckoAppShell::jGetExternalPublicDirectory = 0;
-jmethodID GeckoAppShell::jGetHandlersForMimeTypeWrapper = 0;
-jmethodID GeckoAppShell::jGetHandlersForURLWrapper = 0;
-jmethodID GeckoAppShell::jGetIconForExtensionWrapper = 0;
-jmethodID GeckoAppShell::jGetMessageWrapper = 0;
-jmethodID GeckoAppShell::jGetMimeTypeFromExtensionsWrapper = 0;
-jmethodID GeckoAppShell::jGetNextMessageInListWrapper = 0;
-jmethodID GeckoAppShell::jGetProxyForURIWrapper = 0;
-jmethodID GeckoAppShell::jGetScreenDepthWrapper = 0;
-jmethodID GeckoAppShell::jGetScreenOrientationWrapper = 0;
-jmethodID GeckoAppShell::jGetShowPasswordSetting = 0;
-jmethodID GeckoAppShell::jGetSystemColoursWrapper = 0;
-jmethodID GeckoAppShell::jHandleGeckoMessageWrapper = 0;
-jmethodID GeckoAppShell::jHandleUncaughtException = 0;
-jmethodID GeckoAppShell::jHideProgressDialog = 0;
-jmethodID GeckoAppShell::jInitCameraWrapper = 0;
-jmethodID GeckoAppShell::jIsNetworkLinkKnown = 0;
-jmethodID GeckoAppShell::jIsNetworkLinkUp = 0;
-jmethodID GeckoAppShell::jIsTablet = 0;
-jmethodID GeckoAppShell::jKillAnyZombies = 0;
-jmethodID GeckoAppShell::jLoadPluginClass = 0;
-jmethodID GeckoAppShell::jLockScreenOrientation = 0;
-jmethodID GeckoAppShell::jMarkURIVisited = 0;
-jmethodID GeckoAppShell::jMoveTaskToBack = 0;
-jmethodID GeckoAppShell::jNetworkLinkType = 0;
-jmethodID GeckoAppShell::jNotifyDefaultPrevented = 0;
-jmethodID GeckoAppShell::jNotifyIME = 0;
-jmethodID GeckoAppShell::jNotifyIMEChange = 0;
-jmethodID GeckoAppShell::jNotifyIMEContext = 0;
-jmethodID GeckoAppShell::jNotifyWakeLockChanged = 0;
-jmethodID GeckoAppShell::jNotifyXreExit = 0;
-jmethodID GeckoAppShell::jOpenUriExternal = 0;
-jmethodID GeckoAppShell::jPerformHapticFeedback = 0;
-jmethodID GeckoAppShell::jPumpMessageLoop = 0;
-jmethodID GeckoAppShell::jRegisterSurfaceTextureFrameListener = 0;
-jmethodID GeckoAppShell::jRemovePluginView = 0;
-jmethodID GeckoAppShell::jRequestUiThreadCallback = 0;
-jmethodID GeckoAppShell::jScheduleRestart = 0;
-jmethodID GeckoAppShell::jSendMessageWrapper = 0;
-jmethodID GeckoAppShell::jSetFullScreen = 0;
-jmethodID GeckoAppShell::jSetKeepScreenOn = 0;
-jmethodID GeckoAppShell::jSetURITitle = 0;
-jmethodID GeckoAppShell::jShowAlertNotificationWrapper = 0;
-jmethodID GeckoAppShell::jShowInputMethodPicker = 0;
-jmethodID GeckoAppShell::jStartMonitoringGamepad = 0;
-jmethodID GeckoAppShell::jStopMonitoringGamepad = 0;
-jmethodID GeckoAppShell::jUnlockProfile = 0;
-jmethodID GeckoAppShell::jUnlockScreenOrientation = 0;
-jmethodID GeckoAppShell::jUnregisterSurfaceTextureFrameListener = 0;
-jmethodID GeckoAppShell::jVibrate1 = 0;
-jmethodID GeckoAppShell::jVibrateA = 0;
-void GeckoAppShell::InitStubs(JNIEnv *env) {
-    mGeckoAppShellClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/GeckoAppShell");
-    jAcknowledgeEvent = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "acknowledgeEvent", "()V");
-    jAddPluginViewWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "addPluginView", "(Landroid/view/View;FFFFZ)V");
-    jAlertsProgressListener_OnProgress = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "alertsProgressListener_OnProgress", "(Ljava/lang/String;JJLjava/lang/String;)V");
-    jCancelVibrate = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "cancelVibrate", "()V");
-    jCheckURIVisited = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "checkUriVisited", "(Ljava/lang/String;)V");
-    jClearMessageList = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "clearMessageList", "(I)V");
-    jCloseCamera = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "closeCamera", "()V");
-    jCloseNotification = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "closeNotification", "(Ljava/lang/String;)V");
-    jConnectionGetMimeType = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "connectionGetMimeType", "(Ljava/net/URLConnection;)Ljava/lang/String;");
-    jCreateInputStream = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createInputStream", "(Ljava/net/URLConnection;)Ljava/io/InputStream;");
-    jCreateMessageListWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createMessageList", "(JJ[Ljava/lang/String;ILjava/lang/String;ZZJZI)V");
-    jCreateShortcut = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createShortcut", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
-    jDeleteMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "deleteMessage", "(II)V");
-    jDisableBatteryNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableBatteryNotifications", "()V");
-    jDisableNetworkNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableNetworkNotifications", "()V");
-    jDisableScreenOrientationNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableScreenOrientationNotifications", "()V");
-    jDisableSensor = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableSensor", "(I)V");
-    jEnableBatteryNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableBatteryNotifications", "()V");
-    jEnableLocation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableLocation", "(Z)V");
-    jEnableLocationHighAccuracy = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableLocationHighAccuracy", "(Z)V");
-    jEnableNetworkNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableNetworkNotifications", "()V");
-    jEnableScreenOrientationNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableScreenOrientationNotifications", "()V");
-    jEnableSensor = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableSensor", "(I)V");
-    jGamepadAdded = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "gamepadAdded", "(II)V");
-    jGetConnection = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getConnection", "(Ljava/lang/String;)Ljava/net/URLConnection;");
-    jGetContext = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getContext", "()Landroid/content/Context;");
-    jGetCurrentBatteryInformationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getCurrentBatteryInformation", "()[D");
-    jGetCurrentNetworkInformationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getCurrentNetworkInformation", "()[D");
-    jGetDensity = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getDensity", "()F");
-    jGetDpiWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getDpi", "()I");
-    jGetExtensionFromMimeTypeWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getExtensionFromMimeType", "(Ljava/lang/String;)Ljava/lang/String;");
-    jGetExternalPublicDirectory = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getExternalPublicDirectory", "(Ljava/lang/String;)Ljava/lang/String;");
-    jGetHandlersForMimeTypeWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
-    jGetHandlersForURLWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getHandlersForURL", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
-    jGetIconForExtensionWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getIconForExtension", "(Ljava/lang/String;I)[B");
-    jGetMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getMessage", "(II)V");
-    jGetMimeTypeFromExtensionsWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getMimeTypeFromExtensions", "(Ljava/lang/String;)Ljava/lang/String;");
-    jGetNextMessageInListWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getNextMessageInList", "(II)V");
-    jGetProxyForURIWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getProxyForURI", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;");
-    jGetScreenDepthWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getScreenDepth", "()I");
-    jGetScreenOrientationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getScreenOrientation", "()S");
-    jGetShowPasswordSetting = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getShowPasswordSetting", "()Z");
-    jGetSystemColoursWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getSystemColors", "()[I");
-    jHandleGeckoMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "handleGeckoMessage", "(Lorg/mozilla/gecko/util/NativeJSContainer;)V");
-    jHandleUncaughtException = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "handleUncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V");
-    jHideProgressDialog = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "hideProgressDialog", "()V");
-    jInitCameraWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "initCamera", "(Ljava/lang/String;III)[I");
-    jIsNetworkLinkKnown = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isNetworkLinkKnown", "()Z");
-    jIsNetworkLinkUp = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isNetworkLinkUp", "()Z");
-    jIsTablet = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isTablet", "()Z");
-    jKillAnyZombies = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "killAnyZombies", "()V");
-    jLoadPluginClass = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "loadPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
-    jLockScreenOrientation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "lockScreenOrientation", "(I)V");
-    jMarkURIVisited = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "markUriVisited", "(Ljava/lang/String;)V");
-    jMoveTaskToBack = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "moveTaskToBack", "()V");
-    jNetworkLinkType = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "networkLinkType", "()I");
-    jNotifyDefaultPrevented = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyDefaultPrevented", "(Z)V");
-    jNotifyIME = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIME", "(I)V");
-    jNotifyIMEChange = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
-    jNotifyIMEContext = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIMEContext", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
-    jNotifyWakeLockChanged = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V");
-    jNotifyXreExit = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "onXreExit", "()V");
-    jOpenUriExternal = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "openUriExternal", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
-    jPerformHapticFeedback = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "performHapticFeedback", "(Z)V");
-    jPumpMessageLoop = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "pumpMessageLoop", "()Z");
-    jRegisterSurfaceTextureFrameListener = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "registerSurfaceTextureFrameListener", "(Ljava/lang/Object;I)V");
-    jRemovePluginView = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "removePluginView", "(Landroid/view/View;Z)V");
-    jRequestUiThreadCallback = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "requestUiThreadCallback", "(J)V");
-    jScheduleRestart = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "scheduleRestart", "()V");
-    jSendMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "sendMessage", "(Ljava/lang/String;Ljava/lang/String;I)V");
-    jSetFullScreen = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setFullScreen", "(Z)V");
-    jSetKeepScreenOn = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setKeepScreenOn", "(Z)V");
-    jSetURITitle = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setUriTitle", "(Ljava/lang/String;Ljava/lang/String;)V");
-    jShowAlertNotificationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
-    jShowInputMethodPicker = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "showInputMethodPicker", "()V");
-    jStartMonitoringGamepad = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "startMonitoringGamepad", "()V");
-    jStopMonitoringGamepad = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "stopMonitoringGamepad", "()V");
-    jUnlockProfile = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unlockProfile", "()Z");
-    jUnlockScreenOrientation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unlockScreenOrientation", "()V");
-    jUnregisterSurfaceTextureFrameListener = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V");
-    jVibrate1 = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "vibrate", "(J)V");
-    jVibrateA = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "vibrate", "([JI)V");
+
+constexpr char GeckoAppShell::CreateMessageListWrapper_t::name[];
+constexpr char GeckoAppShell::CreateMessageListWrapper_t::signature[];
+
+void GeckoAppShell::CreateMessageListWrapper(int64_t a0, int64_t a1, mozilla::jni::ObjectArray::Param a2, int32_t a3, mozilla::jni::String::Param a4, bool a5, bool a6, int64_t a7, bool a8, int32_t a9)
+{
+    return mozilla::jni::Method<CreateMessageListWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+}
+
+constexpr char GeckoAppShell::CreateShortcut_t::name[];
+constexpr char GeckoAppShell::CreateShortcut_t::signature[];
+
+void GeckoAppShell::CreateShortcut(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2)
+{
+    return mozilla::jni::Method<CreateShortcut_t>::Call(nullptr, nullptr, a0, a1, a2);
 }
 
-GeckoAppShell* GeckoAppShell::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    GeckoAppShell* ret = new GeckoAppShell(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
-}
+constexpr char GeckoAppShell::DeleteMessageWrapper_t::name[];
+constexpr char GeckoAppShell::DeleteMessageWrapper_t::signature[];
 
-void GeckoAppShell::AcknowledgeEvent() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jAcknowledgeEvent);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::DeleteMessageWrapper(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<DeleteMessageWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::AddPluginViewWrapper(jobject a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, bool a5) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::DisableBatteryNotifications_t::name[];
+constexpr char GeckoAppShell::DisableBatteryNotifications_t::signature[];
 
-    jvalue args[6];
-    args[0].l = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
-    args[5].z = a5;
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jAddPluginViewWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::DisableBatteryNotifications()
+{
+    return mozilla::jni::Method<DisableBatteryNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::AlertsProgressListener_OnProgress(const nsAString& a0, int64_t a1, int64_t a2, const nsAString& a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::DisableNetworkNotifications_t::name[];
+constexpr char GeckoAppShell::DisableNetworkNotifications_t::signature[];
 
-    jvalue args[4];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].j = a1;
-    args[2].j = a2;
-    args[3].l = AndroidBridge::NewJavaString(env, a3);
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jAlertsProgressListener_OnProgress, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::DisableNetworkNotifications()
+{
+    return mozilla::jni::Method<DisableNetworkNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::CancelVibrate() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::DisableScreenOrientationNotifications_t::name[];
+constexpr char GeckoAppShell::DisableScreenOrientationNotifications_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jCancelVibrate);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::DisableScreenOrientationNotifications()
+{
+    return mozilla::jni::Method<DisableScreenOrientationNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::CheckURIVisited(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::DisableSensor_t::name[];
+constexpr char GeckoAppShell::DisableSensor_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jCheckURIVisited, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::DisableSensor(int32_t a0)
+{
+    return mozilla::jni::Method<DisableSensor_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::ClearMessageList(int32_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::EnableBatteryNotifications_t::name[];
+constexpr char GeckoAppShell::EnableBatteryNotifications_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jClearMessageList, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::EnableBatteryNotifications()
+{
+    return mozilla::jni::Method<EnableBatteryNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::CloseCamera() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jCloseCamera);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
+constexpr char GeckoAppShell::EnableLocation_t::name[];
+constexpr char GeckoAppShell::EnableLocation_t::signature[];
 
-void GeckoAppShell::CloseNotification(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jCloseNotification, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::EnableLocation(bool a0)
+{
+    return mozilla::jni::Method<EnableLocation_t>::Call(nullptr, nullptr, a0);
 }
 
-jstring GeckoAppShell::ConnectionGetMimeType(jobject a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::EnableLocationHighAccuracy_t::name[];
+constexpr char GeckoAppShell::EnableLocationHighAccuracy_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jConnectionGetMimeType, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::EnableLocationHighAccuracy(bool a0)
+{
+    return mozilla::jni::Method<EnableLocationHighAccuracy_t>::Call(nullptr, nullptr, a0);
 }
 
-jobject GeckoAppShell::CreateInputStream(jobject a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::EnableNetworkNotifications_t::name[];
+constexpr char GeckoAppShell::EnableNetworkNotifications_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jCreateInputStream, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::EnableNetworkNotifications()
+{
+    return mozilla::jni::Method<EnableNetworkNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::CreateMessageListWrapper(int64_t a0, int64_t a1, jobjectArray a2, int32_t a3, const nsAString& a4, bool a5, bool a6, int64_t a7, bool a8, int32_t a9) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::EnableScreenOrientationNotifications_t::name[];
+constexpr char GeckoAppShell::EnableScreenOrientationNotifications_t::signature[];
 
-    jvalue args[10];
-    args[0].j = a0;
-    args[1].j = a1;
-    args[2].l = a2;
-    args[3].i = a3;
-    args[4].l = AndroidBridge::NewJavaString(env, a4);
-    args[5].z = a5;
-    args[6].z = a6;
-    args[7].j = a7;
-    args[8].z = a8;
-    args[9].i = a9;
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jCreateMessageListWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::EnableScreenOrientationNotifications()
+{
+    return mozilla::jni::Method<EnableScreenOrientationNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::CreateShortcut(const nsAString& a0, const nsAString& a1, const nsAString& a2) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(3) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::EnableSensor_t::name[];
+constexpr char GeckoAppShell::EnableSensor_t::signature[];
 
-    jvalue args[3];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].l = AndroidBridge::NewJavaString(env, a2);
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jCreateShortcut, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::EnableSensor(int32_t a0)
+{
+    return mozilla::jni::Method<EnableSensor_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::DeleteMessageWrapper(int32_t a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GamepadAdded_t::name[];
+constexpr char GeckoAppShell::GamepadAdded_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDeleteMessageWrapper, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::GamepadAdded(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<GamepadAdded_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::DisableBatteryNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetConnection_t::name[];
+constexpr char GeckoAppShell::GetConnection_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableBatteryNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::Object::LocalRef GeckoAppShell::GetConnection(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<GetConnection_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::DisableNetworkNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetContext_t::name[];
+constexpr char GeckoAppShell::GetContext_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableNetworkNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::Object::LocalRef GeckoAppShell::GetContext()
+{
+    return mozilla::jni::Method<GetContext_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::DisableScreenOrientationNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetCurrentBatteryInformationWrapper_t::name[];
+constexpr char GeckoAppShell::GetCurrentBatteryInformationWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableScreenOrientationNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-
-void GeckoAppShell::DisableSensor(int32_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableSensor, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::DoubleArray::LocalRef GeckoAppShell::GetCurrentBatteryInformationWrapper()
+{
+    return mozilla::jni::Method<GetCurrentBatteryInformationWrapper_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::EnableBatteryNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetCurrentNetworkInformationWrapper_t::name[];
+constexpr char GeckoAppShell::GetCurrentNetworkInformationWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableBatteryNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::DoubleArray::LocalRef GeckoAppShell::GetCurrentNetworkInformationWrapper()
+{
+    return mozilla::jni::Method<GetCurrentNetworkInformationWrapper_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::EnableLocation(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetDensity_t::name[];
+constexpr char GeckoAppShell::GetDensity_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocation, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+float GeckoAppShell::GetDensity()
+{
+    return mozilla::jni::Method<GetDensity_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::EnableLocationHighAccuracy(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetDpiWrapper_t::name[];
+constexpr char GeckoAppShell::GetDpiWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocationHighAccuracy, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+int32_t GeckoAppShell::GetDpiWrapper()
+{
+    return mozilla::jni::Method<GetDpiWrapper_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::EnableNetworkNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetExtensionFromMimeTypeWrapper_t::name[];
+constexpr char GeckoAppShell::GetExtensionFromMimeTypeWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableNetworkNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::String::LocalRef GeckoAppShell::GetExtensionFromMimeTypeWrapper(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<GetExtensionFromMimeTypeWrapper_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::EnableScreenOrientationNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetExternalPublicDirectory_t::name[];
+constexpr char GeckoAppShell::GetExternalPublicDirectory_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableScreenOrientationNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-
-void GeckoAppShell::EnableSensor(int32_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableSensor, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::String::LocalRef GeckoAppShell::GetExternalPublicDirectory(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<GetExternalPublicDirectory_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::GamepadAdded(int32_t a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetHandlersForMimeTypeWrapper_t::name[];
+constexpr char GeckoAppShell::GetHandlersForMimeTypeWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jGamepadAdded, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::ObjectArray::LocalRef GeckoAppShell::GetHandlersForMimeTypeWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<GetHandlersForMimeTypeWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jobject GeckoAppShell::GetConnection(const nsACString& a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+constexpr char GeckoAppShell::GetHandlersForURLWrapper_t::name[];
+constexpr char GeckoAppShell::GetHandlersForURLWrapper_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetConnection, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
-}
-
-jobject GeckoAppShell::GetContext() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetContext);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::ObjectArray::LocalRef GeckoAppShell::GetHandlersForURLWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<GetHandlersForURLWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jdoubleArray GeckoAppShell::GetCurrentBatteryInformationWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetIconForExtensionWrapper_t::name[];
+constexpr char GeckoAppShell::GetIconForExtensionWrapper_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentBatteryInformationWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jdoubleArray ret = static_cast<jdoubleArray>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::ByteArray::LocalRef GeckoAppShell::GetIconForExtensionWrapper(mozilla::jni::String::Param a0, int32_t a1)
+{
+    return mozilla::jni::Method<GetIconForExtensionWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jdoubleArray GeckoAppShell::GetCurrentNetworkInformationWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetMessageWrapper_t::name[];
+constexpr char GeckoAppShell::GetMessageWrapper_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentNetworkInformationWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jdoubleArray ret = static_cast<jdoubleArray>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::GetMessageWrapper(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<GetMessageWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jfloat GeckoAppShell::GetDensity() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetMimeTypeFromExtensionsWrapper_t::name[];
+constexpr char GeckoAppShell::GetMimeTypeFromExtensionsWrapper_t::signature[];
 
-    jfloat temp = env->CallStaticFloatMethod(mGeckoAppShellClass, jGetDensity);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+mozilla::jni::String::LocalRef GeckoAppShell::GetMimeTypeFromExtensionsWrapper(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<GetMimeTypeFromExtensionsWrapper_t>::Call(nullptr, nullptr, a0);
 }
 
-int32_t GeckoAppShell::GetDpiWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetNextMessageInListWrapper_t::name[];
+constexpr char GeckoAppShell::GetNextMessageInListWrapper_t::signature[];
 
-    int32_t temp = env->CallStaticIntMethod(mGeckoAppShellClass, jGetDpiWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::GetNextMessageInListWrapper(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<GetNextMessageInListWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jstring GeckoAppShell::GetExtensionFromMimeTypeWrapper(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+constexpr char GeckoAppShell::GetProxyForURIWrapper_t::name[];
+constexpr char GeckoAppShell::GetProxyForURIWrapper_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetExtensionFromMimeTypeWrapper, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
-}
-
-jstring GeckoAppShell::GetExternalPublicDirectory(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetExternalPublicDirectory, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::String::LocalRef GeckoAppShell::GetProxyForURIWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, int32_t a3)
+{
+    return mozilla::jni::Method<GetProxyForURIWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-jobjectArray GeckoAppShell::GetHandlersForMimeTypeWrapper(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(3) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetScreenDepthWrapper_t::name[];
+constexpr char GeckoAppShell::GetScreenDepthWrapper_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetHandlersForMimeTypeWrapper, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    jobjectArray ret = static_cast<jobjectArray>(env->PopLocalFrame(temp));
-    return ret;
+int32_t GeckoAppShell::GetScreenDepthWrapper()
+{
+    return mozilla::jni::Method<GetScreenDepthWrapper_t>::Call(nullptr, nullptr);
 }
 
-jobjectArray GeckoAppShell::GetHandlersForURLWrapper(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(3) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetScreenOrientationWrapper_t::name[];
+constexpr char GeckoAppShell::GetScreenOrientationWrapper_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
+int16_t GeckoAppShell::GetScreenOrientationWrapper()
+{
+    return mozilla::jni::Method<GetScreenOrientationWrapper_t>::Call(nullptr, nullptr);
+}
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetHandlersForURLWrapper, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    jobjectArray ret = static_cast<jobjectArray>(env->PopLocalFrame(temp));
-    return ret;
+constexpr char GeckoAppShell::GetShowPasswordSetting_t::name[];
+constexpr char GeckoAppShell::GetShowPasswordSetting_t::signature[];
+
+bool GeckoAppShell::GetShowPasswordSetting()
+{
+    return mozilla::jni::Method<GetShowPasswordSetting_t>::Call(nullptr, nullptr);
 }
 
-jbyteArray GeckoAppShell::GetIconForExtensionWrapper(const nsAString& a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetSystemColoursWrapper_t::name[];
+constexpr char GeckoAppShell::GetSystemColoursWrapper_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetIconForExtensionWrapper, j0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    jbyteArray ret = static_cast<jbyteArray>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::IntArray::LocalRef GeckoAppShell::GetSystemColoursWrapper()
+{
+    return mozilla::jni::Method<GetSystemColoursWrapper_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::GetMessageWrapper(int32_t a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::HandleGeckoMessageWrapper_t::name[];
+constexpr char GeckoAppShell::HandleGeckoMessageWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jGetMessageWrapper, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::HandleGeckoMessageWrapper(mozilla::jni::Object::Param a0)
+{
+    return mozilla::jni::Method<HandleGeckoMessageWrapper_t>::Call(nullptr, nullptr, a0);
 }
 
-jstring GeckoAppShell::GetMimeTypeFromExtensionsWrapper(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::HandleUncaughtException_t::name[];
+constexpr char GeckoAppShell::HandleUncaughtException_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetMimeTypeFromExtensionsWrapper, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::HandleUncaughtException(mozilla::jni::Object::Param a0, mozilla::jni::Throwable::Param a1)
+{
+    return mozilla::jni::Method<HandleUncaughtException_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::GetNextMessageInListWrapper(int32_t a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::HideProgressDialog_t::name[];
+constexpr char GeckoAppShell::HideProgressDialog_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jGetNextMessageInListWrapper, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::HideProgressDialog()
+{
+    return mozilla::jni::Method<HideProgressDialog_t>::Call(nullptr, nullptr);
 }
 
-jstring GeckoAppShell::GetProxyForURIWrapper(const nsAString& a0, const nsAString& a1, const nsAString& a2, int32_t a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(4) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::InitCameraWrapper_t::name[];
+constexpr char GeckoAppShell::InitCameraWrapper_t::signature[];
 
-    jvalue args[4];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].l = AndroidBridge::NewJavaString(env, a2);
-    args[3].i = a3;
-
-    jobject temp = env->CallStaticObjectMethodA(mGeckoAppShellClass, jGetProxyForURIWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::IntArray::LocalRef GeckoAppShell::InitCameraWrapper(mozilla::jni::String::Param a0, int32_t a1, int32_t a2, int32_t a3)
+{
+    return mozilla::jni::Method<InitCameraWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-int32_t GeckoAppShell::GetScreenDepthWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::IsNetworkLinkKnown_t::name[];
+constexpr char GeckoAppShell::IsNetworkLinkKnown_t::signature[];
 
-    int32_t temp = env->CallStaticIntMethod(mGeckoAppShellClass, jGetScreenDepthWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+bool GeckoAppShell::IsNetworkLinkKnown()
+{
+    return mozilla::jni::Method<IsNetworkLinkKnown_t>::Call(nullptr, nullptr);
 }
 
-int16_t GeckoAppShell::GetScreenOrientationWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::IsNetworkLinkUp_t::name[];
+constexpr char GeckoAppShell::IsNetworkLinkUp_t::signature[];
 
-    int16_t temp = env->CallStaticShortMethod(mGeckoAppShellClass, jGetScreenOrientationWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+bool GeckoAppShell::IsNetworkLinkUp()
+{
+    return mozilla::jni::Method<IsNetworkLinkUp_t>::Call(nullptr, nullptr);
 }
 
-bool GeckoAppShell::GetShowPasswordSetting() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::IsTablet_t::name[];
+constexpr char GeckoAppShell::IsTablet_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jGetShowPasswordSetting);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+bool GeckoAppShell::IsTablet()
+{
+    return mozilla::jni::Method<IsTablet_t>::Call(nullptr, nullptr);
 }
 
-jintArray GeckoAppShell::GetSystemColoursWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::KillAnyZombies_t::name[];
+constexpr char GeckoAppShell::KillAnyZombies_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetSystemColoursWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jintArray ret = static_cast<jintArray>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::KillAnyZombies()
+{
+    return mozilla::jni::Method<KillAnyZombies_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::HandleGeckoMessageWrapper(jobject a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::LoadPluginClass_t::name[];
+constexpr char GeckoAppShell::LoadPluginClass_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jHandleGeckoMessageWrapper, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-
-void GeckoAppShell::HandleUncaughtException(jobject a0, jthrowable a1) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(2) != 0) {
-        return;
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jHandleUncaughtException, a0, a1);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::ClassObject::LocalRef GeckoAppShell::LoadPluginClass(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<LoadPluginClass_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::HideProgressDialog() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::LockScreenOrientation_t::name[];
+constexpr char GeckoAppShell::LockScreenOrientation_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jHideProgressDialog);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::LockScreenOrientation(int32_t a0)
+{
+    return mozilla::jni::Method<LockScreenOrientation_t>::Call(nullptr, nullptr, a0);
 }
 
-jintArray GeckoAppShell::InitCameraWrapper(const nsAString& a0, int32_t a1, int32_t a2, int32_t a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::MarkURIVisited_t::name[];
+constexpr char GeckoAppShell::MarkURIVisited_t::signature[];
 
-    jvalue args[4];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].i = a1;
-    args[2].i = a2;
-    args[3].i = a3;
-
-    jobject temp = env->CallStaticObjectMethodA(mGeckoAppShellClass, jInitCameraWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jintArray ret = static_cast<jintArray>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::MarkURIVisited(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<MarkURIVisited_t>::Call(nullptr, nullptr, a0);
 }
 
-bool GeckoAppShell::IsNetworkLinkKnown() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::MoveTaskToBack_t::name[];
+constexpr char GeckoAppShell::MoveTaskToBack_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkKnown);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::MoveTaskToBack()
+{
+    return mozilla::jni::Method<MoveTaskToBack_t>::Call(nullptr, nullptr);
 }
 
-bool GeckoAppShell::IsNetworkLinkUp() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NetworkLinkType_t::name[];
+constexpr char GeckoAppShell::NetworkLinkType_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkUp);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+int32_t GeckoAppShell::NetworkLinkType()
+{
+    return mozilla::jni::Method<NetworkLinkType_t>::Call(nullptr, nullptr);
 }
 
-bool GeckoAppShell::IsTablet() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NotifyDefaultPrevented_t::name[];
+constexpr char GeckoAppShell::NotifyDefaultPrevented_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsTablet);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::NotifyDefaultPrevented(bool a0)
+{
+    return mozilla::jni::Method<NotifyDefaultPrevented_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::KillAnyZombies() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NotifyIME_t::name[];
+constexpr char GeckoAppShell::NotifyIME_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jKillAnyZombies);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::NotifyIME(int32_t a0)
+{
+    return mozilla::jni::Method<NotifyIME_t>::Call(nullptr, nullptr, a0);
 }
 
-jclass GeckoAppShell::LoadPluginClass(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(3) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
+constexpr char GeckoAppShell::NotifyIMEChange_t::name[];
+constexpr char GeckoAppShell::NotifyIMEChange_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jLoadPluginClass, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    jclass ret = static_cast<jclass>(env->PopLocalFrame(temp));
-    return ret;
-}
-
-void GeckoAppShell::LockScreenOrientation(int32_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jLockScreenOrientation, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::NotifyIMEChange(mozilla::jni::String::Param a0, int32_t a1, int32_t a2, int32_t a3)
+{
+    return mozilla::jni::Method<NotifyIMEChange_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-void GeckoAppShell::MarkURIVisited(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NotifyIMEContext_t::name[];
+constexpr char GeckoAppShell::NotifyIMEContext_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jMarkURIVisited, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::NotifyIMEContext(int32_t a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, mozilla::jni::String::Param a3)
+{
+    return mozilla::jni::Method<NotifyIMEContext_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-void GeckoAppShell::MoveTaskToBack() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NotifyWakeLockChanged_t::name[];
+constexpr char GeckoAppShell::NotifyWakeLockChanged_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jMoveTaskToBack);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::NotifyWakeLockChanged(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<NotifyWakeLockChanged_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-int32_t GeckoAppShell::NetworkLinkType() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NotifyXreExit_t::name[];
+constexpr char GeckoAppShell::NotifyXreExit_t::signature[];
 
-    int32_t temp = env->CallStaticIntMethod(mGeckoAppShellClass, jNetworkLinkType);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::NotifyXreExit()
+{
+    return mozilla::jni::Method<NotifyXreExit_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::NotifyDefaultPrevented(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::OpenUriExternal_t::name[];
+constexpr char GeckoAppShell::OpenUriExternal_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyDefaultPrevented, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool GeckoAppShell::OpenUriExternal(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, mozilla::jni::String::Param a3, mozilla::jni::String::Param a4, mozilla::jni::String::Param a5)
+{
+    return mozilla::jni::Method<OpenUriExternal_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4, a5);
 }
 
-void GeckoAppShell::NotifyIME(int32_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyIME, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
+constexpr char GeckoAppShell::PerformHapticFeedback_t::name[];
+constexpr char GeckoAppShell::PerformHapticFeedback_t::signature[];
 
-void GeckoAppShell::NotifyIMEChange(const nsAString& a0, int32_t a1, int32_t a2, int32_t a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jvalue args[4];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].i = a1;
-    args[2].i = a2;
-    args[3].i = a3;
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jNotifyIMEChange, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::PerformHapticFeedback(bool a0)
+{
+    return mozilla::jni::Method<PerformHapticFeedback_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::NotifyIMEContext(int32_t a0, const nsAString& a1, const nsAString& a2, const nsAString& a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(3) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::PumpMessageLoop_t::name[];
+constexpr char GeckoAppShell::PumpMessageLoop_t::signature[];
 
-    jvalue args[4];
-    args[0].i = a0;
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].l = AndroidBridge::NewJavaString(env, a2);
-    args[3].l = AndroidBridge::NewJavaString(env, a3);
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jNotifyIMEContext, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool GeckoAppShell::PumpMessageLoop()
+{
+    return mozilla::jni::Method<PumpMessageLoop_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::NotifyWakeLockChanged(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::RegisterSurfaceTextureFrameListener_t::name[];
+constexpr char GeckoAppShell::RegisterSurfaceTextureFrameListener_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyWakeLockChanged, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::RegisterSurfaceTextureFrameListener(mozilla::jni::Object::Param a0, int32_t a1)
+{
+    return mozilla::jni::Method<RegisterSurfaceTextureFrameListener_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::NotifyXreExit() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::RemovePluginView_t::name[];
+constexpr char GeckoAppShell::RemovePluginView_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyXreExit);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::RemovePluginView(mozilla::jni::Object::Param a0, bool a1)
+{
+    return mozilla::jni::Method<RemovePluginView_t>::Call(nullptr, nullptr, a0, a1);
+}
+
+constexpr char GeckoAppShell::RequestUiThreadCallback_t::name[];
+constexpr char GeckoAppShell::RequestUiThreadCallback_t::signature[];
+
+void GeckoAppShell::RequestUiThreadCallback(int64_t a0)
+{
+    return mozilla::jni::Method<RequestUiThreadCallback_t>::Call(nullptr, nullptr, a0);
 }
 
-bool GeckoAppShell::OpenUriExternal(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3, const nsAString& a4, const nsAString& a5) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(6) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::ScheduleRestart_t::name[];
+constexpr char GeckoAppShell::ScheduleRestart_t::signature[];
 
-    jvalue args[6];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].l = AndroidBridge::NewJavaString(env, a2);
-    args[3].l = AndroidBridge::NewJavaString(env, a3);
-    args[4].l = AndroidBridge::NewJavaString(env, a4);
-    args[5].l = AndroidBridge::NewJavaString(env, a5);
-
-    bool temp = env->CallStaticBooleanMethodA(mGeckoAppShellClass, jOpenUriExternal, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::ScheduleRestart()
+{
+    return mozilla::jni::Method<ScheduleRestart_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::PerformHapticFeedback(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::SendMessageWrapper_t::name[];
+constexpr char GeckoAppShell::SendMessageWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jPerformHapticFeedback, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::SendMessageWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, int32_t a2)
+{
+    return mozilla::jni::Method<SendMessageWrapper_t>::Call(nullptr, nullptr, a0, a1, a2);
 }
 
-bool GeckoAppShell::PumpMessageLoop() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::SetFullScreen_t::name[];
+constexpr char GeckoAppShell::SetFullScreen_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jPumpMessageLoop);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::SetFullScreen(bool a0)
+{
+    return mozilla::jni::Method<SetFullScreen_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::RegisterSurfaceTextureFrameListener(jobject a0, int32_t a1) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::SetKeepScreenOn_t::name[];
+constexpr char GeckoAppShell::SetKeepScreenOn_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jRegisterSurfaceTextureFrameListener, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::SetKeepScreenOn(bool a0)
+{
+    return mozilla::jni::Method<SetKeepScreenOn_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::RemovePluginView(jobject a0, bool a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::SetURITitle_t::name[];
+constexpr char GeckoAppShell::SetURITitle_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jRemovePluginView, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-
-void GeckoAppShell::RequestUiThreadCallback(int64_t a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jRequestUiThreadCallback, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::SetURITitle(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<SetURITitle_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::ScheduleRestart() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::ShowAlertNotificationWrapper_t::name[];
+constexpr char GeckoAppShell::ShowAlertNotificationWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jScheduleRestart);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::ShowAlertNotificationWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, mozilla::jni::String::Param a3, mozilla::jni::String::Param a4)
+{
+    return mozilla::jni::Method<ShowAlertNotificationWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4);
 }
 
-void GeckoAppShell::SendMessageWrapper(const nsAString& a0, const nsAString& a1, int32_t a2) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jvalue args[3];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].i = a2;
+constexpr char GeckoAppShell::ShowInputMethodPicker_t::name[];
+constexpr char GeckoAppShell::ShowInputMethodPicker_t::signature[];
 
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jSendMessageWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-
-void GeckoAppShell::SetFullScreen(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jSetFullScreen, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::ShowInputMethodPicker()
+{
+    return mozilla::jni::Method<ShowInputMethodPicker_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::SetKeepScreenOn(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::StartMonitoringGamepad_t::name[];
+constexpr char GeckoAppShell::StartMonitoringGamepad_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jSetKeepScreenOn, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::StartMonitoringGamepad()
+{
+    return mozilla::jni::Method<StartMonitoringGamepad_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::SetURITitle(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::StopMonitoringGamepad_t::name[];
+constexpr char GeckoAppShell::StopMonitoringGamepad_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jSetURITitle, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::StopMonitoringGamepad()
+{
+    return mozilla::jni::Method<StopMonitoringGamepad_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::ShowAlertNotificationWrapper(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3, const nsAString& a4) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(5) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::UnlockProfile_t::name[];
+constexpr char GeckoAppShell::UnlockProfile_t::signature[];
 
-    jvalue args[5];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].l = AndroidBridge::NewJavaString(env, a2);
-    args[3].l = AndroidBridge::NewJavaString(env, a3);
-    args[4].l = AndroidBridge::NewJavaString(env, a4);
+bool GeckoAppShell::UnlockProfile()
+{
+    return mozilla::jni::Method<UnlockProfile_t>::Call(nullptr, nullptr);
+}
 
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jShowAlertNotificationWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+constexpr char GeckoAppShell::UnlockScreenOrientation_t::name[];
+constexpr char GeckoAppShell::UnlockScreenOrientation_t::signature[];
+
+void GeckoAppShell::UnlockScreenOrientation()
+{
+    return mozilla::jni::Method<UnlockScreenOrientation_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::ShowInputMethodPicker() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::UnregisterSurfaceTextureFrameListener_t::name[];
+constexpr char GeckoAppShell::UnregisterSurfaceTextureFrameListener_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jShowInputMethodPicker);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::UnregisterSurfaceTextureFrameListener(mozilla::jni::Object::Param a0)
+{
+    return mozilla::jni::Method<UnregisterSurfaceTextureFrameListener_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::StartMonitoringGamepad() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::Vibrate1_t::name[];
+constexpr char GeckoAppShell::Vibrate1_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jStartMonitoringGamepad);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::Vibrate1(int64_t a0)
+{
+    return mozilla::jni::Method<Vibrate1_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::StopMonitoringGamepad() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::VibrateA_t::name[];
+constexpr char GeckoAppShell::VibrateA_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jStopMonitoringGamepad);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::VibrateA(mozilla::jni::LongArray::Param a0, int32_t a1)
+{
+    return mozilla::jni::Method<VibrateA_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-bool GeckoAppShell::UnlockProfile() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::name[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jUnlockProfile);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
-}
+constexpr char GeckoJavaSampler::GetFrameNameJavaProfilingWrapper_t::name[];
+constexpr char GeckoJavaSampler::GetFrameNameJavaProfilingWrapper_t::signature[];
 
-void GeckoAppShell::UnlockScreenOrientation() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jUnlockScreenOrientation);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::String::LocalRef GeckoJavaSampler::GetFrameNameJavaProfilingWrapper(int32_t a0, int32_t a1, int32_t a2)
+{
+    return mozilla::jni::Method<GetFrameNameJavaProfilingWrapper_t>::Call(nullptr, nullptr, a0, a1, a2);
 }
 
-void GeckoAppShell::UnregisterSurfaceTextureFrameListener(jobject a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::GetSampleTimeJavaProfiling_t::name[];
+constexpr char GeckoJavaSampler::GetSampleTimeJavaProfiling_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jUnregisterSurfaceTextureFrameListener, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+double GeckoJavaSampler::GetSampleTimeJavaProfiling(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<GetSampleTimeJavaProfiling_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::Vibrate1(int64_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::GetThreadNameJavaProfilingWrapper_t::name[];
+constexpr char GeckoJavaSampler::GetThreadNameJavaProfilingWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jVibrate1, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::String::LocalRef GeckoJavaSampler::GetThreadNameJavaProfilingWrapper(int32_t a0)
+{
+    return mozilla::jni::Method<GetThreadNameJavaProfilingWrapper_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::VibrateA(jlongArray a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::PauseJavaProfiling_t::name[];
+constexpr char GeckoJavaSampler::PauseJavaProfiling_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jVibrateA, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-jclass GeckoJavaSampler::mGeckoJavaSamplerClass = 0;
-jmethodID GeckoJavaSampler::jGetFrameNameJavaProfilingWrapper = 0;
-jmethodID GeckoJavaSampler::jGetSampleTimeJavaProfiling = 0;
-jmethodID GeckoJavaSampler::jGetThreadNameJavaProfilingWrapper = 0;
-jmethodID GeckoJavaSampler::jPauseJavaProfiling = 0;
-jmethodID GeckoJavaSampler::jStartJavaProfiling = 0;
-jmethodID GeckoJavaSampler::jStopJavaProfiling = 0;
-jmethodID GeckoJavaSampler::jUnpauseJavaProfiling = 0;
-void GeckoJavaSampler::InitStubs(JNIEnv *env) {
-    mGeckoJavaSamplerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/GeckoJavaSampler");
-    jGetFrameNameJavaProfilingWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getFrameName", "(III)Ljava/lang/String;");
-    jGetSampleTimeJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getSampleTime", "(II)D");
-    jGetThreadNameJavaProfilingWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getThreadName", "(I)Ljava/lang/String;");
-    jPauseJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "pause", "()V");
-    jStartJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "start", "(II)V");
-    jStopJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "stop", "()V");
-    jUnpauseJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "unpause", "()V");
+void GeckoJavaSampler::PauseJavaProfiling()
+{
+    return mozilla::jni::Method<PauseJavaProfiling_t>::Call(nullptr, nullptr);
 }
 
-GeckoJavaSampler* GeckoJavaSampler::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    GeckoJavaSampler* ret = new GeckoJavaSampler(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char GeckoJavaSampler::StartJavaProfiling_t::name[];
+constexpr char GeckoJavaSampler::StartJavaProfiling_t::signature[];
+
+void GeckoJavaSampler::StartJavaProfiling(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<StartJavaProfiling_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jstring GeckoJavaSampler::GetFrameNameJavaProfilingWrapper(int32_t a0, int32_t a1, int32_t a2) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::StopJavaProfiling_t::name[];
+constexpr char GeckoJavaSampler::StopJavaProfiling_t::signature[];
 
-    jvalue args[3];
-    args[0].i = a0;
-    args[1].i = a1;
-    args[2].i = a2;
-
-    jobject temp = env->CallStaticObjectMethodA(mGeckoJavaSamplerClass, jGetFrameNameJavaProfilingWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoJavaSampler::StopJavaProfiling()
+{
+    return mozilla::jni::Method<StopJavaProfiling_t>::Call(nullptr, nullptr);
 }
 
-jdouble GeckoJavaSampler::GetSampleTimeJavaProfiling(int32_t a0, int32_t a1) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::UnpauseJavaProfiling_t::name[];
+constexpr char GeckoJavaSampler::UnpauseJavaProfiling_t::signature[];
 
-    jdouble temp = env->CallStaticDoubleMethod(mGeckoJavaSamplerClass, jGetSampleTimeJavaProfiling, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
-}
-
-jstring GeckoJavaSampler::GetThreadNameJavaProfilingWrapper(int32_t a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoJavaSamplerClass, jGetThreadNameJavaProfilingWrapper, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoJavaSampler::UnpauseJavaProfiling()
+{
+    return mozilla::jni::Method<UnpauseJavaProfiling_t>::Call(nullptr, nullptr);
 }
 
-void GeckoJavaSampler::PauseJavaProfiling() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char RestrictedProfiles::name[];
 
-    env->CallStaticVoidMethod(mGeckoJavaSamplerClass, jPauseJavaProfiling);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+constexpr char RestrictedProfiles::GetUserRestrictions_t::name[];
+constexpr char RestrictedProfiles::GetUserRestrictions_t::signature[];
+
+mozilla::jni::String::LocalRef RestrictedProfiles::GetUserRestrictions()
+{
+    return mozilla::jni::Method<GetUserRestrictions_t>::Call(nullptr, nullptr);
 }
 
-void GeckoJavaSampler::StartJavaProfiling(int32_t a0, int32_t a1) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char RestrictedProfiles::IsAllowed_t::name[];
+constexpr char RestrictedProfiles::IsAllowed_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoJavaSamplerClass, jStartJavaProfiling, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool RestrictedProfiles::IsAllowed(int32_t a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<IsAllowed_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoJavaSampler::StopJavaProfiling() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char RestrictedProfiles::IsUserRestricted_t::name[];
+constexpr char RestrictedProfiles::IsUserRestricted_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoJavaSamplerClass, jStopJavaProfiling);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool RestrictedProfiles::IsUserRestricted()
+{
+    return mozilla::jni::Method<IsUserRestricted_t>::Call(nullptr, nullptr);
 }
 
-void GeckoJavaSampler::UnpauseJavaProfiling() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char SurfaceBits::name[];
 
-    env->CallStaticVoidMethod(mGeckoJavaSamplerClass, jUnpauseJavaProfiling);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-jclass RestrictedProfiles::mRestrictedProfilesClass = 0;
-jmethodID RestrictedProfiles::jGetUserRestrictions = 0;
-jmethodID RestrictedProfiles::jIsAllowed = 0;
-jmethodID RestrictedProfiles::jIsUserRestricted = 0;
-void RestrictedProfiles::InitStubs(JNIEnv *env) {
-    mRestrictedProfilesClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/RestrictedProfiles");
-    jGetUserRestrictions = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "getUserRestrictions", "()Ljava/lang/String;");
-    jIsAllowed = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "isAllowed", "(ILjava/lang/String;)Z");
-    jIsUserRestricted = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "isUserRestricted", "()Z");
+constexpr char SurfaceBits::New_t::name[];
+constexpr char SurfaceBits::New_t::signature[];
+
+SurfaceBits::LocalRef SurfaceBits::New()
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr);
 }
 
-RestrictedProfiles* RestrictedProfiles::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    RestrictedProfiles* ret = new RestrictedProfiles(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char SurfaceBits::Buffer_t::name[];
+constexpr char SurfaceBits::Buffer_t::signature[];
+
+mozilla::jni::Object::LocalRef SurfaceBits::Buffer() const
+{
+    return mozilla::jni::Field<Buffer_t>::Get(this, nullptr);
 }
 
-jstring RestrictedProfiles::GetUserRestrictions() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jobject temp = env->CallStaticObjectMethod(mRestrictedProfilesClass, jGetUserRestrictions);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void SurfaceBits::Buffer(mozilla::jni::Object::Param a0) const
+{
+    return mozilla::jni::Field<Buffer_t>::Set(this, nullptr, a0);
 }
 
-bool RestrictedProfiles::IsAllowed(int32_t a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char SurfaceBits::Format_t::name[];
+constexpr char SurfaceBits::Format_t::signature[];
 
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
-
-    bool temp = env->CallStaticBooleanMethod(mRestrictedProfilesClass, jIsAllowed, a0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+int32_t SurfaceBits::Format() const
+{
+    return mozilla::jni::Field<Format_t>::Get(this, nullptr);
 }
 
-bool RestrictedProfiles::IsUserRestricted() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    bool temp = env->CallStaticBooleanMethod(mRestrictedProfilesClass, jIsUserRestricted);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
-}
-jclass SurfaceBits::mSurfaceBitsClass = 0;
-jmethodID SurfaceBits::jSurfaceBits = 0;
-jfieldID SurfaceBits::jbuffer = 0;
-jfieldID SurfaceBits::jformat = 0;
-jfieldID SurfaceBits::jheight = 0;
-jfieldID SurfaceBits::jwidth = 0;
-void SurfaceBits::InitStubs(JNIEnv *env) {
-    mSurfaceBitsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/SurfaceBits");
-    jSurfaceBits = AndroidBridge::GetMethodID(env, mSurfaceBitsClass, "<init>", "()V");
-    jbuffer = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "buffer", "Ljava/nio/ByteBuffer;");
-    jformat = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "format", "I");
-    jheight = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "height", "I");
-    jwidth = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "width", "I");
+void SurfaceBits::Format(int32_t a0) const
+{
+    return mozilla::jni::Field<Format_t>::Set(this, nullptr, a0);
 }
 
-SurfaceBits* SurfaceBits::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    SurfaceBits* ret = new SurfaceBits(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char SurfaceBits::Height_t::name[];
+constexpr char SurfaceBits::Height_t::signature[];
+
+int32_t SurfaceBits::Height() const
+{
+    return mozilla::jni::Field<Height_t>::Get(this, nullptr);
 }
 
-SurfaceBits::SurfaceBits() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    Init(env->NewObject(mSurfaceBitsClass, jSurfaceBits), env);
-    env->PopLocalFrame(nullptr);
+void SurfaceBits::Height(int32_t a0) const
+{
+    return mozilla::jni::Field<Height_t>::Set(this, nullptr, a0);
 }
 
-jobject SurfaceBits::getbuffer() {
-    JNIEnv *env = GetJNIForThread();
-    return static_cast<jobject>(env->GetObjectField(wrapped_obj, jbuffer));
-}
+constexpr char SurfaceBits::Width_t::name[];
+constexpr char SurfaceBits::Width_t::signature[];
 
-void SurfaceBits::setbuffer(jobject a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetObjectField(wrapped_obj, jbuffer, a0);
+int32_t SurfaceBits::Width() const
+{
+    return mozilla::jni::Field<Width_t>::Get(this, nullptr);
 }
 
-int32_t SurfaceBits::getformat() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetIntField(wrapped_obj, jformat);
-}
-
-void SurfaceBits::setformat(int32_t a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetIntField(wrapped_obj, jformat, a0);
-}
-
-int32_t SurfaceBits::getheight() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetIntField(wrapped_obj, jheight);
+void SurfaceBits::Width(int32_t a0) const
+{
+    return mozilla::jni::Field<Width_t>::Set(this, nullptr, a0);
 }
 
-void SurfaceBits::setheight(int32_t a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetIntField(wrapped_obj, jheight, a0);
-}
+constexpr char ThumbnailHelper::name[];
 
-int32_t SurfaceBits::getwidth() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetIntField(wrapped_obj, jwidth);
+constexpr char ThumbnailHelper::SendThumbnail_t::name[];
+constexpr char ThumbnailHelper::SendThumbnail_t::signature[];
+
+void ThumbnailHelper::SendThumbnail(mozilla::jni::Object::Param a0, int32_t a1, bool a2, bool a3)
+{
+    return mozilla::jni::Method<SendThumbnail_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-void SurfaceBits::setwidth(int32_t a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetIntField(wrapped_obj, jwidth, a0);
-}
-jclass ThumbnailHelper::mThumbnailHelperClass = 0;
-jmethodID ThumbnailHelper::jSendThumbnail = 0;
-void ThumbnailHelper::InitStubs(JNIEnv *env) {
-    mThumbnailHelperClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/ThumbnailHelper");
-    jSendThumbnail = AndroidBridge::GetStaticMethodID(env, mThumbnailHelperClass, "notifyThumbnail", "(Ljava/nio/ByteBuffer;IZZ)V");
-}
+constexpr char DisplayPortMetrics::name[];
 
-ThumbnailHelper* ThumbnailHelper::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    ThumbnailHelper* ret = new ThumbnailHelper(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char DisplayPortMetrics::New_t::name[];
+constexpr char DisplayPortMetrics::New_t::signature[];
+
+DisplayPortMetrics::LocalRef DisplayPortMetrics::New(float a0, float a1, float a2, float a3, float a4)
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4);
 }
 
-void ThumbnailHelper::SendThumbnail(jobject a0, int32_t a1, bool a2, bool a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jvalue args[4];
-    args[0].l = a0;
-    args[1].i = a1;
-    args[2].z = a2;
-    args[3].z = a3;
+constexpr char DisplayPortMetrics::MPosition_t::name[];
+constexpr char DisplayPortMetrics::MPosition_t::signature[];
 
-    env->CallStaticVoidMethodA(mThumbnailHelperClass, jSendThumbnail, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-jclass DisplayPortMetrics::mDisplayPortMetricsClass = 0;
-jmethodID DisplayPortMetrics::jDisplayPortMetrics = 0;
-jfieldID DisplayPortMetrics::jMPosition = 0;
-jfieldID DisplayPortMetrics::jResolution = 0;
-void DisplayPortMetrics::InitStubs(JNIEnv *env) {
-    mDisplayPortMetricsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/DisplayPortMetrics");
-    jDisplayPortMetrics = AndroidBridge::GetMethodID(env, mDisplayPortMetricsClass, "<init>", "(FFFFF)V");
-    jMPosition = AndroidBridge::GetFieldID(env, mDisplayPortMetricsClass, "mPosition", "Landroid/graphics/RectF;");
-    jResolution = AndroidBridge::GetFieldID(env, mDisplayPortMetricsClass, "resolution", "F");
+mozilla::jni::Object::LocalRef DisplayPortMetrics::MPosition() const
+{
+    return mozilla::jni::Field<MPosition_t>::Get(this, nullptr);
 }
 
-DisplayPortMetrics* DisplayPortMetrics::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    DisplayPortMetrics* ret = new DisplayPortMetrics(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char DisplayPortMetrics::Resolution_t::name[];
+constexpr char DisplayPortMetrics::Resolution_t::signature[];
+
+float DisplayPortMetrics::Resolution() const
+{
+    return mozilla::jni::Field<Resolution_t>::Get(this, nullptr);
 }
 
-DisplayPortMetrics::DisplayPortMetrics(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GLController::name[];
 
-    jvalue args[5];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
+constexpr char GLController::CreateEGLSurfaceForCompositorWrapper_t::name[];
+constexpr char GLController::CreateEGLSurfaceForCompositorWrapper_t::signature[];
 
-    Init(env->NewObjectA(mDisplayPortMetricsClass, jDisplayPortMetrics, args), env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::Object::LocalRef GLController::CreateEGLSurfaceForCompositorWrapper() const
+{
+    return mozilla::jni::Method<CreateEGLSurfaceForCompositorWrapper_t>::Call(this, nullptr);
 }
 
-jobject DisplayPortMetrics::getMPosition() {
-    JNIEnv *env = GetJNIForThread();
-    return static_cast<jobject>(env->GetObjectField(wrapped_obj, jMPosition));
+constexpr char GeckoLayerClient::name[];
+
+constexpr char GeckoLayerClient::ActivateProgram_t::name[];
+constexpr char GeckoLayerClient::ActivateProgram_t::signature[];
+
+void GeckoLayerClient::ActivateProgram() const
+{
+    return mozilla::jni::Method<ActivateProgram_t>::Call(this, nullptr);
 }
 
-jfloat DisplayPortMetrics::getResolution() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jResolution);
-}
-jclass GLController::mGLControllerClass = 0;
-jmethodID GLController::jCreateEGLSurfaceForCompositorWrapper = 0;
-void GLController::InitStubs(JNIEnv *env) {
-    mGLControllerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/GLController");
-    jCreateEGLSurfaceForCompositorWrapper = AndroidBridge::GetMethodID(env, mGLControllerClass, "createEGLSurfaceForCompositor", "()Ljavax/microedition/khronos/egl/EGLSurface;");
-}
+constexpr char GeckoLayerClient::ContentDocumentChanged_t::name[];
+constexpr char GeckoLayerClient::ContentDocumentChanged_t::signature[];
 
-GLController* GLController::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    GLController* ret = new GLController(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void GeckoLayerClient::ContentDocumentChanged() const
+{
+    return mozilla::jni::Method<ContentDocumentChanged_t>::Call(this, nullptr);
 }
 
-jobject GLController::CreateEGLSurfaceForCompositorWrapper() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::CreateFrame_t::name[];
+constexpr char GeckoLayerClient::CreateFrame_t::signature[];
 
-    jobject temp = env->CallObjectMethod(wrapped_obj, jCreateEGLSurfaceForCompositorWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::Object::LocalRef GeckoLayerClient::CreateFrame() const
+{
+    return mozilla::jni::Method<CreateFrame_t>::Call(this, nullptr);
 }
-jclass GeckoLayerClient::mGeckoLayerClientClass = 0;
-jmethodID GeckoLayerClient::jActivateProgram = 0;
-jmethodID GeckoLayerClient::jContentDocumentChanged = 0;
-jmethodID GeckoLayerClient::jCreateFrame = 0;
-jmethodID GeckoLayerClient::jDeactivateProgramAndRestoreState = 0;
-jmethodID GeckoLayerClient::jGetDisplayPort = 0;
-jmethodID GeckoLayerClient::jIsContentDocumentDisplayed = 0;
-jmethodID GeckoLayerClient::jProgressiveUpdateCallback = 0;
-jmethodID GeckoLayerClient::jSetFirstPaintViewport = 0;
-jmethodID GeckoLayerClient::jSetPageRect = 0;
-jmethodID GeckoLayerClient::jSyncFrameMetrics = 0;
-jmethodID GeckoLayerClient::jSyncViewportInfo = 0;
-void GeckoLayerClient::InitStubs(JNIEnv *env) {
-    mGeckoLayerClientClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/GeckoLayerClient");
-    jActivateProgram = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "activateProgram", "()V");
-    jContentDocumentChanged = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "contentDocumentChanged", "()V");
-    jCreateFrame = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;");
-    jDeactivateProgramAndRestoreState = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "deactivateProgramAndRestoreState", "(ZIIII)V");
-    jGetDisplayPort = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "getDisplayPort", "(ZZILorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)Lorg/mozilla/gecko/gfx/DisplayPortMetrics;");
-    jIsContentDocumentDisplayed = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "isContentDocumentDisplayed", "()Z");
-    jProgressiveUpdateCallback = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "progressiveUpdateCallback", "(ZFFFFFZ)Lorg/mozilla/gecko/gfx/ProgressiveUpdateData;");
-    jSetFirstPaintViewport = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "setFirstPaintViewport", "(FFFFFFF)V");
-    jSetPageRect = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "setPageRect", "(FFFF)V");
-    jSyncFrameMetrics = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "syncFrameMetrics", "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;");
-    jSyncViewportInfo = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "syncViewportInfo", "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;");
+
+constexpr char GeckoLayerClient::DeactivateProgramAndRestoreState_t::name[];
+constexpr char GeckoLayerClient::DeactivateProgramAndRestoreState_t::signature[];
+
+void GeckoLayerClient::DeactivateProgramAndRestoreState(bool a0, int32_t a1, int32_t a2, int32_t a3, int32_t a4) const
+{
+    return mozilla::jni::Method<DeactivateProgramAndRestoreState_t>::Call(this, nullptr, a0, a1, a2, a3, a4);
 }
 
-GeckoLayerClient* GeckoLayerClient::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    GeckoLayerClient* ret = new GeckoLayerClient(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
-}
+constexpr char GeckoLayerClient::GetDisplayPort_t::name[];
+constexpr char GeckoLayerClient::GetDisplayPort_t::signature[];
 
-void GeckoLayerClient::ActivateProgram() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallVoidMethod(wrapped_obj, jActivateProgram);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::Object::LocalRef GeckoLayerClient::GetDisplayPort(bool a0, bool a1, int32_t a2, mozilla::jni::Object::Param a3) const
+{
+    return mozilla::jni::Method<GetDisplayPort_t>::Call(this, nullptr, a0, a1, a2, a3);
 }
 
-void GeckoLayerClient::ContentDocumentChanged() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::IsContentDocumentDisplayed_t::name[];
+constexpr char GeckoLayerClient::IsContentDocumentDisplayed_t::signature[];
 
-    env->CallVoidMethod(wrapped_obj, jContentDocumentChanged);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool GeckoLayerClient::IsContentDocumentDisplayed() const
+{
+    return mozilla::jni::Method<IsContentDocumentDisplayed_t>::Call(this, nullptr);
 }
 
-jobject GeckoLayerClient::CreateFrame() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::ProgressiveUpdateCallback_t::name[];
+constexpr char GeckoLayerClient::ProgressiveUpdateCallback_t::signature[];
 
-    jobject temp = env->CallObjectMethod(wrapped_obj, jCreateFrame);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::Object::LocalRef GeckoLayerClient::ProgressiveUpdateCallback(bool a0, float a1, float a2, float a3, float a4, float a5, bool a6) const
+{
+    return mozilla::jni::Method<ProgressiveUpdateCallback_t>::Call(this, nullptr, a0, a1, a2, a3, a4, a5, a6);
 }
 
-void GeckoLayerClient::DeactivateProgramAndRestoreState(bool a0, int32_t a1, int32_t a2, int32_t a3, int32_t a4) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::SetFirstPaintViewport_t::name[];
+constexpr char GeckoLayerClient::SetFirstPaintViewport_t::signature[];
 
-    jvalue args[5];
-    args[0].z = a0;
-    args[1].i = a1;
-    args[2].i = a2;
-    args[3].i = a3;
-    args[4].i = a4;
-
-    env->CallVoidMethodA(wrapped_obj, jDeactivateProgramAndRestoreState, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoLayerClient::SetFirstPaintViewport(float a0, float a1, float a2, float a3, float a4, float a5, float a6) const
+{
+    return mozilla::jni::Method<SetFirstPaintViewport_t>::Call(this, nullptr, a0, a1, a2, a3, a4, a5, a6);
 }
 
-jobject GeckoLayerClient::GetDisplayPort(bool a0, bool a1, int32_t a2, jobject a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::SetPageRect_t::name[];
+constexpr char GeckoLayerClient::SetPageRect_t::signature[];
 
-    jvalue args[4];
-    args[0].z = a0;
-    args[1].z = a1;
-    args[2].i = a2;
-    args[3].l = a3;
-
-    jobject temp = env->CallObjectMethodA(wrapped_obj, jGetDisplayPort, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoLayerClient::SetPageRect(float a0, float a1, float a2, float a3) const
+{
+    return mozilla::jni::Method<SetPageRect_t>::Call(this, nullptr, a0, a1, a2, a3);
 }
 
-bool GeckoLayerClient::IsContentDocumentDisplayed() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::SyncFrameMetrics_t::name[];
+constexpr char GeckoLayerClient::SyncFrameMetrics_t::signature[];
 
-    bool temp = env->CallBooleanMethod(wrapped_obj, jIsContentDocumentDisplayed);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+mozilla::jni::Object::LocalRef GeckoLayerClient::SyncFrameMetrics(float a0, float a1, float a2, float a3, float a4, float a5, float a6, bool a7, int32_t a8, int32_t a9, int32_t a10, int32_t a11, float a12, bool a13) const
+{
+    return mozilla::jni::Method<SyncFrameMetrics_t>::Call(this, nullptr, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13);
 }
 
-jobject GeckoLayerClient::ProgressiveUpdateCallback(bool a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, bool a6) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::SyncViewportInfo_t::name[];
+constexpr char GeckoLayerClient::SyncViewportInfo_t::signature[];
 
-    jvalue args[7];
-    args[0].z = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
-    args[5].f = a5;
-    args[6].z = a6;
-
-    jobject temp = env->CallObjectMethodA(wrapped_obj, jProgressiveUpdateCallback, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::Object::LocalRef GeckoLayerClient::SyncViewportInfo(int32_t a0, int32_t a1, int32_t a2, int32_t a3, float a4, bool a5) const
+{
+    return mozilla::jni::Method<SyncViewportInfo_t>::Call(this, nullptr, a0, a1, a2, a3, a4, a5);
 }
 
-void GeckoLayerClient::SetFirstPaintViewport(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ImmutableViewportMetrics::name[];
 
-    jvalue args[7];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
-    args[5].f = a5;
-    args[6].f = a6;
+constexpr char ImmutableViewportMetrics::New_t::name[];
+constexpr char ImmutableViewportMetrics::New_t::signature[];
 
-    env->CallVoidMethodA(wrapped_obj, jSetFirstPaintViewport, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+ImmutableViewportMetrics::LocalRef ImmutableViewportMetrics::New(float a0, float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8, float a9, float a10, float a11, float a12)
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
 }
 
-void GeckoLayerClient::SetPageRect(jfloat a0, jfloat a1, jfloat a2, jfloat a3) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char LayerView::name[];
 
-    jvalue args[4];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
+constexpr char LayerView::RegisterCompositorWrapper_t::name[];
+constexpr char LayerView::RegisterCompositorWrapper_t::signature[];
 
-    env->CallVoidMethodA(wrapped_obj, jSetPageRect, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::Object::LocalRef LayerView::RegisterCompositorWrapper()
+{
+    return mozilla::jni::Method<RegisterCompositorWrapper_t>::Call(nullptr, nullptr);
 }
 
-jobject GeckoLayerClient::SyncFrameMetrics(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6, bool a7, int32_t a8, int32_t a9, int32_t a10, int32_t a11, jfloat a12, bool a13) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char NativePanZoomController::name[];
+
+constexpr char NativePanZoomController::RequestContentRepaintWrapper_t::name[];
+constexpr char NativePanZoomController::RequestContentRepaintWrapper_t::signature[];
+
+void NativePanZoomController::RequestContentRepaintWrapper(float a0, float a1, float a2, float a3, float a4) const
+{
+    return mozilla::jni::Method<RequestContentRepaintWrapper_t>::Call(this, nullptr, a0, a1, a2, a3, a4);
+}
+
+constexpr char ProgressiveUpdateData::name[];
 
-    jvalue args[14];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
-    args[5].f = a5;
-    args[6].f = a6;
-    args[7].z = a7;
-    args[8].i = a8;
-    args[9].i = a9;
-    args[10].i = a10;
-    args[11].i = a11;
-    args[12].f = a12;
-    args[13].z = a13;
+constexpr char ProgressiveUpdateData::New_t::name[];
+constexpr char ProgressiveUpdateData::New_t::signature[];
 
-    jobject temp = env->CallObjectMethodA(wrapped_obj, jSyncFrameMetrics, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+ProgressiveUpdateData::LocalRef ProgressiveUpdateData::New()
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr);
+}
+
+constexpr char ProgressiveUpdateData::SetViewport_t::name[];
+constexpr char ProgressiveUpdateData::SetViewport_t::signature[];
+
+void ProgressiveUpdateData::SetViewport(mozilla::jni::Object::Param a0) const
+{
+    return mozilla::jni::Method<SetViewport_t>::Call(this, nullptr, a0);
 }
 
-jobject GeckoLayerClient::SyncViewportInfo(int32_t a0, int32_t a1, int32_t a2, int32_t a3, jfloat a4, bool a5) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ProgressiveUpdateData::Abort_t::name[];
+constexpr char ProgressiveUpdateData::Abort_t::signature[];
 
-    jvalue args[6];
-    args[0].i = a0;
-    args[1].i = a1;
-    args[2].i = a2;
-    args[3].i = a3;
-    args[4].f = a4;
-    args[5].z = a5;
-
-    jobject temp = env->CallObjectMethodA(wrapped_obj, jSyncViewportInfo, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
-}
-jclass ImmutableViewportMetrics::mImmutableViewportMetricsClass = 0;
-jmethodID ImmutableViewportMetrics::jImmutableViewportMetrics = 0;
-void ImmutableViewportMetrics::InitStubs(JNIEnv *env) {
-    mImmutableViewportMetricsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ImmutableViewportMetrics");
-    jImmutableViewportMetrics = AndroidBridge::GetMethodID(env, mImmutableViewportMetricsClass, "<init>", "(FFFFFFFFFFFFF)V");
+bool ProgressiveUpdateData::Abort() const
+{
+    return mozilla::jni::Field<Abort_t>::Get(this, nullptr);
 }
 
-ImmutableViewportMetrics* ImmutableViewportMetrics::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    ImmutableViewportMetrics* ret = new ImmutableViewportMetrics(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void ProgressiveUpdateData::Abort(bool a0) const
+{
+    return mozilla::jni::Field<Abort_t>::Set(this, nullptr, a0);
 }
 
-ImmutableViewportMetrics::ImmutableViewportMetrics(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6, jfloat a7, jfloat a8, jfloat a9, jfloat a10, jfloat a11, jfloat a12) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ProgressiveUpdateData::Scale_t::name[];
+constexpr char ProgressiveUpdateData::Scale_t::signature[];
 
-    jvalue args[13];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
-    args[5].f = a5;
-    args[6].f = a6;
-    args[7].f = a7;
-    args[8].f = a8;
-    args[9].f = a9;
-    args[10].f = a10;
-    args[11].f = a11;
-    args[12].f = a12;
-
-    Init(env->NewObjectA(mImmutableViewportMetricsClass, jImmutableViewportMetrics, args), env);
-    env->PopLocalFrame(nullptr);
-}
-jclass LayerView::mLayerViewClass = 0;
-jmethodID LayerView::jRegisterCompositorWrapper = 0;
-void LayerView::InitStubs(JNIEnv *env) {
-    mLayerViewClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/LayerView");
-    jRegisterCompositorWrapper = AndroidBridge::GetStaticMethodID(env, mLayerViewClass, "registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;");
+float ProgressiveUpdateData::Scale() const
+{
+    return mozilla::jni::Field<Scale_t>::Get(this, nullptr);
 }
 
-LayerView* LayerView::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    LayerView* ret = new LayerView(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void ProgressiveUpdateData::Scale(float a0) const
+{
+    return mozilla::jni::Field<Scale_t>::Set(this, nullptr, a0);
 }
 
-jobject LayerView::RegisterCompositorWrapper() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ProgressiveUpdateData::X_t::name[];
+constexpr char ProgressiveUpdateData::X_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mLayerViewClass, jRegisterCompositorWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
-}
-jclass NativePanZoomController::mNativePanZoomControllerClass = 0;
-jmethodID NativePanZoomController::jRequestContentRepaintWrapper = 0;
-void NativePanZoomController::InitStubs(JNIEnv *env) {
-    mNativePanZoomControllerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/NativePanZoomController");
-    jRequestContentRepaintWrapper = AndroidBridge::GetMethodID(env, mNativePanZoomControllerClass, "requestContentRepaint", "(FFFFF)V");
+float ProgressiveUpdateData::X() const
+{
+    return mozilla::jni::Field<X_t>::Get(this, nullptr);
 }
 
-NativePanZoomController* NativePanZoomController::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    NativePanZoomController* ret = new NativePanZoomController(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void ProgressiveUpdateData::X(float a0) const
+{
+    return mozilla::jni::Field<X_t>::Set(this, nullptr, a0);
 }
 
-void NativePanZoomController::RequestContentRepaintWrapper(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jvalue args[5];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
+constexpr char ProgressiveUpdateData::Y_t::name[];
+constexpr char ProgressiveUpdateData::Y_t::signature[];
 
-    env->CallVoidMethodA(wrapped_obj, jRequestContentRepaintWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+float ProgressiveUpdateData::Y() const
+{
+    return mozilla::jni::Field<Y_t>::Get(this, nullptr);
 }
-jclass ProgressiveUpdateData::mProgressiveUpdateDataClass = 0;
-jmethodID ProgressiveUpdateData::jProgressiveUpdateData = 0;
-jmethodID ProgressiveUpdateData::jsetViewport = 0;
-jfieldID ProgressiveUpdateData::jabort = 0;
-jfieldID ProgressiveUpdateData::jscale = 0;
-jfieldID ProgressiveUpdateData::jx = 0;
-jfieldID ProgressiveUpdateData::jy = 0;
-void ProgressiveUpdateData::InitStubs(JNIEnv *env) {
-    mProgressiveUpdateDataClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ProgressiveUpdateData");
-    jProgressiveUpdateData = AndroidBridge::GetMethodID(env, mProgressiveUpdateDataClass, "<init>", "()V");
-    jsetViewport = AndroidBridge::GetMethodID(env, mProgressiveUpdateDataClass, "setViewport", "(Lorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)V");
-    jabort = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "abort", "Z");
-    jscale = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "scale", "F");
-    jx = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "x", "F");
-    jy = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "y", "F");
+
+void ProgressiveUpdateData::Y(float a0) const
+{
+    return mozilla::jni::Field<Y_t>::Set(this, nullptr, a0);
 }
 
-ProgressiveUpdateData* ProgressiveUpdateData::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    ProgressiveUpdateData* ret = new ProgressiveUpdateData(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
-}
+constexpr char ViewTransform::name[];
 
-ProgressiveUpdateData::ProgressiveUpdateData() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ViewTransform::New_t::name[];
+constexpr char ViewTransform::New_t::signature[];
 
-    Init(env->NewObject(mProgressiveUpdateDataClass, jProgressiveUpdateData), env);
-    env->PopLocalFrame(nullptr);
+ViewTransform::LocalRef ViewTransform::New(float a0, float a1, float a2)
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr, a0, a1, a2);
 }
 
-void ProgressiveUpdateData::setViewport(jobject a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ViewTransform::FixedLayerMarginBottom_t::name[];
+constexpr char ViewTransform::FixedLayerMarginBottom_t::signature[];
 
-    env->CallVoidMethod(wrapped_obj, jsetViewport, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+float ViewTransform::FixedLayerMarginBottom() const
+{
+    return mozilla::jni::Field<FixedLayerMarginBottom_t>::Get(this, nullptr);
 }
 
-bool ProgressiveUpdateData::getabort() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetBooleanField(wrapped_obj, jabort);
-}
-
-void ProgressiveUpdateData::setabort(bool a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetBooleanField(wrapped_obj, jabort, a0);
-}
-
-jfloat ProgressiveUpdateData::getscale() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jscale);
+void ViewTransform::FixedLayerMarginBottom(float a0) const
+{
+    return mozilla::jni::Field<FixedLayerMarginBottom_t>::Set(this, nullptr, a0);
 }
 
-void ProgressiveUpdateData::setscale(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jscale, a0);
+constexpr char ViewTransform::FixedLayerMarginLeft_t::name[];
+constexpr char ViewTransform::FixedLayerMarginLeft_t::signature[];
+
+float ViewTransform::FixedLayerMarginLeft() const
+{
+    return mozilla::jni::Field<FixedLayerMarginLeft_t>::Get(this, nullptr);
 }
 
-jfloat ProgressiveUpdateData::getx() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jx);
+void ViewTransform::FixedLayerMarginLeft(float a0) const
+{
+    return mozilla::jni::Field<FixedLayerMarginLeft_t>::Set(this, nullptr, a0);
 }
 
-void ProgressiveUpdateData::setx(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jx, a0);
-}
+constexpr char ViewTransform::FixedLayerMarginRight_t::name[];
+constexpr char ViewTransform::FixedLayerMarginRight_t::signature[];
 
-jfloat ProgressiveUpdateData::gety() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jy);
+float ViewTransform::FixedLayerMarginRight() const
+{
+    return mozilla::jni::Field<FixedLayerMarginRight_t>::Get(this, nullptr);
 }
 
-void ProgressiveUpdateData::sety(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jy, a0);
+void ViewTransform::FixedLayerMarginRight(float a0) const
+{
+    return mozilla::jni::Field<FixedLayerMarginRight_t>::Set(this, nullptr, a0);
 }
-jclass ViewTransform::mViewTransformClass = 0;
-jmethodID ViewTransform::jViewTransform = 0;
-jfieldID ViewTransform::jfixedLayerMarginBottom = 0;
-jfieldID ViewTransform::jfixedLayerMarginLeft = 0;
-jfieldID ViewTransform::jfixedLayerMarginRight = 0;
-jfieldID ViewTransform::jfixedLayerMarginTop = 0;
-jfieldID ViewTransform::joffsetX = 0;
-jfieldID ViewTransform::joffsetY = 0;
-jfieldID ViewTransform::jscale = 0;
-jfieldID ViewTransform::jx = 0;
-jfieldID ViewTransform::jy = 0;
-void ViewTransform::InitStubs(JNIEnv *env) {
-    mViewTransformClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ViewTransform");
-    jViewTransform = AndroidBridge::GetMethodID(env, mViewTransformClass, "<init>", "(FFF)V");
-    jfixedLayerMarginBottom = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginBottom", "F");
-    jfixedLayerMarginLeft = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginLeft", "F");
-    jfixedLayerMarginRight = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginRight", "F");
-    jfixedLayerMarginTop = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginTop", "F");
-    joffsetX = AndroidBridge::GetFieldID(env, mViewTransformClass, "offsetX", "F");
-    joffsetY = AndroidBridge::GetFieldID(env, mViewTransformClass, "offsetY", "F");
-    jscale = AndroidBridge::GetFieldID(env, mViewTransformClass, "scale", "F");
-    jx = AndroidBridge::GetFieldID(env, mViewTransformClass, "x", "F");
-    jy = AndroidBridge::GetFieldID(env, mViewTransformClass, "y", "F");
+
+constexpr char ViewTransform::FixedLayerMarginTop_t::name[];
+constexpr char ViewTransform::FixedLayerMarginTop_t::signature[];
+
+float ViewTransform::FixedLayerMarginTop() const
+{
+    return mozilla::jni::Field<FixedLayerMarginTop_t>::Get(this, nullptr);
 }
 
-ViewTransform* ViewTransform::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    ViewTransform* ret = new ViewTransform(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void ViewTransform::FixedLayerMarginTop(float a0) const
+{
+    return mozilla::jni::Field<FixedLayerMarginTop_t>::Set(this, nullptr, a0);
 }
 
-ViewTransform::ViewTransform(jfloat a0, jfloat a1, jfloat a2) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ViewTransform::OffsetX_t::name[];
+constexpr char ViewTransform::OffsetX_t::signature[];
 
-    jvalue args[3];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-
-    Init(env->NewObjectA(mViewTransformClass, jViewTransform, args), env);
-    env->PopLocalFrame(nullptr);
+float ViewTransform::OffsetX() const
+{
+    return mozilla::jni::Field<OffsetX_t>::Get(this, nullptr);
 }
 
-jfloat ViewTransform::getfixedLayerMarginBottom() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jfixedLayerMarginBottom);
-}
-
-void ViewTransform::setfixedLayerMarginBottom(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jfixedLayerMarginBottom, a0);
-}
-
-jfloat ViewTransform::getfixedLayerMarginLeft() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jfixedLayerMarginLeft);
+void ViewTransform::OffsetX(float a0) const
+{
+    return mozilla::jni::Field<OffsetX_t>::Set(this, nullptr, a0);
 }
 
-void ViewTransform::setfixedLayerMarginLeft(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jfixedLayerMarginLeft, a0);
-}
+constexpr char ViewTransform::OffsetY_t::name[];
+constexpr char ViewTransform::OffsetY_t::signature[];
 
-jfloat ViewTransform::getfixedLayerMarginRight() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jfixedLayerMarginRight);
+float ViewTransform::OffsetY() const
+{
+    return mozilla::jni::Field<OffsetY_t>::Get(this, nullptr);
 }
 
-void ViewTransform::setfixedLayerMarginRight(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jfixedLayerMarginRight, a0);
-}
-
-jfloat ViewTransform::getfixedLayerMarginTop() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jfixedLayerMarginTop);
-}
-
-void ViewTransform::setfixedLayerMarginTop(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jfixedLayerMarginTop, a0);
-}
-
-jfloat ViewTransform::getoffsetX() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, joffsetX);
+void ViewTransform::OffsetY(float a0) const
+{
+    return mozilla::jni::Field<OffsetY_t>::Set(this, nullptr, a0);
 }
 
-void ViewTransform::setoffsetX(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, joffsetX, a0);
-}
+constexpr char ViewTransform::Scale_t::name[];
+constexpr char ViewTransform::Scale_t::signature[];
 
-jfloat ViewTransform::getoffsetY() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, joffsetY);
-}
-
-void ViewTransform::setoffsetY(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, joffsetY, a0);
+float ViewTransform::Scale() const
+{
+    return mozilla::jni::Field<Scale_t>::Get(this, nullptr);
 }
 
-jfloat ViewTransform::getscale() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jscale);
-}
-
-void ViewTransform::setscale(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jscale, a0);
+void ViewTransform::Scale(float a0) const
+{
+    return mozilla::jni::Field<Scale_t>::Set(this, nullptr, a0);
 }
 
-jfloat ViewTransform::getx() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jx);
+constexpr char ViewTransform::X_t::name[];
+constexpr char ViewTransform::X_t::signature[];
+
+float ViewTransform::X() const
+{
+    return mozilla::jni::Field<X_t>::Get(this, nullptr);
 }
 
-void ViewTransform::setx(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jx, a0);
-}
-
-jfloat ViewTransform::gety() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jy);
+void ViewTransform::X(float a0) const
+{
+    return mozilla::jni::Field<X_t>::Set(this, nullptr, a0);
 }
 
-void ViewTransform::sety(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jy, a0);
-}
-jclass NativeZip::mNativeZipClass = 0;
-jmethodID NativeZip::jCreateInputStream = 0;
-void NativeZip::InitStubs(JNIEnv *env) {
-    mNativeZipClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/mozglue/NativeZip");
-    jCreateInputStream = AndroidBridge::GetMethodID(env, mNativeZipClass, "createInputStream", "(Ljava/nio/ByteBuffer;I)Ljava/io/InputStream;");
+constexpr char ViewTransform::Y_t::name[];
+constexpr char ViewTransform::Y_t::signature[];
+
+float ViewTransform::Y() const
+{
+    return mozilla::jni::Field<Y_t>::Get(this, nullptr);
 }
 
-NativeZip* NativeZip::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    NativeZip* ret = new NativeZip(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void ViewTransform::Y(float a0) const
+{
+    return mozilla::jni::Field<Y_t>::Set(this, nullptr, a0);
 }
 
-jobject NativeZip::CreateInputStream(jobject a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char NativeZip::name[];
 
-    jobject temp = env->CallObjectMethod(wrapped_obj, jCreateInputStream, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
-}
-jclass MatrixBlobCursor::mMatrixBlobCursorClass = 0;
-jmethodID MatrixBlobCursor::jMatrixBlobCursor = 0;
-jmethodID MatrixBlobCursor::jMatrixBlobCursor0 = 0;
-jmethodID MatrixBlobCursor::jAddRow = 0;
-jmethodID MatrixBlobCursor::jAddRow1 = 0;
-jmethodID MatrixBlobCursor::jAddRow2 = 0;
-void MatrixBlobCursor::InitStubs(JNIEnv *env) {
-    mMatrixBlobCursorClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/sqlite/MatrixBlobCursor");
-    jMatrixBlobCursor = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "<init>", "([Ljava/lang/String;)V");
-    jMatrixBlobCursor0 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "<init>", "([Ljava/lang/String;I)V");
-    jAddRow = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "(Ljava/lang/Iterable;)V");
-    jAddRow1 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "(Ljava/util/ArrayList;I)V");
-    jAddRow2 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "([Ljava/lang/Object;)V");
+constexpr char NativeZip::CreateInputStream_t::name[];
+constexpr char NativeZip::CreateInputStream_t::signature[];
+
+mozilla::jni::Object::LocalRef NativeZip::CreateInputStream(mozilla::jni::Object::Param a0, int32_t a1) const
+{
+    return mozilla::jni::Method<CreateInputStream_t>::Call(this, nullptr, a0, a1);
 }
 
-MatrixBlobCursor* MatrixBlobCursor::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    MatrixBlobCursor* ret = new MatrixBlobCursor(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
-}
+constexpr char MatrixBlobCursor::name[];
 
-MatrixBlobCursor::MatrixBlobCursor(jobjectArray a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char MatrixBlobCursor::New_t::name[];
+constexpr char MatrixBlobCursor::New_t::signature[];
 
-    Init(env->NewObject(mMatrixBlobCursorClass, jMatrixBlobCursor, a0), env);
-    env->PopLocalFrame(nullptr);
+MatrixBlobCursor::LocalRef MatrixBlobCursor::New(mozilla::jni::ObjectArray::Param a0)
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr, a0);
 }
 
-MatrixBlobCursor::MatrixBlobCursor(jobjectArray a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    Init(env->NewObject(mMatrixBlobCursorClass, jMatrixBlobCursor0, a0, a1), env);
-    env->PopLocalFrame(nullptr);
-}
+constexpr char MatrixBlobCursor::New2_t::name[];
+constexpr char MatrixBlobCursor::New2_t::signature[];
 
-void MatrixBlobCursor::AddRow(jobject a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallVoidMethod(wrapped_obj, jAddRow, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+MatrixBlobCursor::LocalRef MatrixBlobCursor::New(mozilla::jni::ObjectArray::Param a0, int32_t a1)
+{
+    return mozilla::jni::Constructor<New2_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void MatrixBlobCursor::AddRow(jobject a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char MatrixBlobCursor::AddRow_t::name[];
+constexpr char MatrixBlobCursor::AddRow_t::signature[];
 
-    env->CallVoidMethod(wrapped_obj, jAddRow1, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void MatrixBlobCursor::AddRow(mozilla::jni::Object::Param a0) const
+{
+    return mozilla::jni::Method<AddRow_t>::Call(this, nullptr, a0);
 }
 
-void MatrixBlobCursor::AddRow(jobjectArray a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char MatrixBlobCursor::AddRow2_t::name[];
+constexpr char MatrixBlobCursor::AddRow2_t::signature[];
 
-    env->CallVoidMethod(wrapped_obj, jAddRow2, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-jclass SQLiteBridgeException::mSQLiteBridgeExceptionClass = 0;
-jmethodID SQLiteBridgeException::jSQLiteBridgeException = 0;
-jmethodID SQLiteBridgeException::jSQLiteBridgeException0 = 0;
-jfieldID SQLiteBridgeException::jserialVersionUID = 0;
-void SQLiteBridgeException::InitStubs(JNIEnv *env) {
-    mSQLiteBridgeExceptionClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/sqlite/SQLiteBridgeException");
-    jSQLiteBridgeException = AndroidBridge::GetMethodID(env, mSQLiteBridgeExceptionClass, "<init>", "()V");
-    jSQLiteBridgeException0 = AndroidBridge::GetMethodID(env, mSQLiteBridgeExceptionClass, "<init>", "(Ljava/lang/String;)V");
-    jserialVersionUID = AndroidBridge::GetStaticFieldID(env, mSQLiteBridgeExceptionClass, "serialVersionUID", "J");
+void MatrixBlobCursor::AddRow(mozilla::jni::Object::Param a0, int32_t a1) const
+{
+    return mozilla::jni::Method<AddRow2_t>::Call(this, nullptr, a0, a1);
 }
 
-SQLiteBridgeException* SQLiteBridgeException::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    SQLiteBridgeException* ret = new SQLiteBridgeException(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
-}
+constexpr char MatrixBlobCursor::AddRow3_t::name[];
+constexpr char MatrixBlobCursor::AddRow3_t::signature[];
 
-SQLiteBridgeException::SQLiteBridgeException() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    Init(env->NewObject(mSQLiteBridgeExceptionClass, jSQLiteBridgeException), env);
-    env->PopLocalFrame(nullptr);
+void MatrixBlobCursor::AddRow(mozilla::jni::ObjectArray::Param a0) const
+{
+    return mozilla::jni::Method<AddRow3_t>::Call(this, nullptr, a0);
 }
 
-SQLiteBridgeException::SQLiteBridgeException(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char SQLiteBridgeException::name[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+constexpr char SQLiteBridgeException::New_t::name[];
+constexpr char SQLiteBridgeException::New_t::signature[];
 
-    Init(env->NewObject(mSQLiteBridgeExceptionClass, jSQLiteBridgeException0, j0), env);
-    env->PopLocalFrame(nullptr);
+SQLiteBridgeException::LocalRef SQLiteBridgeException::New()
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr);
 }
 
-int64_t SQLiteBridgeException::getserialVersionUID() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetStaticLongField(mSQLiteBridgeExceptionClass, jserialVersionUID);
-}
-jclass Clipboard::mClipboardClass = 0;
-jmethodID Clipboard::jClearText = 0;
-jmethodID Clipboard::jGetClipboardTextWrapper = 0;
-jmethodID Clipboard::jHasText = 0;
-jmethodID Clipboard::jSetClipboardText = 0;
-void Clipboard::InitStubs(JNIEnv *env) {
-    mClipboardClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/util/Clipboard");
-    jClearText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "clearText", "()V");
-    jGetClipboardTextWrapper = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "getText", "()Ljava/lang/String;");
-    jHasText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "hasText", "()Z");
-    jSetClipboardText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "setText", "(Ljava/lang/CharSequence;)V");
+constexpr char SQLiteBridgeException::New2_t::name[];
+constexpr char SQLiteBridgeException::New2_t::signature[];
+
+SQLiteBridgeException::LocalRef SQLiteBridgeException::New(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Constructor<New2_t>::Call(nullptr, nullptr, a0);
 }
 
-Clipboard* Clipboard::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    Clipboard* ret = new Clipboard(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char SQLiteBridgeException::SerialVersionUID_t::name[];
+constexpr char SQLiteBridgeException::SerialVersionUID_t::signature[];
+
+int64_t SQLiteBridgeException::SerialVersionUID()
+{
+    return mozilla::jni::Field<SerialVersionUID_t>::Get(nullptr, nullptr);
 }
 
-void Clipboard::ClearText() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mClipboardClass, jClearText);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
+constexpr char Clipboard::name[];
 
-jstring Clipboard::GetClipboardTextWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char Clipboard::ClearText_t::name[];
+constexpr char Clipboard::ClearText_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mClipboardClass, jGetClipboardTextWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void Clipboard::ClearText()
+{
+    return mozilla::jni::Method<ClearText_t>::Call(nullptr, nullptr);
 }
 
-bool Clipboard::HasText() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char Clipboard::GetClipboardTextWrapper_t::name[];
+constexpr char Clipboard::GetClipboardTextWrapper_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mClipboardClass, jHasText);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+mozilla::jni::String::LocalRef Clipboard::GetClipboardTextWrapper()
+{
+    return mozilla::jni::Method<GetClipboardTextWrapper_t>::Call(nullptr, nullptr);
 }
 
-void Clipboard::SetClipboardText(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char Clipboard::HasText_t::name[];
+constexpr char Clipboard::HasText_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    env->CallStaticVoidMethod(mClipboardClass, jSetClipboardText, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool Clipboard::HasText()
+{
+    return mozilla::jni::Method<HasText_t>::Call(nullptr, nullptr);
 }
 
-void InitStubs(JNIEnv *env) {
-    DownloadsIntegration::InitStubs(env);
-    GeckoAppShell::InitStubs(env);
-    GeckoJavaSampler::InitStubs(env);
-    Restri