Merge fx-team to m-c
authorWes Kocher <wkocher@mozilla.com>
Thu, 21 Nov 2013 19:16:50 -0800
changeset 171532 dbf94e314cde175900e0d95d211f7d163bafe4c9
parent 171513 d93ca560b15c3473400f16fc7b5661b6a9f907d5 (current diff)
parent 171531 5c11b81a0c9191ad78786fcd28c361d0f23d52a6 (diff)
child 171533 beb188bd7767c82e113955f5eac2fb159166a76e
child 171579 7a703a1f974b5f3c44b11e40699013d47d57748c
child 171609 cff1826bfddbe9c33ae0d91c0cac57f0e2c27303
child 171622 b2a0444bc991771fb68e92937c5b011586fee98d
child 177502 bd5d668bbac482e5203a1cfef5a8c208e94e9ba4
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
dbf94e314cde / 28.0a1 / 20131122030202 / files
nightly linux64
dbf94e314cde / 28.0a1 / 20131122030202 / files
nightly mac
dbf94e314cde / 28.0a1 / 20131122030202 / files
nightly win32
dbf94e314cde / 28.0a1 / 20131122030202 / files
nightly win64
dbf94e314cde / 28.0a1 / 20131122030202 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge fx-team to m-c
build/annotationProcessors/MethodWithAnnotationInfo.java
build/annotationProcessors/utils/AlphabeticMethodComparator.java
build/annotationProcessors/utils/GeneratableEntryPointIterator.java
mobile/android/base/mozglue/GeneratableAndroidBridgeTarget.java
mobile/android/base/mozglue/OptionalGeneratedParameter.java
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -107,16 +107,18 @@ run-if = crashreporter
 [browser_CTP_nonplugins.js]
 [browser_CTP_resize.js]
 [browser_URLBarSetURI.js]
 [browser_aboutHealthReport.js]
 [browser_aboutHome.js]
 [browser_aboutSyncProgress.js]
 [browser_addKeywordSearch.js]
 [browser_alltabslistener.js]
+[browser_backButtonFitts.js]
+skip-if = os != "win" # The Fitts Law back button is only supported on Windows (bug 571454)
 [browser_blob-channelname.js]
 [browser_bookmark_titles.js]
 skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)
 [browser_bug304198.js]
 [browser_bug321000.js]
 skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
 [browser_bug329212.js]
 [browser_bug356571.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_backButtonFitts.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test () {
+  waitForExplicitFinish();
+  var firstLocation = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
+  gBrowser.selectedTab = gBrowser.addTab(firstLocation);
+  gBrowser.selectedBrowser.addEventListener("pageshow", function onPageShow1() {
+    gBrowser.selectedBrowser.removeEventListener("pageshow", onPageShow1);
+    gBrowser.selectedBrowser.contentWindow.history.pushState("page2", "page2", "page2");
+    window.maximize();
+
+    // Find where the nav-bar is vertically.
+    var navBar = document.getElementById("nav-bar");
+    var boundingRect = navBar.getBoundingClientRect();
+    var yPixel = boundingRect.top + Math.floor(boundingRect.height / 2);
+    var xPixel = 0; // Use the first pixel of the screen since it is maximized.
+
+    gBrowser.selectedBrowser.contentWindow.addEventListener("popstate", function onPopState() {
+      gBrowser.selectedBrowser.contentWindow.removeEventListener("popstate", onPopState);
+      is(gBrowser.selectedBrowser.contentDocument.location.href, firstLocation,
+         "Clicking the first pixel should have navigated back.");
+      window.restore();
+      gBrowser.removeCurrentTab();
+      finish();
+    });
+    EventUtils.synthesizeMouseAtPoint(xPixel, yPixel, {}, window);
+  });
+}
--- a/browser/components/sessionstore/test/browser_625016.js
+++ b/browser/components/sessionstore/test/browser_625016.js
@@ -35,27 +35,31 @@ function setup() {
   is(ss.getClosedWindowCount(), 0, "starting with no closed windows");
 
   // Open a new window, which should trigger a save event soon.
   waitForSaveState(onSaveState);
   newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:rights");
 }
 
 function onSaveState() {
+  try {
+    ss.getWindowValue(newWin, "foobar");
+  } catch (e) {
+    // The window is untracked which means that the saveState() call isn't the
+    // one we're waiting for. It's most likely been triggered by an async
+    // collection running in the background.
+    waitForSaveState(onSaveState);
+    return;
+  }
+
   // Double check that we have no closed windows
   is(ss.getClosedWindowCount(), 0, "no closed windows on first save");
 
   Services.obs.addObserver(observe1, "sessionstore-state-write", false);
 
-  try {
-    ss.getWindowValue(newWin, "foobar");
-  } catch (e) {
-    ok(false, "window is untracked!");
-  }
-
   // Now close the new window, which should trigger another save event
   newWin.close();
 }
 
 function observe1(aSubject, aTopic, aData) {
   info("observe1: " + aTopic);
   switch (aTopic) {
     case "sessionstore-state-write":
--- a/browser/devtools/shared/test/browser_outputparser.js
+++ b/browser/devtools/shared/test/browser_outputparser.js
@@ -44,31 +44,46 @@ function testParseCssProperty() {
 
   testParseHTMLAttribute();
 }
 
 function testParseHTMLAttribute() {
   let attrib = "color:red; font-size: 12px; background-image: " +
                "url(chrome://branding/content/about-logo.png)";
   let frag = parser.parseHTMLAttribute(attrib, {
-    colorSwatchClass: "test-colorswatch",
     urlClass: "theme-link"
   });
 
   let target = doc.querySelector("div");
   ok(target, "captain, we have the div");
   target.appendChild(frag);
 
-  let expected = 'color:<span style="background-color:red" ' +
-                 'class="test-colorswatch"></span>#F00; font-size: 12px; ' +
+  let expected = 'color:#F00; font-size: 12px; ' +
                  'background-image: url(\'<a href="chrome://branding/content/about-logo.png" ' +
                  'class="theme-link" ' +
                  'target="_blank">chrome://branding/content/about-logo.png</a>\')';
 
   is(target.innerHTML, expected, "HTML Attribute correctly parsed");
+  target.innerHTML = "";
+  testParseNonCssHTMLAttribute();
+}
+
+function testParseNonCssHTMLAttribute() {
+  let attrib = "someclass background someotherclass red";
+  let frag = parser.parseHTMLAttribute(attrib);
+
+  let target = doc.querySelector("div");
+  ok(target, "captain, we have the div");
+  target.appendChild(frag);
+
+  let expected = 'someclass background someotherclass red';
+
+  is(target.innerHTML, expected, "Non-CSS HTML Attribute correctly parsed");
+  target.innerHTML = "";
   finishUp();
 }
 
+
 function finishUp() {
   Services = Loader = OutputParser = parser = doc = null;
   gBrowser.removeCurrentTab();
   finish();
 }
--- a/browser/devtools/sourceeditor/editor.js
+++ b/browser/devtools/sourceeditor/editor.js
@@ -52,17 +52,17 @@ const CM_SCRIPTS  = [
 
 const CM_IFRAME   =
   "data:text/html;charset=utf8,<!DOCTYPE html>" +
   "<html dir='ltr'>" +
   "  <head>" +
   "    <style>" +
   "      html, body { height: 100%; }" +
   "      body { margin: 0; overflow: hidden; }" +
-  "      .CodeMirror { width: 100%; height: 100% !important; }" +
+  "      .CodeMirror { width: 100%; height: 100% !important; line-height: normal!important}" +
   "    </style>" +
 [ "    <link rel='stylesheet' href='" + style + "'>" for (style of CM_STYLES) ].join("\n") +
   "  </head>" +
   "  <body class='theme-body devtools-monospace'></body>" +
   "</html>";
 
 const CM_MAPPING = [
   "focus",
--- a/browser/metro/base/content/contenthandlers/Content.js
+++ b/browser/metro/base/content/contenthandlers/Content.js
@@ -44,16 +44,18 @@ let HTMLFrameElement = Ci.nsIDOMHTMLFram
 let HTMLFrameSetElement = Ci.nsIDOMHTMLFrameSetElement;
 let HTMLSelectElement = Ci.nsIDOMHTMLSelectElement;
 let HTMLOptionElement = Ci.nsIDOMHTMLOptionElement;
 
 const kReferenceDpi = 240; // standard "pixel" size used in some preferences
 
 const kStateActive = 0x00000001; // :active pseudoclass for elements
 
+const kZoomToElementMargin = 16; // in px
+
 /*
  * getBoundingContentRect
  *
  * @param aElement
  * @return Bounding content rect adjusted for scroll and frame offsets.
  */
 function getBoundingContentRect(aElement) {
   if (!aElement)
@@ -390,46 +392,47 @@ let Content = {
       this._zoomToElement(aElement);
     }
   },
 
   /******************************************************
    * Zoom utilities
    */
   _zoomOut: function() {
-    let rect = getBoundingContentRect(content.document.documentElement);
-
-    let utils = Util.getWindowUtils(content);
-    let viewId = utils.getViewId(content.document.documentElement);
-    let presShellId = {};
-    utils.getPresShellId(presShellId);
-    let zoomData = [rect.x,
-                    rect.y,
-                    rect.width,
-                    rect.height,
-                    presShellId.value,
-                    viewId].join(",");
-    Services.obs.notifyObservers(null, "Metro:ZoomToRect", zoomData);
+    let rect = new Rect(0,0,0,0);
+    this._zoomToRect(rect);
     this._isZoomedIn = false;
   },
 
   _zoomToElement: function(aElement) {
     let rect = getBoundingContentRect(aElement);
+    this._inflateRect(rect, kZoomToElementMargin);
+    this._zoomToRect(rect);
+    this._isZoomedIn = true;
+  },
+
+  _inflateRect: function(aRect, aMargin) {
+    aRect.left -= aMargin;
+    aRect.top -= aMargin;
+    aRect.bottom += aMargin;
+    aRect.right += aMargin;
+  },
+
+  _zoomToRect: function (aRect) {
     let utils = Util.getWindowUtils(content);
     let viewId = utils.getViewId(content.document.documentElement);
     let presShellId = {};
     utils.getPresShellId(presShellId);
-    let zoomData = [rect.x,
-                    rect.y,
-                    rect.width,
-                    rect.height,
+    let zoomData = [aRect.x,
+                    aRect.y,
+                    aRect.width,
+                    aRect.height,
                     presShellId.value,
                     viewId].join(",");
     Services.obs.notifyObservers(null, "Metro:ZoomToRect", zoomData);
-    this._isZoomedIn = true;
   },
 
   _shouldZoomToElement: function(aElement) {
     let win = aElement.ownerDocument.defaultView;
     if (win.getComputedStyle(aElement, null).display == "inline") {
       return false;
     }
     else if (aElement instanceof Ci.nsIDOMHTMLLIElement) {
--- a/browser/themes/osx/devtools/common.css
+++ b/browser/themes/osx/devtools/common.css
@@ -7,17 +7,17 @@
 
 /* Font for code */
 
 :root {
   font: message-box;
 }
 
 .devtools-monospace {
-  font-family: monospace;
+  font-family: Menlo, monospace;
   font-size: 108%;
 }
 
 /* Toolbar and Toolbar items */
 
 .devtools-toolbar {
   -moz-appearance: none;
   padding: 4px 3px;
--- a/browser/themes/windows/devtools/common.css
+++ b/browser/themes/windows/devtools/common.css
@@ -5,17 +5,17 @@
 
 /* Font for code */
 
 :root {
   font: message-box;
 }
 
 .devtools-monospace {
-  font-family: monospace;
+  font-family: Consolas, monospace;
 }
 
 /* Toolbar and Toolbar items */
 
 .devtools-toolbar {
   -moz-appearance: none;
   padding: 4px 3px;
   color: hsl(210,30%,85%);
rename from build/annotationProcessors/MethodWithAnnotationInfo.java
rename to build/annotationProcessors/AnnotationInfo.java
--- a/build/annotationProcessors/MethodWithAnnotationInfo.java
+++ b/build/annotationProcessors/AnnotationInfo.java
@@ -1,24 +1,20 @@
 /* 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 java.lang.reflect.Method;
-
 /**
- * Object holding method and annotation. Used by GeneratableEntryPointIterator.
+ * Object holding annotation data. Used by GeneratableElementIterator.
  */
-public class MethodWithAnnotationInfo {
-    public final Method method;
+public class AnnotationInfo {
     public final String wrapperName;
     public final boolean isStatic;
     public final boolean isMultithreaded;
 
-    public MethodWithAnnotationInfo(Method aMethod, String aWrapperName, boolean aIsStatic, boolean aIsMultithreaded) {
-        method = aMethod;
+    public AnnotationInfo(String aWrapperName, boolean aIsStatic, boolean aIsMultithreaded) {
         wrapperName = aWrapperName;
         isStatic = aIsStatic;
         isMultithreaded = aIsMultithreaded;
     }
 }
--- a/build/annotationProcessors/AnnotationProcessor.java
+++ b/build/annotationProcessors/AnnotationProcessor.java
@@ -1,26 +1,34 @@
 /* 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.classloader.IterableJarLoadingURLClassLoader;
-import org.mozilla.gecko.annotationProcessors.utils.GeneratableEntryPointIterator;
+import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
 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";
+
     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);
         }
 
         System.out.println("Processing annotations...");
@@ -28,49 +36,126 @@ public class AnnotationProcessor {
         // We want to produce the same output as last time as often as possible. Ordering of
         // generated statements, therefore, needs to be consistent.
         Arrays.sort(args);
 
         // Start the clock!
         long s = System.currentTimeMillis();
 
         // Get an iterator over the classes in the jar files given...
-        Iterator<Class<?>> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
+        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 *jEnv);\n\n");
 
-        CodeGenerator generatorInstance = new CodeGenerator();
+        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 *jEnv) {\n");
 
         while (jarClassIterator.hasNext()) {
-            Class<?> aClass = jarClassIterator.next();
+            ClassWithOptions aClassTuple = jarClassIterator.next();
+
+            CodeGenerator generatorInstance;
 
             // Get an iterator over the appropriately generated methods of this class
-            Iterator<MethodWithAnnotationInfo> methodIterator = new GeneratableEntryPointIterator(aClass.getDeclaredMethods());
+            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(jEnv);\n");
 
-            // Iterate all annotated methods in this class..
+            // Iterate all annotated members in this class..
             while (methodIterator.hasNext()) {
-                MethodWithAnnotationInfo aMethodTuple = methodIterator.next();
-                generatorInstance.generateMethod(aMethodTuple, aClass);
+                AnnotatableEntity aElementTuple = methodIterator.next();
+                switch (aElementTuple.mEntityType) {
+                    case METHOD:
+                        generatorInstance.generateMethod(aElementTuple);
+                        break;
+                    case FIELD:
+                        generatorInstance.generateField(aElementTuple);
+                        break;
+                    case CONSTRUCTOR:
+                        generatorInstance.generateConstructor(aElementTuple);
+                        break;
+                }
             }
 
+            headerFile.append(generatorInstance.getHeaderFileContents());
+            implementationFile.append(generatorInstance.getWrapperFileContents());
         }
 
-        writeOutputFiles(generatorInstance);
+        implementationFile.append('\n');
+        stubInitialiser.append("}");
+        implementationFile.append(stubInitialiser);
+
+        implementationFile.append("\n} /* android */\n" +
+                                    "} /* widget */\n" +
+                                    "} /* mozilla */\n");
+
+        headerFile.append("\n} /* android */\n" +
+                            "} /* widget */\n" +
+                            "} /* mozilla */\n" +
+                            "#endif\n");
+
+        writeOutputFiles(headerFile, implementationFile);
         long e = System.currentTimeMillis();
         System.out.println("Annotation processing complete in " + (e - s) + "ms");
     }
 
-    private static void writeOutputFiles(CodeGenerator aGenerator) {
+    private static void writeOutputFiles(StringBuilder aHeaderFile, StringBuilder aImplementationFile) {
+        FileOutputStream headerStream = null;
         try {
-            FileOutputStream outStream = new FileOutputStream(OUTFILE);
-            outStream.write(aGenerator.getWrapperFileContents());
+            headerStream = new FileOutputStream(OUTFILE);
+            headerStream.write(aImplementationFile.toString().getBytes());
         } catch (IOException e) {
             System.err.println("Unable to write " + OUTFILE + ". Perhaps a permissions issue?");
             e.printStackTrace(System.err);
+        } finally {
+            if (headerStream != null) {
+                try {
+                    headerStream.close();
+                } catch (IOException e) {
+                    System.err.println("Unable to close headerStream due to "+e);
+                    e.printStackTrace(System.err);
+                }
+            }
         }
 
+        FileOutputStream outStream = null;
         try {
-            FileOutputStream headerStream = new FileOutputStream(HEADERFILE);
-            headerStream.write(aGenerator.getHeaderFileContents());
+            outStream = new FileOutputStream(HEADERFILE);
+            outStream.write(aHeaderFile.toString().getBytes());
         } catch (IOException e) {
-            System.err.println("Unable to write " + OUTFILE + ". Perhaps a permissions issue?");
+            System.err.println("Unable to write " + HEADERFILE + ". Perhaps a permissions issue?");
             e.printStackTrace(System.err);
+        } finally {
+            if (outStream != null) {
+                try {
+                    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,336 +1,618 @@
 /* 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.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 headerFields = new StringBuilder();
-    private final StringBuilder headerMethods = new StringBuilder();
+    private final StringBuilder headerPublic = new StringBuilder();
+    private final StringBuilder headerProtected = new StringBuilder();
 
     private final HashSet<String> seenClasses = new HashSet<String>();
 
-    private 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";
+    private final String mCClassName;
+
+    private final Class<?> mClassToWrap;
+
+    private boolean mHasEncounteredDefaultConstructor;
 
-    public CodeGenerator() {
+    // 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;
+
+    public CodeGenerator(Class<?> aClass, String aGeneratedName) {
+        mClassToWrap = aClass;
+        mCClassName = aGeneratedName;
+
         // 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 headerFields
-        // with headerMethods.
-        wrapperStartupCode.append(GENERATED_COMMENT);
-        wrapperStartupCode.append(
-                "#include \"nsXPCOMStrings.h\"\n" +
-                "#include \"AndroidBridge.h\"\n" +
-                "#include \"AndroidBridgeUtilities.h\"\n" +
-                "\n" +
-                "#ifdef DEBUG\n" +
-                "#define ALOG_BRIDGE(args...) ALOG(args)\n" +
-                "#else\n" +
-                "#define ALOG_BRIDGE(args...) ((void)0)\n" +
-                "#endif\n" +
-                "\n" +
-                "using namespace mozilla;\n" +
-                "void AndroidBridge::InitStubs(JNIEnv *jEnv) {\n" +
-                "    initInit();\n");
+        // wrapperMethodBodies. Similarly, GeneratedJNIWrappers.h is the concatenation of headerPublic
+        // with headerProtected.
+        wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *jEnv) {\n" +
+                                  "    initInit();\n");
+
         // Now we write the various GetStaticMethodID calls here...
+        headerPublic.append("class ").append(mCClassName).append(" : public AutoGlobalWrappedJavaObject {\n" +
+                            "public:\n" +
+                            "    static void InitStubs(JNIEnv *jEnv);\n");
+        headerProtected.append("protected:");
 
-        headerFields.append("protected:\n\n");
-        headerMethods.append(GENERATED_COMMENT);
-        headerMethods.append("public:\n\n");
+        generateWrapperMethod();
+    }
+
+    /**
+     * 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.
+     */
+    private void generateWrapperMethod() {
+        headerPublic.append("    static ").append(mCClassName).append("* Wrap(jobject obj);\n" +
+                "    ").append(mCClassName).append("(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {};\n");
+
+        wrapperMethodBodies.append("\n").append(mCClassName).append("* ").append(mCClassName).append("::Wrap(jobject obj) {\n" +
+                "    JNIEnv *env = GetJNIForThread();\n\n" +
+                "    if (!env) {\n" +
+                "        ALOG_BRIDGE(\"Aborted: No env - %s\", __PRETTY_FUNCTION__);\n" +
+                "        return NULL;\n" +
+                "    }\n\n" +
+                "    ").append(mCClassName).append("* ret = new ").append(mCClassName).append("(obj, env);\n" +
+                "    env->DeleteLocalRef(obj);\n" +
+                "    return ret;\n" +
+                "}\n");
+    }
+
+    private void generateMemberCommon(Member theMethod, String aCMethodName, Class<?> aClass) {
+        ensureClassHeaderAndStartup(aClass);
+        writeMemberIdField(theMethod, aCMethodName);
+        writeStartupCode(theMethod);
     }
 
     /**
      * Append the appropriate generated code to the buffers for the method provided.
      *
-     * @param aMethodTuple The Java method, plus the name for the generated method.
-     * @param aClass       The class to which the Java method belongs.
+     * @param aMethodTuple The Java method, plus annotation data.
      */
-    public void generateMethod(MethodWithAnnotationInfo aMethodTuple, Class<?> aClass) {
+    public void generateMethod(AnnotatableEntity aMethodTuple) {
         // Unpack the tuple and extract some useful fields from the Method..
-        Method aMethod = aMethodTuple.method;
-        String CMethodName = aMethodTuple.wrapperName;
+        Method theMethod = aMethodTuple.getMethod();
 
-        String javaMethodName = aMethod.getName();
+        String CMethodName = aMethodTuple.mAnnotationInfo.wrapperName;
+
+        generateMemberCommon(theMethod, CMethodName, mClassToWrap);
 
-        ensureClassHeaderAndStartup(aClass);
+        boolean isFieldStatic = Utils.isMemberStatic(theMethod);
+        boolean shallGenerateStatic = isFieldStatic || aMethodTuple.mAnnotationInfo.isStatic;
 
-        writeHeaderField(CMethodName);
-        writeStartupCode(CMethodName, javaMethodName, aMethod, aClass);
+        Class<?>[] parameterTypes = theMethod.getParameterTypes();
+        Class<?> returnType = theMethod.getReturnType();
 
         // Get the C++ method signature for this method.
-        String implementationSignature = Utils.getCImplementationMethodSignature(aMethod, CMethodName);
-        String headerSignature = Utils.getCHeaderMethodSignature(aMethod, CMethodName, aMethodTuple.isStatic);
+        String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName);
+        String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, shallGenerateStatic);
 
         // Add the header signature to the header file.
-        headerMethods.append(headerSignature);
-        headerMethods.append(";\n");
+        writeSignatureToHeader(headerSignature);
 
         // Use the implementation signature to generate the method body...
-        writeMethodBody(implementationSignature, CMethodName, aMethod, aClass, aMethodTuple.isStatic, aMethodTuple.isMultithreaded);
+        writeMethodBody(implementationSignature, CMethodName, theMethod, mClassToWrap, aMethodTuple.mAnnotationInfo.isStatic, aMethodTuple.mAnnotationInfo.isMultithreaded);
+    }
+
+    private void generateGetterOrSetterBody(Class<?> aFieldType, String aFieldName, boolean aIsFieldStatic, boolean isSetter) {
+        StringBuilder argumentContent = null;
+
+        if (isSetter) {
+            Class<?>[] setterArguments = new Class<?>[]{aFieldType};
+            // Marshall the argument..
+            argumentContent = getArgumentMarshalling(setterArguments);
+        }
+
+        boolean isObjectReturningMethod = Utils.isObjectType(aFieldType);
+        wrapperMethodBodies.append("    ");
+        if (isSetter) {
+            wrapperMethodBodies.append("env->Set");
+        } else {
+            wrapperMethodBodies.append("return ");
+
+            if (isObjectReturningMethod) {
+                wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(aFieldType)).append(">(");
+            }
+
+            wrapperMethodBodies.append("env->Get");
+        }
+
+        if (aIsFieldStatic) {
+            wrapperMethodBodies.append("Static");
+        }
+        wrapperMethodBodies.append(Utils.getFieldType(aFieldType))
+                           .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");
+    }
+
+    public void generateField(AnnotatableEntity aFieldTuple) {
+        Field theField = aFieldTuple.getField();
+
+        // 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")) {
+            return;
+        }
+
+        String CFieldName = aFieldTuple.mAnnotationInfo.wrapperName;
+
+        Class<?> fieldType = theField.getType();
+
+        generateMemberCommon(theField, CFieldName, mClassToWrap);
+
+        boolean isFieldStatic = Utils.isMemberStatic(theField);
+        boolean isFieldFinal = Utils.isMemberFinal(theField);
+        boolean shallGenerateStatic = isFieldStatic || aFieldTuple.mAnnotationInfo.isStatic;
+
+        String getterName = "get" + CFieldName;
+        String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName);
+        String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, shallGenerateStatic);
+
+        writeSignatureToHeader(getterHeaderSignature);
+
+        writeFunctionStartupBoilerPlate(getterSignature, fieldType, isFieldStatic, true);
+
+        generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, false);
+
+        // If field not final, also generate a setter function.
+        if (!isFieldFinal) {
+            String setterName = "set" + CFieldName;
+
+            Class<?>[] setterArguments = new Class<?>[]{fieldType};
+
+            String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName);
+            String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, shallGenerateStatic);
+
+            writeSignatureToHeader(setterHeaderSignature);
+
+            writeFunctionStartupBoilerPlate(setterSignature, Void.class, isFieldStatic, true);
+
+            generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, true);
+        }
+    }
+
+    public void generateConstructor(AnnotatableEntity aCtorTuple) {
+        // Unpack the tuple and extract some useful fields from the Method..
+        Constructor theCtor = aCtorTuple.getConstructor();
+        String CMethodName = mCClassName;
+
+        generateMemberCommon(theCtor, mCClassName, mClassToWrap);
+
+        String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName);
+        String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false);
+
+        // Slice off the "void " from the start of the constructor declaration.
+        headerSignature = headerSignature.substring(5);
+        implementationSignature = implementationSignature.substring(5);
+
+        // Add the header signatures to the header file.
+        writeSignatureToHeader(headerSignature);
+
+        // Use the implementation signature to generate the method body...
+        writeCtorBody(implementationSignature, theCtor, aCtorTuple.mAnnotationInfo.isMultithreaded);
+
+        if (theCtor.getParameterTypes().length == 0) {
+            mHasEncounteredDefaultConstructor = true;
+        }
     }
 
     /**
      * 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...
-        headerFields.append("\njclass ");
-        headerFields.append(Utils.getClassReferenceName(aClass));
-        headerFields.append(";\n");
+        headerProtected.append("\n    static jclass ")
+                       .append(Utils.getClassReferenceName(aClass))
+                       .append(";\n");
 
         // Add startup code to populate it..
-        wrapperStartupCode.append('\n');
-        wrapperStartupCode.append(Utils.getStartupLineForClass(aClass));
+        wrapperStartupCode.append('\n')
+                          .append(Utils.getStartupLineForClass(aClass));
 
         seenClasses.add(className);
     }
 
     /**
+     * Write out the function startup boilerplate for the method described. Check for environment
+     * existence,
+     * @param methodSignature
+     * @param returnType
+     * @param aIsStatic
+     * @param aIsThreaded
+     */
+    private void writeFunctionStartupBoilerPlate(String methodSignature, Class<?> returnType, boolean aIsStatic, 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");
+        }
+        wrapperMethodBodies.append("    if (!env) {\n" +
+                                   "        ALOG_BRIDGE(\"Aborted: No env - %s\", __PRETTY_FUNCTION__);\n" +
+                                   "        return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
+                "    }\n\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) {
+        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" +
+                "        ALOG_BRIDGE(\"Exceptional exit of: %s\", __PRETTY_FUNCTION__);\n" +
+                "        env->ExceptionDescribe();\n"+
+                "        env->ExceptionClear();\n" +
+                "        return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
+                "    }\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');
+            }
+        }
+
+        return argumentContent;
+    }
+
+    private void writeCtorBody(String implementationSignature, Constructor theCtor, boolean aIsThreaded) {
+        Class<?>[] argumentTypes = theCtor.getParameterTypes();
+
+        writeFunctionStartupBoilerPlate(implementationSignature, Void.class, false, aIsThreaded);
+
+        writeFramePushBoilerplate(theCtor, false);
+
+        // 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" +
+                                   "    env->PopLocalFrame(NULL);\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 aCMethodName    The C++ method name 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, String aCMethodName, Method aMethod, Class<?> aClass, boolean aIsStaticBridgeMethod, boolean aIsMultithreaded) {
         Class<?>[] argumentTypes = aMethod.getParameterTypes();
         Class<?> returnType = aMethod.getReturnType();
 
-        // The start-of-function boilerplate. Does the bridge exist? Does the env exist? etc.
-        wrapperMethodBodies.append('\n');
-        wrapperMethodBodies.append(methodSignature);
-
-        wrapperMethodBodies.append(" {\n");
+        writeFunctionStartupBoilerPlate(methodSignature, returnType, aIsStaticBridgeMethod, aIsMultithreaded);
 
-        // Static stubs check the bridge instance has been created before trying to run.
-        if (aIsStaticBridgeMethod) {
-            wrapperMethodBodies.append("    if (!sBridge) {\n" +
-                                       "        ALOG_BRIDGE(\"Aborted: No sBridge - %s\", __PRETTY_FUNCTION__);\n" +
-                                       "        return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
-                                       "    }\n\n");
-        }
-        wrapperMethodBodies.append("    JNIEnv *env = ");
-        if (!aIsMultithreaded) {
-            wrapperMethodBodies.append("GetJNIEnv();\n");
-        } else {
-            wrapperMethodBodies.append("GetJNIForThread();\n");
-        }
-        wrapperMethodBodies.append("    if (!env) {\n" +
-                                   "        ALOG_BRIDGE(\"Aborted: No env - %s\", __PRETTY_FUNCTION__);\n" +
-                                   "        return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
-                                   "    }\n\n");
+        boolean isObjectReturningMethod = !returnType.getCanonicalName().equals("void") && Utils.isObjectType(returnType);
 
-        boolean isObjectReturningMethod = !returnType.getCanonicalName().equals("void") && Utils.doesReturnObjectType(aMethod);
-
-        // 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.
-        int localReferencesNeeded = Utils.enumerateReferenceArguments(aMethod);
-        if (isObjectReturningMethod) {
-            localReferencesNeeded++;
-        }
-        wrapperMethodBodies.append("    if (env->PushLocalFrame(").append(localReferencesNeeded).append(") != 0) {\n" +
-                                   "        ALOG_BRIDGE(\"Exceptional exit of: %s\", __PRETTY_FUNCTION__);\n" +
-                                   "        env->ExceptionDescribe();\n"+
-                                   "        env->ExceptionClear();\n" +
-                                   "        return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
-                                   "    }\n\n");
+        writeFramePushBoilerplate(aMethod, isObjectReturningMethod);
 
         // 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.append(", ");
-            // If we have >2 arguments, use the jvalue[] calling approach.
-            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("].");
-                    wrapperMethodBodies.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(" = 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');
-                }
-            }
+            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));
             }
             wrapperMethodBodies.append(" temp = ");
         }
 
-        boolean isStaticJavaMethod = Utils.isMethodStatic(aMethod);
+        boolean isStaticJavaMethod = Utils.isMemberStatic(aMethod);
 
         // The call into Java
-        wrapperMethodBodies.append("env->");
-        wrapperMethodBodies.append(Utils.getCallPrefix(returnType, isStaticJavaMethod));
+        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("aTarget, ");
+            wrapperMethodBodies.append("wrapped_obj, ");
         } else {
-            // If the stub to be generated is static, we need to use the singleton to access the class
-            // reference.
-            if (aIsStaticBridgeMethod) {
-                wrapperMethodBodies.append("sBridge->");
-            }
-            // If this is a static underlyin Java method, we need to use the class reference in our
+            // If this is a static underlying Java method, we need to use the class reference in our
             // call.
             wrapperMethodBodies.append(Utils.getClassReferenceName(aClass)).append(", ");
         }
 
-        // Write the method id out..
-        if (aIsStaticBridgeMethod) {
-            wrapperMethodBodies.append("sBridge->");
-        }
-        wrapperMethodBodies.append('j');
-        wrapperMethodBodies.append(aCMethodName);
+        wrapperMethodBodies.append(mMembersToIds.get(aMethod));
 
         // Tack on the arguments, if any..
-        wrapperMethodBodies.append(argumentContent);
-        wrapperMethodBodies.append(");\n\n");
+        wrapperMethodBodies.append(argumentContent)
+                           .append(");\n\n");
 
         // Check for exception and return the failure value..
         wrapperMethodBodies.append("    if (env->ExceptionCheck()) {\n" +
                                    "        ALOG_BRIDGE(\"Exceptional exit of: %s\", __PRETTY_FUNCTION__);\n" +
                                    "        env->ExceptionDescribe();\n" +
                                    "        env->ExceptionClear();\n" +
                                    "        env->PopLocalFrame(NULL);\n" +
                                    "        return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
-                                   "    }\n");
+                                   "    }\n\n");
 
         // If we're returning an object, pop the callee's stack frame extracting our ref as the return
         // value.
         if (isObjectReturningMethod) {
-            wrapperMethodBodies.append("    ");
-            wrapperMethodBodies.append(Utils.getCReturnType(returnType));
-            wrapperMethodBodies.append(" ret = static_cast<").append(Utils.getCReturnType(returnType)).append(">(env->PopLocalFrame(temp));\n" +
+            wrapperMethodBodies.append("    ")
+                               .append(Utils.getCReturnType(returnType))
+                               .append(" ret = static_cast<").append(Utils.getCReturnType(returnType)).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(NULL);\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(NULL);\n");
         }
         wrapperMethodBodies.append("}\n");
     }
 
     /**
-     * Generates the code to get the method id of the given method on startup.
+     * Generates the code to get the id of the given member on startup.
      *
-     * @param aCMethodName    The C method name of the method being generated.
-     * @param aJavaMethodName The name of the Java method being wrapped.
-     * @param aMethod         The Java method being wrapped.
+     * @param aMember         The Java member being wrapped.
      */
-    private void writeStartupCode(String aCMethodName, String aJavaMethodName, Method aMethod, Class<?> aClass) {
-        wrapperStartupCode.append("    j");
-        wrapperStartupCode.append(aCMethodName);
-        wrapperStartupCode.append(" = get");
-        if (Utils.isMethodStatic(aMethod)) {
+    private void writeStartupCode(Member aMember) {
+        wrapperStartupCode.append("    ")
+                          .append(mMembersToIds.get(aMember))
+                          .append(" = get");
+        if (Utils.isMemberStatic(aMember)) {
             wrapperStartupCode.append("Static");
         }
-        wrapperStartupCode.append("Method(\"");
-        wrapperStartupCode.append(aJavaMethodName);
-        wrapperStartupCode.append("\", \"");
-        wrapperStartupCode.append(Utils.getTypeSignatureString(aMethod));
-        wrapperStartupCode.append("\");\n");
+
+        boolean isField = aMember instanceof Field;
+        if (isField) {
+            wrapperStartupCode.append("Field(\"");
+        } else {
+            wrapperStartupCode.append("Method(\"");
+        }
+        if (aMember instanceof Constructor) {
+            wrapperStartupCode.append("<init>");
+        } else {
+            wrapperStartupCode.append(aMember.getName());
+        }
+
+        wrapperStartupCode.append("\", \"")
+                          .append(Utils.getTypeSignatureStringForMember(aMember))
+                          .append("\");\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");
     }
 
     /**
-     * Create a method id field in the header file for the C method name provided.
+     * Write the field declaration for the C++ id field of the given member.
      *
-     * @param aMethodName C method name to generate a method id field for.
+     * @param aMember Member for which an id field needs to be generated.
      */
-    private void writeHeaderField(String aMethodName) {
-        headerFields.append("jmethodID j");
-        headerFields.append(aMethodName);
-        headerFields.append(";\n");
+    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 byte[] getWrapperFileContents() {
+    public String getWrapperFileContents() {
         wrapperStartupCode.append("}\n");
-        wrapperStartupCode.append(wrapperMethodBodies);
+        zeroingCode.append(wrapperStartupCode)
+                   .append(wrapperMethodBodies);
         wrapperMethodBodies.setLength(0);
-        return wrapperStartupCode.toString().getBytes();
+        wrapperStartupCode.setLength(0);
+        return zeroingCode.toString();
     }
 
     /**
      * Get the finalised bytes to go into the generated header file.
      *
      * @return The bytes to be written to the header file.
      */
-    public byte[] getHeaderFileContents() {
-        headerFields.append('\n');
-        headerFields.append(headerMethods);
-        headerMethods.setLength(0);
-        return headerFields.toString().getBytes();
+    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();
     }
 }
new file mode 100644
--- /dev/null
+++ b/build/annotationProcessors/classloader/AnnotatableEntity.java
@@ -0,0 +1,57 @@
+/* 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.classloader;
+
+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;
+
+/**
+ * Union type to hold either a method, field, or ctor. Allows us to iterate "The generatable stuff", despite
+ * the fact that such things can be of either flavour.
+ */
+public class AnnotatableEntity {
+    public enum ENTITY_TYPE {METHOD, FIELD, CONSTRUCTOR}
+
+    private final Member mMember;
+    public final ENTITY_TYPE mEntityType;
+
+    public final AnnotationInfo mAnnotationInfo;
+
+    public AnnotatableEntity(Member aObject, AnnotationInfo aAnnotationInfo) {
+        mMember = aObject;
+        mAnnotationInfo = aAnnotationInfo;
+
+        if (aObject instanceof Method) {
+            mEntityType = ENTITY_TYPE.METHOD;
+        } else if (aObject instanceof Field) {
+            mEntityType = ENTITY_TYPE.FIELD;
+        } else {
+            mEntityType = ENTITY_TYPE.CONSTRUCTOR;
+        }
+    }
+
+    public Method getMethod() {
+        if (mEntityType != ENTITY_TYPE.METHOD) {
+            throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
+        }
+        return (Method) mMember;
+    }
+    public Field getField() {
+        if (mEntityType != ENTITY_TYPE.FIELD) {
+            throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
+        }
+        return (Field) mMember;
+    }
+    public Constructor getConstructor() {
+        if (mEntityType != ENTITY_TYPE.CONSTRUCTOR) {
+            throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
+        }
+        return (Constructor) mMember;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/build/annotationProcessors/classloader/ClassWithOptions.java
@@ -0,0 +1,15 @@
+/* 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.classloader;
+
+public class ClassWithOptions {
+    public final Class<?> wrappedClass;
+    public final String generatedName;
+
+    public ClassWithOptions(Class<?> someClass, String name) {
+        wrappedClass = someClass;
+        generatedName = name;
+    }
+}
--- a/build/annotationProcessors/classloader/IterableJarLoadingURLClassLoader.java
+++ b/build/annotationProcessors/classloader/IterableJarLoadingURLClassLoader.java
@@ -16,50 +16,45 @@ import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
 /**
  * A classloader which can be initialised with a list of jar files and which can provide an iterator
  * over the top level classes in the jar files it was initialised with.
  * classNames is kept sorted to ensure iteration order is consistent across program invocations.
  * Otherwise, we'd forever be reporting the outdatedness of the generated code as we permute its
  * contents.
- * This classloader does not support inner classes. (You probably shouldn't be putting JNI entry
- * points in inner classes anyway)
  */
 public class IterableJarLoadingURLClassLoader extends URLClassLoader {
     LinkedList<String> classNames = new LinkedList<String>();
 
     /**
      * Create an instance and return its iterator. Provides an iterator over the classes in the jar
      * files provided as arguments.
      * Inner classes are not supported.
      *
      * @param args A list of jar file names an iterator over the classes of which is desired.
      * @return An iterator over the top level classes in the jar files provided, in arbitrary order.
      */
-    public static Iterator<Class<?>> getIteratorOverJars(String[] args) {
+    public static Iterator<ClassWithOptions> getIteratorOverJars(String[] args) {
         URL[] urlArray = new URL[args.length];
         LinkedList<String> aClassNames = new LinkedList<String>();
 
         for (int i = 0; i < args.length; i++) {
             try {
                 urlArray[i] = (new File(args[i])).toURI().toURL();
 
                 Enumeration<JarEntry> entries = new JarFile(args[i]).entries();
                 while (entries.hasMoreElements()) {
                     JarEntry e = entries.nextElement();
                     String fName = e.getName();
                     if (!fName.endsWith(".class")) {
                         continue;
                     }
                     final String className = fName.substring(0, fName.length() - 6).replace('/', '.');
-                    // Inner classes are not supported.
-                    if (className.contains("$")) {
-                        continue;
-                    }
+
                     aClassNames.add(className);
                 }
             } catch (IOException e) {
                 System.err.println("Error loading jar file \"" + args[i] + '"');
                 e.printStackTrace(System.err);
             }
         }
         Collections.sort(aClassNames);
--- a/build/annotationProcessors/classloader/JarClassIterator.java
+++ b/build/annotationProcessors/classloader/JarClassIterator.java
@@ -1,38 +1,75 @@
 /* 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.classloader;
 
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Iterator;
 
 /**
  * Class for iterating over an IterableJarLoadingURLClassLoader's classes.
  */
-public class JarClassIterator implements Iterator<Class<?>> {
+public class JarClassIterator implements Iterator<ClassWithOptions> {
     private IterableJarLoadingURLClassLoader mTarget;
     private Iterator<String> mTargetClassListIterator;
 
     public JarClassIterator(IterableJarLoadingURLClassLoader aTarget) {
         mTarget = aTarget;
         mTargetClassListIterator = aTarget.classNames.iterator();
     }
 
     @Override
     public boolean hasNext() {
         return mTargetClassListIterator.hasNext();
     }
 
     @Override
-    public Class<?> next() {
+    public ClassWithOptions next() {
         String className = mTargetClassListIterator.next();
         try {
-            return mTarget.loadClass(className);
+            Class<?> ret = mTarget.loadClass(className);
+            if (ret.getCanonicalName() == null || "null".equals(ret.getCanonicalName())) {
+                // Anonymous inner class - unsupported.
+                return next();
+            } else {
+                String generateName = null;
+                for (Annotation annotation : ret.getAnnotations()) {
+                    Class<?> annotationType = annotation.annotationType();
+                    if (annotationType.getCanonicalName().equals("org.mozilla.gecko.mozglue.generatorannotations.GeneratorOptions")) {
+                        try {
+                            // Determine the explicitly-given name of the stub to generate, if any.
+                            final Method generateNameMethod = annotationType.getDeclaredMethod("generatedClassName");
+                            generateNameMethod.setAccessible(true);
+                            generateName = (String) generateNameMethod.invoke(annotation);
+                            break;
+                        } catch (NoSuchMethodException e) {
+                            System.err.println("Unable to find expected field on GeneratorOptions annotation. Did the signature change?");
+                            e.printStackTrace(System.err);
+                            System.exit(3);
+                        } catch (IllegalAccessException e) {
+                            System.err.println("IllegalAccessException reading fields on GeneratorOptions annotation. Seems the semantics of Reflection have changed...");
+                            e.printStackTrace(System.err);
+                            System.exit(4);
+                        } catch (InvocationTargetException e) {
+                            System.err.println("InvocationTargetException reading fields on GeneratorOptions annotation. This really shouldn't happen.");
+                            e.printStackTrace(System.err);
+                            System.exit(5);
+                        }
+                    }
+                }
+                if (generateName == null) {
+                    generateName = ret.getSimpleName();
+                }
+                return new ClassWithOptions(ret, generateName);
+            }
         } catch (ClassNotFoundException e) {
             System.err.println("Unable to enumerate class: " + className + ". Corrupted jar file?");
             e.printStackTrace();
             System.exit(2);
         }
         return null;
     }
 
--- a/build/annotationProcessors/moz.build
+++ b/build/annotationProcessors/moz.build
@@ -1,17 +1,19 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 jar = add_java_jar('annotationProcessors')
 jar.sources += [
+    'AnnotationInfo.java',
     'AnnotationProcessor.java',
+    'classloader/AnnotatableEntity.java',
+    'classloader/ClassWithOptions.java',
     'classloader/IterableJarLoadingURLClassLoader.java',
     'classloader/JarClassIterator.java',
     'CodeGenerator.java',
-    'MethodWithAnnotationInfo.java',
-    'utils/AlphabeticMethodComparator.java',
-    'utils/GeneratableEntryPointIterator.java',
+    'utils/AlphabeticAnnotatableEntityComparator.java',
+    'utils/GeneratableElementIterator.java',
     'utils/Utils.java',
 ]
rename from build/annotationProcessors/utils/AlphabeticMethodComparator.java
rename to build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
--- a/build/annotationProcessors/utils/AlphabeticMethodComparator.java
+++ b/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
@@ -1,28 +1,81 @@
 /* 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.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.util.Comparator;
 
-public class AlphabeticMethodComparator implements Comparator<Method> {
+public class AlphabeticAnnotatableEntityComparator<T extends Member> implements Comparator<T> {
     @Override
-    public int compare(Method lhs, Method rhs) {
+    public int compare(T aLhs, T aRhs) {
+        // Constructors, Methods, Fields.
+        boolean lIsConstructor = aLhs instanceof Constructor;
+        boolean rIsConstructor = aRhs instanceof Constructor;
+        boolean lIsMethod = aLhs instanceof Method;
+        boolean rIsField = aRhs instanceof Field;
+
+        if (lIsConstructor) {
+            if (!rIsConstructor) {
+                return -1;
+            }
+        } else if (lIsMethod) {
+            if (rIsConstructor) {
+                return 1;
+            } else if (rIsField) {
+                return -1;
+            }
+        } else {
+            if (!rIsField) {
+                return 1;
+            }
+        }
+
+        // Verify these objects are the same type and cast them.
+        if (aLhs instanceof Method) {
+            return compare((Method) aLhs, (Method) aRhs);
+        } else if (aLhs instanceof Field) {
+            return compare((Field) aLhs, (Field) aRhs);
+        } else {
+            return compare((Constructor) aLhs, (Constructor) aRhs);
+        }
+    }
+
+    // Alas, the type system fails us.
+    private static int compare(Method aLhs, Method aRhs) {
         // Initially, attempt to differentiate the methods be name alone..
-        String lName = lhs.getName();
-        String rName = rhs.getName();
+        String lName = aLhs.getName();
+        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.getTypeSignatureString(lhs);
-        rName = Utils.getTypeSignatureString(rhs);
+        lName = Utils.getTypeSignatureStringForMethod(aLhs);
+        rName = Utils.getTypeSignatureStringForMethod(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);
+
+        return lName.compareTo(rName);
+    }
+
+    private static int compare(Field aLhs, Field aRhs) {
+        // Compare field names..
+        String lName = aLhs.getName();
+        String rName = aRhs.getName();
 
         return lName.compareTo(rName);
     }
 }
rename from build/annotationProcessors/utils/GeneratableEntryPointIterator.java
rename to build/annotationProcessors/utils/GeneratableElementIterator.java
--- a/build/annotationProcessors/utils/GeneratableEntryPointIterator.java
+++ b/build/annotationProcessors/utils/GeneratableElementIterator.java
@@ -1,57 +1,82 @@
 /* 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 org.mozilla.gecko.annotationProcessors.MethodWithAnnotationInfo;
+import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
+import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
 
 import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Iterator;
-import java.util.List;
 
 /**
- * Iterator over the methods in a given method list which have the GeneratableAndroidBridgeTarget
+ * Iterator over the methods in a given method list which have the WrappedJNIMethod
  * annotation. Returns an object containing both the annotation (Which may contain interesting
  * parameters) and the argument.
  */
-public class GeneratableEntryPointIterator implements Iterator<MethodWithAnnotationInfo> {
-    private final Method[] mMethods;
-    private MethodWithAnnotationInfo mNextReturnValue;
-    private int mMethodIndex;
+public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
+    private final Member[] mObjects;
+    private AnnotatableEntity mNextReturnValue;
+    private int mElementIndex;
+
+    private boolean mIterateEveryEntry;
+
+    public GeneratableElementIterator(Class<?> aClass) {
+        // Get all the elements of this class as AccessibleObjects.
+        Member[] aMethods = aClass.getDeclaredMethods();
+        Member[] aFields = aClass.getDeclaredFields();
+        Member[] aCtors = aClass.getConstructors();
+
+        // Shove them all into one buffer.
+        Member[] objs = new Member[aMethods.length + aFields.length + aCtors.length];
 
-    public GeneratableEntryPointIterator(Method[] aMethods) {
-        // Sort the methods into alphabetical order by name, to ensure we always iterate methods
-        // in the same order..
-        Arrays.sort(aMethods, new AlphabeticMethodComparator());
-        mMethods = aMethods;
+        int offset = 0;
+        System.arraycopy(aMethods, 0, objs, 0, aMethods.length);
+        offset += aMethods.length;
+        System.arraycopy(aFields, 0, objs, offset, aFields.length);
+        offset += aFields.length;
+        System.arraycopy(aCtors, 0, objs, offset, aCtors.length);
+
+        // Sort the elements to ensure determinism.
+        Arrays.sort(objs, new AlphabeticAnnotatableEntityComparator());
+        mObjects = objs;
+
+        // Check for "Wrap ALL the things" flag.
+        for (Annotation annotation : aClass.getDeclaredAnnotations()) {
+            final String annotationTypeName = annotation.annotationType().getName();
+            if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI")) {
+                mIterateEveryEntry = true;
+                break;
+            }
+        }
 
         findNextValue();
     }
 
     /**
      * Find and cache the next appropriately annotated method, plus the annotation parameter, if
      * one exists. Otherwise cache null, so hasNext returns false.
      */
     private void findNextValue() {
-        while (mMethodIndex < mMethods.length) {
-            Method candidateMethod = mMethods[mMethodIndex];
-            mMethodIndex++;
-            for (Annotation annotation : candidateMethod.getDeclaredAnnotations()) {
-                // GeneratableAndroidBridgeTarget has a parameter. Use Reflection to obtain it.
+        while (mElementIndex < mObjects.length) {
+            Member candidateElement = mObjects[mElementIndex];
+            mElementIndex++;
+            for (Annotation annotation : ((AnnotatedElement) candidateElement).getDeclaredAnnotations()) {
+                // WrappedJNIMethod has parameters. Use Reflection to obtain them.
                 Class<? extends Annotation> annotationType = annotation.annotationType();
                 final String annotationTypeName = annotationType.getName();
-
-                if (annotationTypeName.equals("org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget")) {
+                if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI")) {
                     String stubName = null;
                     boolean isStaticStub = false;
                     boolean isMultithreadedStub = false;
                     try {
                         // Determine the explicitly-given name of the stub to generate, if any.
                         final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
                         stubNameMethod.setAccessible(true);
                         stubName = (String) stubNameMethod.invoke(annotation);
@@ -61,51 +86,61 @@ public class GeneratableEntryPointIterat
                         staticStubMethod.setAccessible(true);
                         isStaticStub = (Boolean) staticStubMethod.invoke(annotation);
 
                         // Determine if the generated stub is to allow calls from multiple threads.
                         final Method multithreadedStubMethod = annotationType.getDeclaredMethod("allowMultithread");
                         multithreadedStubMethod.setAccessible(true);
                         isMultithreadedStub = (Boolean) multithreadedStubMethod.invoke(annotation);
                     } catch (NoSuchMethodException e) {
-                        System.err.println("Unable to find expected field on GeneratableAndroidBridgeTarget annotation. Did the signature change?");
+                        System.err.println("Unable to find expected field on WrapElementForJNI annotation. Did the signature change?");
                         e.printStackTrace(System.err);
                         System.exit(3);
                     } catch (IllegalAccessException e) {
-                        System.err.println("IllegalAccessException reading fields on GeneratableAndroidBridgeTarget annotation. Seems the semantics of Reflection have changed...");
+                        System.err.println("IllegalAccessException reading fields on WrapElementForJNI annotation. Seems the semantics of Reflection have changed...");
                         e.printStackTrace(System.err);
                         System.exit(4);
                     } catch (InvocationTargetException e) {
-                        System.err.println("InvocationTargetException reading fields on GeneratableAndroidBridgeTarget annotation. This really shouldn't happen.");
+                        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 = candidateMethod.getName();
+                        String aMethodName = candidateElement.getName();
                         stubName = aMethodName.substring(0, 1).toUpperCase() + aMethodName.substring(1);
                     }
 
-                    mNextReturnValue = new MethodWithAnnotationInfo(candidateMethod, stubName, isStaticStub, isMultithreadedStub);
+                    AnnotationInfo annotationInfo = new AnnotationInfo(stubName, isStaticStub, isMultithreadedStub);
+                    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 (mIterateEveryEntry) {
+                AnnotationInfo annotationInfo = new AnnotationInfo(candidateElement.getName(), false, false);
+                mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
+                return;
+            }
         }
         mNextReturnValue = null;
     }
 
     @Override
     public boolean hasNext() {
         return mNextReturnValue != null;
     }
 
     @Override
-    public MethodWithAnnotationInfo next() {
-        MethodWithAnnotationInfo ret = mNextReturnValue;
+    public AnnotatableEntity next() {
+        AnnotatableEntity ret = mNextReturnValue;
         findNextValue();
         return ret;
     }
 
     @Override
     public void remove() {
-        throw new UnsupportedOperationException("Removal of methods from GeneratableEntryPointIterator not supported.");
+        throw new UnsupportedOperationException("Removal of methods from GeneratableElementIterator not supported.");
     }
 }
--- a/build/annotationProcessors/utils/Utils.java
+++ b/build/annotationProcessors/utils/Utils.java
@@ -1,15 +1,18 @@
 /* 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 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 {
@@ -65,33 +68,48 @@ public class Utils {
         sInstanceCallTypes.put("long", "CallLongMethod");
         sInstanceCallTypes.put("double", "CallDoubleMethod");
         sInstanceCallTypes.put("float", "CallFloatMethod");
         sInstanceCallTypes.put("char", "CallCharMethod");
         sInstanceCallTypes.put("byte", "CallByteMethod");
         sInstanceCallTypes.put("short", "CallShortMethod");
     }
 
+    private static final HashMap<String, String> sFieldTypes = 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");
     }
 
     private static final HashMap<String, String> sCanonicalSignatureParts = 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");
@@ -159,26 +177,43 @@ public class Utils {
 
     /**
      * 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) {
-        // Since there's only one thing we want to do differently...
+        if (type.getCanonicalName().equals("java.lang.Void")) {
+            return "void";
+        }
         String cParameterType = getCParameterType(type);
         if (cParameterType.equals("const nsAString&")) {
             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 (sFieldTypes.containsKey(name)) {
+            return sFieldTypes.get(name);
+        }
+        return "Object";
+    }
+
+    /**
      * 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) {
@@ -207,159 +242,216 @@ public class Utils {
         String name = type.getCanonicalName();
         if (sFailureReturns.containsKey(name)) {
             return sFailureReturns.get(name);
         }
         return " nullptr";
     }
 
     /**
-     * Get the canonical JNI type signature for a method.
+     * 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 aMethod The method to generate a signature for.
-     * @return The canonical JNI type signature for this 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;
      */
-    public static String getTypeSignatureString(Method aMethod) {
-        Class<?>[] arguments = aMethod.getParameterTypes();
-        Class<?> returnType = aMethod.getReturnType();
-
+    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();
     }
 
     /**
-     * Helper method used by getTypeSignatureString to build the signature. Write the subsignature
+     * 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 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]);
+        }
+
+        // Constructors always return Void.
+        sb.append(")V");
+        return sb.toString();
+    }
+
+    /**
+     * Helper method used by getTypeSignatureStringForMethod to build the signature. Write the subsignature
      * of a given type into the buffer.
      *
      * @param sb The buffer to write into.
      * @param c  The type of the element to write the subsignature of.
      */
     private static void writeTypeSignature(StringBuilder sb, Class<?> c) {
         String name = c.getCanonicalName().replaceAll("\\.", "/");
+
         // 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 (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);
+        }
+
         // 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(';');
         }
     }
 
     /**
      * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
      * generating header files and method bodies.
      *
-     * @param aMethod      The Java method to generate the corresponding wrapper signature for.
-     * @param aCMethodName The name of the generated method this is to be the signatgure for.
-     * @return The generated method signature.
+     * @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.
      */
-    public static String getCImplementationMethodSignature(Method aMethod, String aCMethodName) {
-        Class<?>[] argumentTypes = aMethod.getParameterTypes();
-        Class<?> returnType = aMethod.getReturnType();
+    public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName) {
+        StringBuilder retBuffer = new StringBuilder();
 
-        StringBuilder retBuffer = new StringBuilder();
-        // Write return type..
-        retBuffer.append(getCReturnType(returnType));
-        retBuffer.append(" AndroidBridge::");
+        retBuffer.append(getCReturnType(aReturnType));
+        retBuffer.append(' ');
+        retBuffer.append(aCClassName);
+        retBuffer.append("::");
         retBuffer.append(aCMethodName);
         retBuffer.append('(');
 
-        // For an instance method, the first argument is the target object.
-        if (!isMethodStatic(aMethod)) {
-            retBuffer.append("jobject aTarget");
-            if (argumentTypes.length > 0) {
-                retBuffer.append(", ");
-            }
-        }
-
         // Write argument types...
-        for (int aT = 0; aT < argumentTypes.length; aT++) {
-            retBuffer.append(getCParameterType(argumentTypes[aT]));
+        for (int aT = 0; aT < aArgumentTypes.length; aT++) {
+            retBuffer.append(getCParameterType(aArgumentTypes[aT]));
             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 != argumentTypes.length - 1) {
+            if (aT != aArgumentTypes.length - 1) {
                 retBuffer.append(", ");
             }
         }
         retBuffer.append(')');
         return retBuffer.toString();
     }
 
     /**
      * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
      * generating header files and method bodies.
      *
-     * @param aMethod      The Java method to generate the corresponding wrapper signature for.
-     * @param aCMethodName The name of the generated method this is to be the signatgure for.
-     * @return The generated method signature.
+     * @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.
      */
-    public static String getCHeaderMethodSignature(Method aMethod, String aCMethodName, boolean aIsStaticStub) {
-        Class<?>[] argumentTypes = aMethod.getParameterTypes();
-
-        // The annotations on the parameters of this method, in declaration order.
-        // Importantly - the same order as those in argumentTypes.
-        Annotation[][] argumentAnnotations = aMethod.getParameterAnnotations();
-        Class<?> returnType = aMethod.getReturnType();
-
+    public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub) {
         StringBuilder retBuffer = new StringBuilder();
 
         // Add the static keyword, if applicable.
         if (aIsStaticStub) {
             retBuffer.append("static ");
         }
 
         // Write return type..
-        retBuffer.append(getCReturnType(returnType));
+        retBuffer.append(getCReturnType(aReturnType));
         retBuffer.append(' ');
         retBuffer.append(aCMethodName);
         retBuffer.append('(');
 
-        // For an instance method, the first argument is the target object.
-        if (!isMethodStatic(aMethod)) {
-            retBuffer.append("jobject aTarget");
-            if (argumentTypes.length > 0) {
-                retBuffer.append(", ");
-            }
-        }
-
         // Write argument types...
-        for (int aT = 0; aT < argumentTypes.length; aT++) {
-            retBuffer.append(getCParameterType(argumentTypes[aT]));
+        for (int aT = 0; aT < aArgumentTypes.length; aT++) {
+            retBuffer.append(getCParameterType(aArgumentTypes[aT]));
             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(argumentTypes[aT], argumentAnnotations[aT]));
+            retBuffer.append(getDefaultValueString(aArgumentTypes[aT], aArgumentAnnotations[aT]));
 
-            if (aT != argumentTypes.length - 1) {
+            if (aT != aArgumentTypes.length - 1) {
                 retBuffer.append(", ");
             }
         }
         retBuffer.append(')');
         return retBuffer.toString();
     }
 
     /**
@@ -371,17 +463,17 @@ public class Utils {
      * @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).
      */
     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.OptionalGeneratedParameter")) {
+            if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter")) {
                 return " = " + getDefaultParameterValueForType(aArgumentType);
             }
         }
         return "";
     }
 
     /**
      * Helper method to return an appropriate default parameter value for an argument of a given type.
@@ -401,24 +493,23 @@ public class Utils {
         } else {
             return "nullptr";
         }
     }
 
     /**
      * Helper method that returns the number of reference types in the arguments of m.
      *
-     * @param m The method to consider.
+     * @param aArgs The method arguments to consider.
      * @return How many of the arguments of m are nonprimitive.
      */
-    public static int enumerateReferenceArguments(Method m) {
+    public static int enumerateReferenceArguments(Class<?>[] aArgs) {
         int ret = 0;
-        Class<?>[] args = m.getParameterTypes();
-        for (int i = 0; i < args.length; i++) {
-            String name = args[i].getCanonicalName();
+        for (int i = 0; i < aArgs.length; i++) {
+            String name = aArgs[i].getCanonicalName();
             if (!sBasicCTypes.containsKey(name)) {
                 ret++;
             }
         }
         return ret;
     }
 
     /**
@@ -448,35 +539,33 @@ public class Utils {
         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 = NewJavaString(env, ").append(argName).append(");\n");
+                sb.append("l = AndroidBridge::NewJavaString(env, ").append(argName).append(");\n");
             } else {
                 sb.append("l = ").append(argName).append(";\n");
             }
         }
 
         return sb.toString();
     }
 
     /**
-     * Returns true if the method provided returns an object type. Returns false if it returns a
-     * primitive type.
+     * Returns true if the type provided is an object type. Returns false otherwise
      *
-     * @param aMethod The method to consider.
-     * @return true if the method provided returns an object type, false otherwise.
+     * @param aType The type to consider.
+     * @return true if the method provided is an object type, false otherwise.
      */
-    public static boolean doesReturnObjectType(Method aMethod) {
-        Class<?> returnType = aMethod.getReturnType();
-        return !sBasicCTypes.containsKey(returnType.getCanonicalName());
+    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.
      */
@@ -491,17 +580,26 @@ public class Utils {
      * @param aClass The target Java class.
      * @return The generated code to populate the reference to the class.
      */
     public static String getStartupLineForClass(Class<?> aClass) {
         StringBuilder sb = new StringBuilder();
         sb.append("    ");
         sb.append(getClassReferenceName(aClass));
         sb.append(" = getClassGlobalRef(\"");
-        sb.append(aClass.getCanonicalName().replaceAll("\\.", "/"));
+
+        String name = aClass.getCanonicalName().replaceAll("\\.", "/");
+        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();
     }
 
     /**
      * 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.
@@ -516,16 +614,26 @@ public class Utils {
                 return true;
             }
         }
         return false;
     }
 
     /**
      * Helper method to read the modifier bits of the given method to determine if it is static.
-     * @param aMethod The Method to check.
+     * @param aMember The Member to check.
      * @return true of the method is declared static, false otherwise.
      */
-    public static boolean isMethodStatic(Method aMethod) {
-        int aMethodModifiers = aMethod.getModifiers();
+    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);
+    }
 }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1787,18 +1787,18 @@ 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");
-    if (AndroidBridge::Bridge() != nullptr)
-        *showPassword = AndroidBridge::Bridge()->GetShowPasswordSetting();
+
+    *showPassword = GeckoAppShell::GetShowPasswordSetting();
 #endif
     return true;
 }
 
 bool
 ContentParent::RecvFirstIdle()
 {
 #ifdef MOZ_NUWA_PROCESS
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2257,21 +2257,17 @@ NPError NP_CALLBACK
     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: {
-      AndroidBridge *bridge = AndroidBridge::Bridge();
-      if (!bridge)
-        return NPERR_GENERIC_ERROR;
-
-      jobject ret = bridge->GetContext();
+      jobject ret = GeckoAppShell::GetContext();
       if (!ret)
         return NPERR_GENERIC_ERROR;
 
       int32_t* i  = reinterpret_cast<int32_t*>(result);
       *i = reinterpret_cast<int32_t>(ret);
       return NPERR_NO_ERROR;
     }
 
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -863,17 +863,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) {
-    AndroidBridge::Bridge()->LockScreenOrientation(mFullScreenOrientation);
+    GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
   }
 }
 
 void nsNPAPIPluginInstance::NotifySize(nsIntSize size)
 {
   if (kOpenGL_ANPDrawingModel != GetANPDrawingModel() ||
       size == mCurrentSize)
     return;
@@ -920,21 +920,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) {
-      AndroidBridge::Bridge()->LockScreenOrientation(mFullScreenOrientation);
+      GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
     } else if (oldOrientation != dom::eScreenOrientation_None) {
       // We applied an orientation when we entered fullscreen, but
       // we don't want it anymore
-      AndroidBridge::Bridge()->UnlockScreenOrientation();
+      GeckoAppShell::UnlockScreenOrientation();
     }
   }
 }
 
 void nsNPAPIPluginInstance::PopPostedEvent(PluginEventRunnable* r)
 {
   mPostedEvents.RemoveElement(r);
 }
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1667,19 +1667,17 @@ bool nsPluginInstanceOwner::AddPluginVie
   return true;
 }
 
 void nsPluginInstanceOwner::RemovePluginView()
 {
   if (!mInstance || !mJavaView)
     return;
 
-  if (AndroidBridge::Bridge())
-    AndroidBridge::Bridge()->RemovePluginView((jobject)mJavaView, mFullScreen);
-
+  GeckoAppShell::RemovePluginView((jobject)mJavaView, mFullScreen);
   AndroidBridge::GetJNIEnv()->DeleteGlobalRef((jobject)mJavaView);
   mJavaView = nullptr;
 
   if (mFullScreen)
     sFullScreenInstance = nullptr;
 }
 
 void nsPluginInstanceOwner::GetVideos(nsTArray<nsNPAPIPluginInstance::VideoInfo*>& aVideos)
--- a/dom/system/android/AndroidLocationProvider.cpp
+++ b/dom/system/android/AndroidLocationProvider.cpp
@@ -21,40 +21,34 @@ AndroidLocationProvider::AndroidLocation
 AndroidLocationProvider::~AndroidLocationProvider()
 {
     NS_IF_RELEASE(gLocationCallback);
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Startup()
 {
-    if (!AndroidBridge::Bridge())
-        return NS_ERROR_NOT_IMPLEMENTED;
-    AndroidBridge::Bridge()->EnableLocation(true);
+    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()
 {
-    if (!AndroidBridge::Bridge())
-        return NS_ERROR_NOT_IMPLEMENTED;
-    AndroidBridge::Bridge()->EnableLocation(false);
+    GeckoAppShell::EnableLocation(false);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::SetHighAccuracy(bool enable)
 {
-    if (!AndroidBridge::Bridge())
-        return NS_ERROR_NOT_IMPLEMENTED;
-    AndroidBridge::Bridge()->EnableLocationHighAccuracy(enable);
+    GeckoAppShell::EnableLocationHighAccuracy(enable);
     return NS_OK;
 }
--- a/dom/system/android/nsHapticFeedback.cpp
+++ b/dom/system/android/nsHapticFeedback.cpp
@@ -9,15 +9,11 @@
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS1(nsHapticFeedback, nsIHapticFeedback)
 
 NS_IMETHODIMP
 nsHapticFeedback::PerformSimpleAction(int32_t aType)
 {
-    AndroidBridge* bridge = AndroidBridge::Bridge();
-    if (bridge) {
-        bridge->PerformHapticFeedback(aType == LongPress);
-        return NS_OK;
-    }
-    return NS_ERROR_FAILURE;
+    GeckoAppShell::PerformHapticFeedback(aType == LongPress);
+    return NS_OK;
 }
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2510,17 +2510,17 @@ public:
     virtual bool UnbindExternalBuffer(GLuint texture) { return false; }
 
 #ifdef MOZ_WIDGET_GONK
     virtual EGLImage CreateEGLImageForNativeBuffer(void* buffer) = 0;
     virtual void DestroyEGLImage(EGLImage image) = 0;
 #endif
 
     virtual already_AddRefed<TextureImage>
-    CreateDirectTextureImage(android::GraphicBuffer* aBuffer, GLenum aWrapMode)
+    CreateDirectTextureImage(::android::GraphicBuffer* aBuffer, GLenum aWrapMode)
     { return nullptr; }
 
     // Before reads from offscreen texture
     void GuaranteeResolve();
 
 protected:
     GLuint mTexBlit_Buffer;
     GLuint mTexBlit_VertShader;
--- a/gfx/thebes/nsSurfaceTexture.cpp
+++ b/gfx/thebes/nsSurfaceTexture.cpp
@@ -205,17 +205,17 @@ nsSurfaceTexture::~nsSurfaceTexture()
     mNativeWindow = nullptr;
   }
 
   JNIEnv* env = GetJNIForThread();
   if (!env)
     return;
 
   if (mSurfaceTexture && env) {
-    AndroidBridge::Bridge()->UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
+    GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
 
     env->DeleteGlobalRef(mSurfaceTexture);
     mSurfaceTexture = nullptr;
   }
 }
 
 void*
 nsSurfaceTexture::GetNativeWindow()
@@ -234,19 +234,19 @@ nsSurfaceTexture::GetTransformMatrix(gfx
 {
   return sJNIFunctions.GetTransformMatrix(mSurfaceTexture, aMatrix);
 }
 
 void
 nsSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
 {
   if (aRunnable)
-    AndroidBridge::Bridge()->RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID);
+    GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID);
   else
-    AndroidBridge::Bridge()->UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
+    GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
 
   mFrameAvailableCallback = aRunnable;
 }
 
 void
 nsSurfaceTexture::NotifyFrameAvailable()
 {
   if (mFrameAvailableCallback) {
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -9,16 +9,17 @@
 #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,
@@ -49,107 +50,65 @@ Vibrate(const nsTArray<uint32_t> &patter
   b->Vibrate(pattern);
 }
 
 void
 CancelVibrate(const WindowIdentifier &)
 {
   // Ignore WindowIdentifier parameter.
 
-  AndroidBridge* b = AndroidBridge::Bridge();
-  if (b)
-    b->CancelVibrate();
+  GeckoAppShell::CancelVibrate();
 }
 
 void
 EnableBatteryNotifications()
 {
-  AndroidBridge* bridge = AndroidBridge::Bridge();
-  if (!bridge) {
-    return;
-  }
-
-  bridge->EnableBatteryNotifications();
+  GeckoAppShell::EnableBatteryNotifications();
 }
 
 void
 DisableBatteryNotifications()
 {
-  AndroidBridge* bridge = AndroidBridge::Bridge();
-  if (!bridge) {
-    return;
-  }
-
-  bridge->DisableBatteryNotifications();
+  GeckoAppShell::DisableBatteryNotifications();
 }
 
 void
 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
 {
-  AndroidBridge* bridge = AndroidBridge::Bridge();
-  if (!bridge) {
-    return;
-  }
-
-  bridge->GetCurrentBatteryInformation(aBatteryInfo);
+  AndroidBridge::Bridge()->GetCurrentBatteryInformation(aBatteryInfo);
 }
 
 void
 EnableNetworkNotifications()
 {
-  AndroidBridge* bridge = AndroidBridge::Bridge();
-  if (!bridge) {
-    return;
-  }
-
-  bridge->EnableNetworkNotifications();
+  GeckoAppShell::EnableNetworkNotifications();
 }
 
 void
 DisableNetworkNotifications()
 {
-  AndroidBridge* bridge = AndroidBridge::Bridge();
-  if (!bridge) {
-    return;
-  }
-
-  bridge->DisableNetworkNotifications();
+  GeckoAppShell::DisableNetworkNotifications();
 }
 
 void
 GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
 {
-  AndroidBridge* bridge = AndroidBridge::Bridge();
-  if (!bridge) {
-    return;
-  }
-
-  bridge->GetCurrentNetworkInformation(aNetworkInfo);
+  AndroidBridge::Bridge()->GetCurrentNetworkInformation(aNetworkInfo);
 }
 
 void
 EnableScreenConfigurationNotifications()
 {
-  AndroidBridge* bridge = AndroidBridge::Bridge();
-  if (!bridge) {
-    return;
-  }
-
-  bridge->EnableScreenOrientationNotifications();
+  GeckoAppShell::EnableScreenOrientationNotifications();
 }
 
 void
 DisableScreenConfigurationNotifications()
 {
-  AndroidBridge* bridge = AndroidBridge::Bridge();
-  if (!bridge) {
-    return;
-  }
-
-  bridge->DisableScreenOrientationNotifications();
+  GeckoAppShell::DisableScreenOrientationNotifications();
 }
 
 void
 GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration)
 {
   AndroidBridge* bridge = AndroidBridge::Bridge();
   if (!bridge) {
     return;
@@ -176,43 +135,33 @@ GetCurrentScreenConfiguration(ScreenConf
 
   *aScreenConfiguration =
     hal::ScreenConfiguration(rect, orientation, colorDepth, pixelDepth);
 }
 
 bool
 LockScreenOrientation(const ScreenOrientation& aOrientation)
 {
-  AndroidBridge* bridge = AndroidBridge::Bridge();
-  if (!bridge) {
-    return false;
-  }
-
   switch (aOrientation) {
     // 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:
-      bridge->LockScreenOrientation(aOrientation);
+      GeckoAppShell::LockScreenOrientation(aOrientation);
       return true;
     default:
       return false;
   }
 }
 
 void
 UnlockScreenOrientation()
 {
-  AndroidBridge* bridge = AndroidBridge::Bridge();
-  if (!bridge) {
-    return;
-  }
-
-  bridge->UnlockScreenOrientation();
+  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) {
-  AndroidBridge::Bridge()->EnableSensor(aSensor);
+  GeckoAppShell::EnableSensor(aSensor);
 }
 
 void
 DisableSensorNotifications(SensorType aSensor) {
-  AndroidBridge::Bridge()->DisableSensor(aSensor);
+  GeckoAppShell::DisableSensor(aSensor);
 }
 
 } // hal_impl
 } // mozilla
--- a/ipc/glue/MessagePump.cpp
+++ b/ipc/glue/MessagePump.cpp
@@ -90,17 +90,17 @@ MessagePump::Run(MessagePump::Delegate* 
     // here.  To ensure that MessageLoop tasks and XPCOM events have
     // 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
-    did_work |= AndroidBridge::Bridge()->PumpMessageLoop();
+    did_work |= GeckoAppShell::PumpMessageLoop();
 #endif
 
     did_work |= aDelegate->DoDelayedWork(&delayed_work_time_);
 
 if (did_work && delayed_work_time_.is_null()
 #ifdef MOZ_NUWA_PROCESS
     && (!IsNuwaReady() || !IsNuwaProcess())
 #endif
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -5,20 +5,20 @@
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.GeckoLayerClient;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PanZoomController;
+import org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.prompts.PromptService;
 import org.mozilla.gecko.mozglue.GeckoLoader;
-import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
-import org.mozilla.gecko.mozglue.OptionalGeneratedParameter;
 import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.PendingIntent;
@@ -397,33 +397,33 @@ public class GeckoAppShell
     }
 
     // Tell the Gecko event loop that an event is available.
     public static native void notifyGeckoOfEvent(GeckoEvent event);
 
     /*
      *  The Gecko-side API: API methods that Gecko calls
      */
-    @GeneratableAndroidBridgeTarget(generateStatic = true)
+    @WrapElementForJNI(generateStatic = true)
     public static void notifyIME(int type) {
         if (mEditableListener != null) {
             mEditableListener.notifyIME(type);
         }
     }
 
-    @GeneratableAndroidBridgeTarget(generateStatic = true)
+    @WrapElementForJNI(generateStatic = true)
     public static void notifyIMEContext(int state, String typeHint,
                                         String modeHint, String actionHint) {
         if (mEditableListener != null) {
             mEditableListener.notifyIMEContext(state, typeHint,
                                                modeHint, actionHint);
         }
     }
 
-    @GeneratableAndroidBridgeTarget(generateStatic = true)
+    @WrapElementForJNI(generateStatic = true)
     public static void notifyIMEChange(String text, int start, int end, int newEnd) {
         if (newEnd < 0) { // Selection change
             mEditableListener.onSelectionChange(start, end);
         } else { // Text change
             mEditableListener.onTextChange(text, start, end, newEnd);
         }
     }
 
@@ -457,17 +457,17 @@ public class GeckoAppShell
                 }
                 long waited = SystemClock.uptimeMillis() - time;
                 Log.d(LOGTAG, "Gecko event sync taking too long: " + waited + "ms");
             }
         }
     }
 
     // Signal the Java thread that it's time to wake up
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void acknowledgeEvent() {
         synchronized (sEventAckLock) {
             sWaitingForEventAck = false;
             sEventAckLock.notifyAll();
         }
     }
 
     private static float getLocationAccuracy(Location location) {
@@ -496,17 +496,17 @@ public class GeckoAppShell
                  getLocationAccuracy(location) < getLocationAccuracy(lastKnownLocation))) {
                 lastKnownLocation = location;
             }
         }
 
         return lastKnownLocation;
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void enableLocation(final boolean enable) {
         ThreadUtils.postToUiThread(new Runnable() {
                 @Override
                 public void run() {
                     LocationManager lm = getLocationManager(getContext());
                     if (lm == null) {
                         return;
                     }
@@ -552,22 +552,22 @@ public class GeckoAppShell
             // which allows enabling/disabling location update notifications from the cell radio.
             // CONTROL_LOCATION_UPDATES is not for use by normal applications, but we might be
             // hitting this problem if the Tegras are confused about missing cell radios.
             Log.e(LOGTAG, "LOCATION_SERVICE not found?!", e);
             return null;
         }
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void enableLocationHighAccuracy(final boolean enable) {
         mLocationHighAccuracy = enable;
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void enableSensor(int aSensortype) {
         GeckoInterface gi = getGeckoInterface();
         if (gi == null)
             return;
         SensorManager sm = (SensorManager)
             getContext().getSystemService(Context.SENSOR_SERVICE);
 
         switch(aSensortype) {
@@ -612,17 +612,17 @@ public class GeckoAppShell
             if (gGyroscopeSensor != null)
                 sm.registerListener(gi.getSensorEventListener(), gGyroscopeSensor, sDefaultSensorHint);
             break;
         default:
             Log.w(LOGTAG, "Error! Can't enable unknown SENSOR type " + aSensortype);
         }
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void disableSensor(int aSensortype) {
         GeckoInterface gi = getGeckoInterface();
         if (gi == null)
             return;
 
         SensorManager sm = (SensorManager)
             getContext().getSystemService(Context.SENSOR_SERVICE);
 
@@ -656,44 +656,44 @@ public class GeckoAppShell
             if (gGyroscopeSensor != null)
                 sm.unregisterListener(gi.getSensorEventListener(), gGyroscopeSensor);
             break;
         default:
             Log.w(LOGTAG, "Error! Can't disable unknown SENSOR type " + aSensortype);
         }
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void moveTaskToBack() {
         if (getGeckoInterface() != null)
             getGeckoInterface().getActivity().moveTaskToBack(true);
     }
 
     public static void returnIMEQueryResult(String result, int selectionStart, int selectionLength) {
         // This method may be called from JNI to report Gecko's current selection indexes, but
         // Native Fennec doesn't care because the Java code already knows the selection indexes.
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "NotifyXreExit")
+    @WrapElementForJNI(stubName = "NotifyXreExit")
     static void onXreExit() {
         // The launch state can only be Launched or GeckoRunning at this point
         GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoExiting);
         if (getGeckoInterface() != null) {
             if (gRestartScheduled) {
                 getGeckoInterface().doRestart();
             } else {
                 getGeckoInterface().getActivity().finish();
             }
         }
 
         Log.d(LOGTAG, "Killing via System.exit()");
         System.exit(0);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     static void scheduleRestart() {
         gRestartScheduled = true;
     }
 
     public static File preInstallWebApp(String aTitle, String aURI, String aOrigin) {
         int index = WebAppAllocator.getInstance(getContext()).findAndAllocateIndex(aOrigin, aTitle, (String) null);
         GeckoProfile profile = GeckoProfile.get(getContext(), "webapp" + index);
         return profile.getDir();
@@ -726,17 +726,17 @@ public class GeckoAppShell
         intent.setData(Uri.parse(aURI));
         intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
                             AppConstants.ANDROID_PACKAGE_NAME + ".WebApps$WebApp" + aIndex);
         return intent;
     }
 
     // "Installs" an application by creating a shortcut
     // This is the entry point from AndroidBridge.h
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     static void createShortcut(String aTitle, String aURI, String aIconData, String aType) {
         if ("webapp".equals(aType)) {
             Log.w(LOGTAG, "createShortcut with no unique URI should not be used for aType = webapp!");
         }
 
         createShortcut(aTitle, aURI, aURI, aIconData, aType);
     }
 
@@ -921,25 +921,25 @@ public class GeckoAppShell
                                    halfSize - sHeight,
                                    halfSize + sWidth,
                                    halfSize + sHeight),
                           null);
 
         return bitmap;
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetHandlersForMimeTypeWrapper")
+    @WrapElementForJNI(stubName = "GetHandlersForMimeTypeWrapper")
     static String[] getHandlersForMimeType(String aMimeType, String aAction) {
         Intent intent = getIntentForActionString(aAction);
         if (aMimeType != null && aMimeType.length() > 0)
             intent.setType(aMimeType);
         return getHandlersForIntent(intent);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetHandlersForURLWrapper")
+    @WrapElementForJNI(stubName = "GetHandlersForURLWrapper")
     static String[] getHandlersForURL(String aURL, String aAction) {
         // aURL may contain the whole URL or just the protocol
         Uri uri = aURL.indexOf(':') >= 0 ? Uri.parse(aURL) : new Uri.Builder().scheme(aURL).build();
 
         Intent intent = getOpenURIIntent(getContext(), uri.toString(), "",
             TextUtils.isEmpty(aAction) ? Intent.ACTION_VIEW : aAction, "");
 
         return getHandlersForIntent(intent);
@@ -972,22 +972,22 @@ public class GeckoAppShell
     static Intent getIntentForActionString(String aAction) {
         // Default to the view action if no other action as been specified.
         if (TextUtils.isEmpty(aAction)) {
             return new Intent(Intent.ACTION_VIEW);
         }
         return new Intent(aAction);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetExtensionFromMimeTypeWrapper")
+    @WrapElementForJNI(stubName = "GetExtensionFromMimeTypeWrapper")
     static String getExtensionFromMimeType(String aMimeType) {
         return MimeTypeMap.getSingleton().getExtensionFromMimeType(aMimeType);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetMimeTypeFromExtensionsWrapper")
+    @WrapElementForJNI(stubName = "GetMimeTypeFromExtensionsWrapper")
     static String getMimeTypeFromExtensions(String aFileExt) {
         StringTokenizer st = new StringTokenizer(aFileExt, ".,; ");
         String type = null;
         String subType = null;
         while (st.hasMoreElements()) {
             String ext = st.nextToken();
             String mt = getMimeTypeFromExtension(ext);
             if (mt == null)
@@ -1110,17 +1110,17 @@ public class GeckoAppShell
      *
      * @param targetURI the string spec of the URI to open.
      * @param mimeType an optional MIME type string.
      * @param action an Android action specifier, such as
      *               <code>Intent.ACTION_SEND</code>.
      * @param title the title to use in <code>ACTION_SEND</code> intents.
      * @return true if the activity started successfully; false otherwise.
      */
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static boolean openUriExternal(String targetURI,
                                           String mimeType,
               @OptionalGeneratedParameter String packageName,
               @OptionalGeneratedParameter String className,
               @OptionalGeneratedParameter String action,
               @OptionalGeneratedParameter String title) {
         final Context context = getContext();
         final Intent intent = getOpenURIIntent(context, targetURI,
@@ -1296,17 +1296,17 @@ public class GeckoAppShell
     public static void setNotificationClient(NotificationClient client) {
         if (sNotificationClient == null) {
             sNotificationClient = client;
         } else {
             Log.d(LOGTAG, "Notification client already set");
         }
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "ShowAlertNotificationWrapper")
+    @WrapElementForJNI(stubName = "ShowAlertNotificationWrapper")
     public static void showAlertNotification(String aImageUrl, String aAlertTitle, String aAlertText,
                                              String aAlertCookie, String aAlertName) {
         // The intent to launch when the user clicks the expanded notification
         String app = getContext().getClass().getName();
         Intent notificationIntent = new Intent(GeckoApp.ACTION_ALERT_CALLBACK);
         notificationIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, app);
         notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
@@ -1323,23 +1323,23 @@ public class GeckoAppShell
                 getContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
 
         mAlertCookies.put(aAlertName, aAlertCookie);
         callObserver(aAlertName, "alertshow", aAlertCookie);
 
         sNotificationClient.add(notificationID, aImageUrl, aAlertTitle, aAlertText, contentIntent);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void alertsProgressListener_OnProgress(String aAlertName, long aProgress, long aProgressMax, String aAlertText) {
         int notificationID = aAlertName.hashCode();
         sNotificationClient.update(notificationID, aProgress, aProgressMax, aAlertText);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void closeNotification(String aAlertName) {
         String alertCookie = mAlertCookies.get(aAlertName);
         if (alertCookie != null) {
             callObserver(aAlertName, "alertfinished", alertCookie);
             mAlertCookies.remove(aAlertName);
         }
 
         removeObserver(aAlertName);
@@ -1357,26 +1357,26 @@ public class GeckoAppShell
             if (sNotificationClient.isOngoing(notificationID)) {
                 // When clicked, keep the notification if it displays progress
                 return;
             }
         }
         closeNotification(aAlertName);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetDpiWrapper")
+    @WrapElementForJNI(stubName = "GetDpiWrapper")
     public static int getDpi() {
         if (sDensityDpi == 0) {
             sDensityDpi = getContext().getResources().getDisplayMetrics().densityDpi;
         }
 
         return sDensityDpi;
     }
 
-    @GeneratableAndroidBridgeTarget()
+    @WrapElementForJNI
     public static float getDensity() {
         return getContext().getResources().getDisplayMetrics().density;
     }
 
     private static boolean isHighMemoryDevice() {
         BufferedReader br = null;
         FileReader fr = null;
         try {
@@ -1401,17 +1401,17 @@ public class GeckoAppShell
         }
         return false;
     }
 
     /**
      * Returns the colour depth of the default screen. This will either be
      * 24 or 16.
      */
-    @GeneratableAndroidBridgeTarget(stubName = "GetScreenDepthWrapper")
+    @WrapElementForJNI(stubName = "GetScreenDepthWrapper")
     public static synchronized int getScreenDepth() {
         if (sScreenDepth == 0) {
             sScreenDepth = 16;
             PixelFormat info = new PixelFormat();
             PixelFormat.getPixelFormatInfo(getGeckoInterface().getActivity().getWindowManager().getDefaultDisplay().getPixelFormat(), info);
             if (info.bitsPerPixel >= 24 && isHighMemoryDevice()) {
                 sScreenDepth = 24;
             }
@@ -1424,133 +1424,133 @@ public class GeckoAppShell
         if (sScreenDepth != 0) {
             Log.e(LOGTAG, "Tried to override screen depth after it's already been set");
             return;
         }
 
         sScreenDepth = aScreenDepth;
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void setFullScreen(boolean fullscreen) {
         if (getGeckoInterface() != null)
             getGeckoInterface().setFullScreen(fullscreen);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "ShowFilePickerForExtensionsWrapper")
+    @WrapElementForJNI(stubName = "ShowFilePickerForExtensionsWrapper")
     public static String showFilePickerForExtensions(String aExtensions) {
         if (getGeckoInterface() != null)
             return sActivityHelper.showFilePicker(getGeckoInterface().getActivity(), getMimeTypeFromExtensions(aExtensions));
         return "";
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "ShowFilePickerForMimeTypeWrapper")
+    @WrapElementForJNI(stubName = "ShowFilePickerForMimeTypeWrapper")
     public static String showFilePickerForMimeType(String aMimeType) {
         if (getGeckoInterface() != null)
             return sActivityHelper.showFilePicker(getGeckoInterface().getActivity(), aMimeType);
         return "";
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void performHapticFeedback(boolean aIsLongPress) {
         // Don't perform haptic feedback if a vibration is currently playing,
         // because the haptic feedback will nuke the vibration.
         if (!sVibrationMaybePlaying || System.nanoTime() >= sVibrationEndTime) {
             LayerView layerView = getLayerView();
             layerView.performHapticFeedback(aIsLongPress ?
                                             HapticFeedbackConstants.LONG_PRESS :
                                             HapticFeedbackConstants.VIRTUAL_KEY);
         }
     }
 
     private static Vibrator vibrator() {
         LayerView layerView = getLayerView();
         return (Vibrator) layerView.getContext().getSystemService(Context.VIBRATOR_SERVICE);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "Vibrate1")
+    @WrapElementForJNI(stubName = "Vibrate1")
     public static void vibrate(long milliseconds) {
         sVibrationEndTime = System.nanoTime() + milliseconds * 1000000;
         sVibrationMaybePlaying = true;
         vibrator().vibrate(milliseconds);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "VibrateA")
+    @WrapElementForJNI(stubName = "VibrateA")
     public static void vibrate(long[] pattern, int repeat) {
         // If pattern.length is even, the last element in the pattern is a
         // meaningless delay, so don't include it in vibrationDuration.
         long vibrationDuration = 0;
         int iterLen = pattern.length - (pattern.length % 2 == 0 ? 1 : 0);
         for (int i = 0; i < iterLen; i++) {
           vibrationDuration += pattern[i];
         }
 
         sVibrationEndTime = System.nanoTime() + vibrationDuration * 1000000;
         sVibrationMaybePlaying = true;
         vibrator().vibrate(pattern, repeat);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void cancelVibrate() {
         sVibrationMaybePlaying = false;
         sVibrationEndTime = 0;
         vibrator().cancel();
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void showInputMethodPicker() {
         InputMethodManager imm = (InputMethodManager)
             getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
         imm.showInputMethodPicker();
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void setKeepScreenOn(final boolean on) {
         ThreadUtils.postToUiThread(new Runnable() {
             @Override
             public void run() {
                 // TODO
             }
         });
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void notifyDefaultPrevented(final boolean defaultPrevented) {
         ThreadUtils.postToUiThread(new Runnable() {
             @Override
             public void run() {
                 LayerView view = getLayerView();
                 PanZoomController controller = (view == null ? null : view.getPanZoomController());
                 if (controller != null) {
                     controller.notifyDefaultActionPrevented(defaultPrevented);
                 }
             }
         });
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static boolean isNetworkLinkUp() {
         ConnectivityManager cm = (ConnectivityManager)
            getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
         NetworkInfo info = cm.getActiveNetworkInfo();
         if (info == null || !info.isConnected())
             return false;
         return true;
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static boolean isNetworkLinkKnown() {
         ConnectivityManager cm = (ConnectivityManager)
             getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
         if (cm.getActiveNetworkInfo() == null)
             return false;
         return true;
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static int networkLinkType() {
         ConnectivityManager cm = (ConnectivityManager)
             getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
         NetworkInfo info = cm.getActiveNetworkInfo();
         if (info == null) {
             return LINK_TYPE_UNKNOWN;
         }
 
@@ -1599,17 +1599,17 @@ public class GeckoAppShell
                 return LINK_TYPE_4G; // 3.9G
             case TelephonyManager.NETWORK_TYPE_UNKNOWN:
             default:
                 Log.w(LOGTAG, "Connected to an unknown mobile network!");
                 return LINK_TYPE_UNKNOWN;
         }
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void setSelectedLocale(String localeCode) {
         /* Bug 713464: This method is still called from Gecko side.
            Earlier we had an option to run Firefox in a language other than system's language.
            However, this is not supported as of now.
            Gecko resets the locale to en-US by calling this function with an empty string.
            This affects GeckoPreferences activity in multi-locale builds.
 
         N.B., if this code ever becomes live again, you need to hook it up to locale
@@ -1638,17 +1638,17 @@ public class GeckoAppShell
         Resources res = getContext().getBaseContext().getResources();
         Configuration config = res.getConfiguration();
         config.locale = locale;
         res.updateConfiguration(config, res.getDisplayMetrics());
         */
     }
 
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetSystemColoursWrapper")
+    @WrapElementForJNI(stubName = "GetSystemColoursWrapper")
     public static int[] getSystemColors() {
         // attrsAppearance[] must correspond to AndroidSystemColors structure in android/AndroidBridge.h
         final int[] attrsAppearance = {
             android.R.attr.textColor,
             android.R.attr.textColorPrimary,
             android.R.attr.textColorPrimaryInverse,
             android.R.attr.textColorSecondary,
             android.R.attr.textColorSecondaryInverse,
@@ -1675,17 +1675,17 @@ public class GeckoAppShell
                 result[idx] = color;
             }
             appearance.recycle();
         }
 
         return result;
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void killAnyZombies() {
         GeckoProcessesVisitor visitor = new GeckoProcessesVisitor() {
             @Override
             public boolean callback(int pid) {
                 if (pid != android.os.Process.myPid())
                     android.os.Process.killProcess(pid);
                 return true;
             }
@@ -1831,31 +1831,31 @@ public class GeckoAppShell
                 String file = split[nameColumn];
                 if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(file) && file.startsWith(filter))
                     Log.i(LOGTAG, "[OPENFILE] " + name + "(" + split[pidColumn] + ") : " + file);
             }
             in.close();
         } catch (Exception e) { }
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void scanMedia(String aFile, String aMimeType) {
         // If the platform didn't give us a mimetype, try to guess one from the filename
         if (TextUtils.isEmpty(aMimeType)) {
             int extPosition = aFile.lastIndexOf(".");
             if (extPosition > 0 && extPosition < aFile.length() - 1) {
                 aMimeType = getMimeTypeFromExtension(aFile.substring(extPosition+1));
             }
         }
 
         Context context = getContext();
         GeckoMediaScannerClient.startScan(context, aFile, aMimeType);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetIconForExtensionWrapper")
+    @WrapElementForJNI(stubName = "GetIconForExtensionWrapper")
     public static byte[] getIconForExtension(String aExt, int iconSize) {
         try {
             if (iconSize <= 0)
                 iconSize = 16;
 
             if (aExt != null && aExt.length() > 1 && aExt.charAt(0) == '.')
                 aExt = aExt.substring(1);
 
@@ -1903,39 +1903,39 @@ public class GeckoAppShell
         if (resolveInfo == null)
             return null;
 
         ActivityInfo activityInfo = resolveInfo.activityInfo;
 
         return activityInfo.loadIcon(pm);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static boolean getShowPasswordSetting() {
         try {
             int showPassword =
                 Settings.System.getInt(getContext().getContentResolver(),
                                        Settings.System.TEXT_SHOW_PASSWORD, 1);
             return (showPassword > 0);
         }
         catch (Exception e) {
             return true;
         }
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "AddPluginViewWrapper")
+    @WrapElementForJNI(stubName = "AddPluginViewWrapper")
     public static void addPluginView(View view,
                                      float x, float y,
                                      float w, float h,
                                      boolean isFullScreen) {
         if (getGeckoInterface() != null)
              getGeckoInterface().addPluginView(view, new RectF(x, y, x + w, y + h), isFullScreen);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void removePluginView(View view, boolean isFullScreen) {
         if (getGeckoInterface() != null)
             getGeckoInterface().removePluginView(view, isFullScreen);
     }
 
     /**
      * A plugin that wish to be loaded in the WebView must provide this permission
      * in their AndroidManifest.xml.
@@ -2149,17 +2149,17 @@ public class GeckoAppShell
         } catch (android.content.pm.PackageManager.NameNotFoundException nnfe) {
             Log.w(LOGTAG, "Couldn't find package.", nnfe);
             return null;
         }
     }
 
     private static ContextGetter sContextGetter;
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true)
+    @WrapElementForJNI(allowMultithread = true)
     public static Context getContext() {
         return sContextGetter.getContext();
     }
 
     public static void setContextGetter(ContextGetter cg) {
         sContextGetter = cg;
     }
 
@@ -2207,17 +2207,17 @@ public class GeckoAppShell
     public static android.hardware.Camera sCamera = null;
 
     static native void cameraCallbackBridge(byte[] data);
 
     static int kPreferedFps = 25;
     static byte[] sCameraBuffer = null;
 
 
-    @GeneratableAndroidBridgeTarget(stubName = "InitCameraWrapper")
+    @WrapElementForJNI(stubName = "InitCameraWrapper")
     static int[] initCamera(String aContentType, int aCamera, int aWidth, int aHeight) {
         ThreadUtils.postToUiThread(new Runnable() {
                 @Override
                 public void run() {
                     try {
                         if (getGeckoInterface() != null)
                             getGeckoInterface().enableCameraView();
                     } catch (Exception e) {}
@@ -2308,17 +2308,17 @@ public class GeckoAppShell
             result[3] = params.getPreviewFrameRate();
         } catch(RuntimeException e) {
             Log.w(LOGTAG, "initCamera RuntimeException.", e);
             result[0] = result[1] = result[2] = result[3] = 0;
         }
         return result;
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     static synchronized void closeCamera() {
         ThreadUtils.postToUiThread(new Runnable() {
                 @Override
                 public void run() {
                     try {
                         if (getGeckoInterface() != null)
                             getGeckoInterface().disableCameraView();
                     } catch (Exception e) {}
@@ -2360,148 +2360,148 @@ public class GeckoAppShell
      */
     public static void unregisterEventListener(String event, GeckoEventListener listener) {
         sEventDispatcher.unregisterEventListener(event, listener);
     }
 
     /*
      * Battery API related methods.
      */
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void enableBatteryNotifications() {
         GeckoBatteryManager.enableNotifications();
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "HandleGeckoMessageWrapper")
+    @WrapElementForJNI(stubName = "HandleGeckoMessageWrapper")
     public static String handleGeckoMessage(String message) {
         return sEventDispatcher.dispatchEvent(message);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void disableBatteryNotifications() {
         GeckoBatteryManager.disableNotifications();
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetCurrentBatteryInformationWrapper")
+    @WrapElementForJNI(stubName = "GetCurrentBatteryInformationWrapper")
     public static double[] getCurrentBatteryInformation() {
         return GeckoBatteryManager.getCurrentInformation();
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "CheckURIVisited")
+    @WrapElementForJNI(stubName = "CheckURIVisited")
     static void checkUriVisited(String uri) {
         GlobalHistory.getInstance().checkUriVisited(uri);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "MarkURIVisited")
+    @WrapElementForJNI(stubName = "MarkURIVisited")
     static void markUriVisited(final String uri) {
         ThreadUtils.postToBackgroundThread(new Runnable() {
             @Override
             public void run() {
                 GlobalHistory.getInstance().add(uri);
             }
         });
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "SetURITitle")
+    @WrapElementForJNI(stubName = "SetURITitle")
     static void setUriTitle(final String uri, final String title) {
         ThreadUtils.postToBackgroundThread(new Runnable() {
             @Override
             public void run() {
                 GlobalHistory.getInstance().update(uri, title);
             }
         });
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     static void hideProgressDialog() {
         // unused stub
     }
 
     /*
      * WebSMS related methods.
      */
-    @GeneratableAndroidBridgeTarget(stubName = "SendMessageWrapper")
+    @WrapElementForJNI(stubName = "SendMessageWrapper")
     public static void sendMessage(String aNumber, String aMessage, int aRequestId) {
         if (SmsManager.getInstance() == null) {
             return;
         }
 
         SmsManager.getInstance().send(aNumber, aMessage, aRequestId);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetMessageWrapper")
+    @WrapElementForJNI(stubName = "GetMessageWrapper")
     public static void getMessage(int aMessageId, int aRequestId) {
         if (SmsManager.getInstance() == null) {
             return;
         }
 
         SmsManager.getInstance().getMessage(aMessageId, aRequestId);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "DeleteMessageWrapper")
+    @WrapElementForJNI(stubName = "DeleteMessageWrapper")
     public static void deleteMessage(int aMessageId, int aRequestId) {
         if (SmsManager.getInstance() == null) {
             return;
         }
 
         SmsManager.getInstance().deleteMessage(aMessageId, aRequestId);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "CreateMessageListWrapper")
+    @WrapElementForJNI(stubName = "CreateMessageListWrapper")
     public static void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId) {
         if (SmsManager.getInstance() == null) {
             return;
         }
 
         SmsManager.getInstance().createMessageList(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetNextMessageInListWrapper")
+    @WrapElementForJNI(stubName = "GetNextMessageInListWrapper")
     public static void getNextMessageInList(int aListId, int aRequestId) {
         if (SmsManager.getInstance() == null) {
             return;
         }
 
         SmsManager.getInstance().getNextMessageInList(aListId, aRequestId);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void clearMessageList(int aListId) {
         if (SmsManager.getInstance() == null) {
             return;
         }
 
         SmsManager.getInstance().clearMessageList(aListId);
     }
 
     /* Called by JNI from AndroidBridge, and by reflection from tests/BaseTest.java.in */
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static boolean isTablet() {
         return HardwareUtils.isTablet();
     }
 
     public static void viewSizeChanged() {
         LayerView v = getLayerView();
         if (v != null && v.isIMEEnabled()) {
             sendEventToGecko(GeckoEvent.createBroadcastEvent(
                     "ScrollTo:FocusedInput", ""));
         }
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetCurrentNetworkInformationWrapper")
+    @WrapElementForJNI(stubName = "GetCurrentNetworkInformationWrapper")
     public static double[] getCurrentNetworkInformation() {
         return GeckoNetworkManager.getInstance().getCurrentInformation();
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void enableNetworkNotifications() {
         GeckoNetworkManager.getInstance().enableNotifications();
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void disableNetworkNotifications() {
         GeckoNetworkManager.getInstance().disableNotifications();
     }
 
     // values taken from android's Base64
     public static final int BASE64_DEFAULT = 0;
     public static final int BASE64_URL_SAFE = 8;
 
@@ -2605,42 +2605,42 @@ public class GeckoAppShell
             if (op<oLen) out[op++] = (byte)o2; }
         return out; 
     }
 
     public static byte[] decodeBase64(String s, int flags) {
         return decodeBase64(s.getBytes(), flags);
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetScreenOrientationWrapper")
+    @WrapElementForJNI(stubName = "GetScreenOrientationWrapper")
     public static short getScreenOrientation() {
         return GeckoScreenOrientationListener.getInstance().getScreenOrientation();
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void enableScreenOrientationNotifications() {
         GeckoScreenOrientationListener.getInstance().enableNotifications();
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void disableScreenOrientationNotifications() {
         GeckoScreenOrientationListener.getInstance().disableNotifications();
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void lockScreenOrientation(int aOrientation) {
         GeckoScreenOrientationListener.getInstance().lockScreenOrientation(aOrientation);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void unlockScreenOrientation() {
         GeckoScreenOrientationListener.getInstance().unlockScreenOrientation();
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static boolean pumpMessageLoop() {
         Handler geckoHandler = ThreadUtils.sGeckoHandler;
         Message msg = getNextMessageFromQueue(ThreadUtils.sGeckoQueue);
 
         if (msg == null)
             return false;
         if (msg.obj == geckoHandler && msg.getTarget() == geckoHandler) {
             // Our "queue is empty" message; see runGecko()
@@ -2652,61 +2652,61 @@ public class GeckoAppShell
         else
             msg.getTarget().dispatchMessage(msg);
         msg.recycle();
         return true;
     }
 
     static native void notifyFilePickerResult(String filePath, long id);
 
-    @GeneratableAndroidBridgeTarget(stubName = "ShowFilePickerAsyncWrapper")
+    @WrapElementForJNI(stubName = "ShowFilePickerAsyncWrapper")
     public static void showFilePickerAsync(String aMimeType, final long id) {
         sActivityHelper.showFilePickerAsync(getGeckoInterface().getActivity(), aMimeType, new ActivityHandlerHelper.FileResultHandler() {
             public void gotFile(String filename) {
                 GeckoAppShell.notifyFilePickerResult(filename, id);
             }
         });
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void notifyWakeLockChanged(String topic, String state) {
         if (getGeckoInterface() != null)
             getGeckoInterface().notifyWakeLockChanged(topic, state);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static void registerSurfaceTextureFrameListener(Object surfaceTexture, final int id) {
         ((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
             @Override
             public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                 GeckoAppShell.onSurfaceTextureFrameAvailable(surfaceTexture, id);
             }
         });
     }
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true)
+    @WrapElementForJNI(allowMultithread = true)
     public static void unregisterSurfaceTextureFrameListener(Object surfaceTexture) {
         ((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(null);
     }
 
-    @GeneratableAndroidBridgeTarget
+    @WrapElementForJNI
     public static boolean unlockProfile() {
         // Try to kill any zombie Fennec's that might be running
         GeckoAppShell.killAnyZombies();
 
         // Then force unlock this profile
         if (getGeckoInterface() != null) {
             GeckoProfile profile = getGeckoInterface().getProfile();
             File lock = profile.getFile(".parentlock");
             return lock.exists() && lock.delete();
         }
         return false;
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetProxyForURIWrapper")
+    @WrapElementForJNI(stubName = "GetProxyForURIWrapper")
     public static String getProxyForURI(String spec, String scheme, String host, int port) {
         URI uri = null;
         try {
             uri = new URI(spec);
         } catch(java.net.URISyntaxException uriEx) {
             try {
                 uri = new URI(scheme, null, host, port, null, null, null);
             } catch(java.net.URISyntaxException uriEx2) {
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -2,16 +2,18 @@
  * 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;
 
 import org.mozilla.gecko.gfx.DisplayPortMetrics;
 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
+import org.mozilla.gecko.mozglue.generatorannotations.GeneratorOptions;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
 
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorManager;
@@ -78,16 +80,18 @@ public class GeckoEvent {
             this.value = value;
          }
     }
 
     /**
      * The DomKeyLocation enum encapsulates the DOM KeyboardEvent's constants.
      * @see https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_location_constants
      */
+    @GeneratorOptions(generatedClassName = "JavaDomKeyLocation")
+    @WrapEntireClassForJNI
     public enum DomKeyLocation {
         DOM_KEY_LOCATION_STANDARD(0),
         DOM_KEY_LOCATION_LEFT(1),
         DOM_KEY_LOCATION_RIGHT(2),
         DOM_KEY_LOCATION_NUMPAD(3),
         DOM_KEY_LOCATION_MOBILE(4),
         DOM_KEY_LOCATION_JOYSTICK(5);
 
--- a/mobile/android/base/GeckoJavaSampler.java
+++ b/mobile/android/base/GeckoJavaSampler.java
@@ -3,17 +3,17 @@
  * 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;
 
 import android.os.SystemClock;
 import android.util.Log;
 
-import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 
 import java.lang.Thread;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
 public class GeckoJavaSampler {
     private static final String LOGTAG = "JavaSampler";
@@ -121,82 +121,82 @@ public class GeckoJavaSampler {
                 int readPos = (startPos + aSampleId) % mSamples.get(aThreadId).length;
                 return mSamples.get(aThreadId)[readPos];
             }
             return null;
         }
     }
 
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "GetThreadNameJavaProfilingWrapper")
+    @WrapElementForJNI(allowMultithread = true, stubName = "GetThreadNameJavaProfilingWrapper")
     public synchronized static String getThreadName(int aThreadId) {
         if (aThreadId == 0 && sMainThread != null) {
             return sMainThread.getName();
         }
         return null;
     }
 
     private synchronized static Sample getSample(int aThreadId, int aSampleId) {
         return sSamplingRunnable.getSample(aThreadId, aSampleId);
     }
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "GetSampleTimeJavaProfiling")
+    @WrapElementForJNI(allowMultithread = true, stubName = "GetSampleTimeJavaProfiling")
     public synchronized static double getSampleTime(int aThreadId, int aSampleId) {
         Sample sample = getSample(aThreadId, aSampleId);
         if (sample != null) {
             if (sample.mJavaTime != 0) {
                 return (double)(sample.mJavaTime -
                     SystemClock.elapsedRealtime()) + getProfilerTime();
             }
             System.out.println("Sample: " + sample.mTime);
             return sample.mTime;
         }
         return 0;
     }
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "GetFrameNameJavaProfilingWrapper")
+    @WrapElementForJNI(allowMultithread = true, stubName = "GetFrameNameJavaProfilingWrapper")
     public synchronized static String getFrameName(int aThreadId, int aSampleId, int aFrameId) {
         Sample sample = getSample(aThreadId, aSampleId);
         if (sample != null && aFrameId < sample.mFrames.length) {
             Frame frame = sample.mFrames[aFrameId];
             if (frame == null) {
                 return null;
             }
             return frame.className + "." + frame.methodName + "()";
         }
         return null;
     }
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "StartJavaProfiling")
+    @WrapElementForJNI(allowMultithread = true, stubName = "StartJavaProfiling")
     public static void start(int aInterval, int aSamples) {
         synchronized (GeckoJavaSampler.class) {
             if (sSamplingRunnable != null) {
                 return;
             }
             sSamplingRunnable = new SamplingThread(aInterval, aSamples);
             sSamplingThread = new Thread(sSamplingRunnable, "Java Sampler");
             sSamplingThread.start();
         }
     }
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "PauseJavaProfiling")
+    @WrapElementForJNI(allowMultithread = true, stubName = "PauseJavaProfiling")
     public static void pause() {
         synchronized (GeckoJavaSampler.class) {
             sSamplingRunnable.mPauseSampler = true;
         }
     }
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "UnpauseJavaProfiling")
+    @WrapElementForJNI(allowMultithread = true, stubName = "UnpauseJavaProfiling")
     public static void unpause() {
         synchronized (GeckoJavaSampler.class) {
             sSamplingRunnable.mPauseSampler = false;
         }
     }
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "StopJavaProfiling")
+    @WrapElementForJNI(allowMultithread = true, stubName = "StopJavaProfiling")
     public static void stop() {
         synchronized (GeckoJavaSampler.class) {
             if (sSamplingThread == null) {
                 return;
             }
 
             sSamplingRunnable.mStopSampler = true;
             try {
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -146,17 +146,17 @@ endif
 jni-stubs.inc: gecko-browser.jar gecko-mozglue.jar gecko-util.jar sync-thirdparty.jar
 	$(JAVAH) -o javah.out -bootclasspath $(JAVA_BOOTCLASSPATH) -classpath $(subst $(NULL) $(NULL),:,$^) $(CLASSES_WITH_JNI)
 	$(PYTHON) $(topsrcdir)/mobile/android/base/jni-generator.py javah.out $@
 
 ANNOTATION_PROCESSOR_JAR_FILES := $(DEPTH)/build/annotationProcessors/annotationProcessors.jar
 
 GeneratedJNIWrappers.cpp: $(ANNOTATION_PROCESSOR_JAR_FILES)
 GeneratedJNIWrappers.cpp: $(ALL_JARS)
-	$(JAVA) -classpath $(JAVA_BOOTCLASSPATH):$(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.AnnotationProcessor $(ALL_JARS)
+	$(JAVA) -classpath gecko-mozglue.jar:$(JAVA_BOOTCLASSPATH):$(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.AnnotationProcessor $(ALL_JARS)
 
 gecko_package_dir = generated/org/mozilla/gecko
 # Like generated/org/mozilla/fennec_$USERID.
 android_package_dir = $(addprefix generated/,$(subst .,/,$(ANDROID_PACKAGE_NAME)))
 
 # These _PP_JAVAFILES are specified in moz.build and defined in
 # backend.mk, which is included by config.mk.  Therefore this needs to
 # be defined after config.mk is included.
--- a/mobile/android/base/SurfaceBits.java
+++ b/mobile/android/base/SurfaceBits.java
@@ -1,14 +1,17 @@
 /* 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;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
+
 import java.nio.ByteBuffer;
 
+@WrapEntireClassForJNI
 public class SurfaceBits {
     public int width;
     public int height;
     public int format;
     public ByteBuffer buffer;
 }
--- a/mobile/android/base/ThumbnailHelper.java
+++ b/mobile/android/base/ThumbnailHelper.java
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.IntSize;
 import org.mozilla.gecko.mozglue.DirectBufferAllocator;
-import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 
 import android.graphics.Bitmap;
 import android.util.Log;
 
 import java.nio.ByteBuffer;
 import java.util.LinkedList;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -146,17 +146,17 @@ public final class ThumbnailHelper {
         }
 
         Log.d(LOGTAG, "Sending thumbnail event: " + mWidth + ", " + mHeight);
         GeckoEvent e = GeckoEvent.createThumbnailEvent(tab.getId(), mWidth, mHeight, mBuffer);
         GeckoAppShell.sendEventToGecko(e);
     }
 
     /* This method is invoked by JNI once the thumbnail data is ready. */
-    @GeneratableAndroidBridgeTarget(stubName = "SendThumbnail")
+    @WrapElementForJNI(stubName = "SendThumbnail")
     public static void notifyThumbnail(ByteBuffer data, int tabId, boolean success) {
         Tab tab = Tabs.getInstance().getTab(tabId);
         ThumbnailHelper helper = ThumbnailHelper.getInstance();
         if (success && tab != null) {
             helper.handleThumbnailData(tab, data);
         }
         helper.processNextThumbnail(tab);
     }
--- a/mobile/android/base/db/LocalBrowserDB.java
+++ b/mobile/android/base/db/LocalBrowserDB.java
@@ -397,20 +397,21 @@ public class LocalBrowserDB implements B
                                         Bookmarks.UNFILED_FOLDER_GUID },
                          null);
         } else {
             // Right now, we only support showing folder and bookmark type of
             // entries. We should add support for other types though (bug 737024)
             c = cr.query(mBookmarksUriWithProfile,
                          DEFAULT_BOOKMARK_COLUMNS,
                          Bookmarks.PARENT + " = ? AND " +
-                         "(" + Bookmarks.TYPE + " = ? OR " + Bookmarks.TYPE + " = ?)",
+                         "(" + Bookmarks.TYPE + " = ? OR " +
+                            "(" + Bookmarks.TYPE + " = ? AND " + Bookmarks.URL + " IS NOT NULL))",
                          new String[] { String.valueOf(folderId),
-                                        String.valueOf(Bookmarks.TYPE_BOOKMARK),
-                                        String.valueOf(Bookmarks.TYPE_FOLDER) },
+                                        String.valueOf(Bookmarks.TYPE_FOLDER),
+                                        String.valueOf(Bookmarks.TYPE_BOOKMARK) },
                          null);
         }
 
         if (addDesktopFolder) {
             // Wrap cursor to add fake desktop bookmarks and reading list folders
             c = new SpecialFoldersCursorWrapper(c, addDesktopFolder);
         }
 
--- a/mobile/android/base/gfx/DisplayPortMetrics.java
+++ b/mobile/android/base/gfx/DisplayPortMetrics.java
@@ -1,35 +1,39 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.util.FloatUtils;
 
 import android.graphics.RectF;
 
 /*
  * This class keeps track of the area we request Gecko to paint, as well
  * as the resolution of the paint. The area may be different from the visible
  * area of the page, and the resolution may be different from the resolution
  * used in the compositor to render the page. This is so that we can ask Gecko
  * to paint a much larger area without using extra memory, and then render some
  * subsection of that with compositor scaling.
  */
 public final class DisplayPortMetrics {
+    @WrapElementForJNI
     public final float resolution;
+    @WrapElementForJNI
     private final RectF mPosition;
 
     public DisplayPortMetrics() {
         this(0, 0, 0, 0, 1);
     }
 
+    @WrapElementForJNI
     public DisplayPortMetrics(float left, float top, float right, float bottom, float resolution) {
         this.resolution = resolution;
         mPosition = new RectF(left, top, right, bottom);
     }
 
     public float getLeft() {
         return mPosition.left;
     }
--- a/mobile/android/base/gfx/GLController.java
+++ b/mobile/android/base/gfx/GLController.java
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.GeckoThread;
-import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.util.Log;
 
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.egl.EGLContext;
 import javax.microedition.khronos.egl.EGLDisplay;
@@ -210,17 +210,17 @@ public class GLController {
             if (red[0] == rSize && green[0] == gSize && blue[0] == bSize) {
                 return config;
             }
         }
 
         throw new GLControllerException("No suitable EGL configuration found");
     }
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "CreateEGLSurfaceForCompositorWrapper")
+    @WrapElementForJNI(allowMultithread = true, stubName = "CreateEGLSurfaceForCompositorWrapper")
     private EGLSurface createEGLSurfaceForCompositor() {
         initEGL();
         return mEGL.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mView.getNativeWindow(), null);
     }
 
     private String getEGLError() {
         return "Error " + (mEGL == null ? "(no mEGL)" : mEGL.eglGetError());
     }
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/gfx/GeckoLayerClient.java
@@ -6,16 +6,17 @@
 package org.mozilla.gecko.gfx;
 
 import org.mozilla.gecko.BrowserApp;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.ZoomConstraints;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.FloatUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.Context;
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.os.SystemClock;
@@ -408,48 +409,49 @@ public class GeckoLayerClient implements
             });
 
             setViewportMetrics(newMetrics, type == ViewportMessageType.UPDATE);
             mDisplayPort = DisplayPortCalculator.calculate(getViewportMetrics(), null);
         }
         return mDisplayPort;
     }
 
-    /* This is invoked by JNI on the gecko thread */
+    @WrapElementForJNI
     DisplayPortMetrics getDisplayPort(boolean pageSizeUpdate, boolean isBrowserContentDisplayed, int tabId, ImmutableViewportMetrics metrics) {
         Tabs tabs = Tabs.getInstance();
         if (isBrowserContentDisplayed && tabs.isSelectedTabId(tabId)) {
             // for foreground tabs, send the viewport update unless the document
             // displayed is different from the content document. In that case, just
             // calculate the display port.
             return handleViewportMessage(metrics, pageSizeUpdate ? ViewportMessageType.PAGE_SIZE : ViewportMessageType.UPDATE);
         } else {
             // for background tabs, request a new display port calculation, so that
             // when we do switch to that tab, we have the correct display port and
             // don't need to draw twice (once to allow the first-paint viewport to
             // get to java, and again once java figures out the display port).
             return DisplayPortCalculator.calculate(metrics, null);
         }
     }
 
-    /* This is invoked by JNI on the gecko thread */
+    @WrapElementForJNI
     void contentDocumentChanged() {
         mContentDocumentIsDisplayed = false;
     }
 
-    /* This is invoked by JNI on the gecko thread */
+    @WrapElementForJNI
     boolean isContentDocumentDisplayed() {
         return mContentDocumentIsDisplayed;
     }
 
     // This is called on the Gecko thread to determine if we're still interested
     // in the update of this display-port to continue. We can return true here
     // to abort the current update and continue with any subsequent ones. This
     // is useful for slow-to-render pages when the display-port starts lagging
     // behind enough that continuing to draw it is wasted effort.
+    @WrapElementForJNI(allowMultithread = true)
     public ProgressiveUpdateData progressiveUpdateCallback(boolean aHasPendingNewThebesContent,
                                                            float x, float y, float width, float height,
                                                            float resolution, boolean lowPrecision) {
         // Reset the checkerboard risk flag when switching to low precision
         // rendering.
         if (lowPrecision && !mLastProgressiveUpdateWasLowPrecision) {
             // Skip low precision rendering until we're at risk of checkerboarding.
             if (!mProgressiveUpdateWasInDanger) {
@@ -547,23 +549,23 @@ public class GeckoLayerClient implements
 
     void setIsRTL(boolean aIsRTL) {
         synchronized (getLock()) {
             ImmutableViewportMetrics newMetrics = getViewportMetrics().setIsRTL(aIsRTL);
             setViewportMetrics(newMetrics, false);
         }
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature.
-      * The compositor invokes this function just before compositing a frame where the document
+    /** The compositor invokes this function just before compositing a frame where the document
       * is different from the document composited on the last frame. In these cases, the viewport
       * information we have in Java is no longer valid and needs to be replaced with the new
       * viewport information provided. setPageRect will never be invoked on the same frame that
       * this function is invoked on; and this function will always be called prior to syncViewportInfo.
       */
+    @WrapElementForJNI(allowMultithread = true)
     public void setFirstPaintViewport(float offsetX, float offsetY, float zoom,
             float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) {
         synchronized (getLock()) {
             ImmutableViewportMetrics currentMetrics = getViewportMetrics();
 
             Tab tab = Tabs.getInstance().getSelectedTab();
 
             RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
@@ -606,43 +608,43 @@ public class GeckoLayerClient implements
             }
         }
         DisplayPortCalculator.resetPageState();
         mDrawTimingQueue.reset();
 
         mContentDocumentIsDisplayed = true;
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature.
-      * The compositor invokes this function whenever it determines that the page rect
+    /** The compositor invokes this function whenever it determines that the page rect
       * has changed (based on the information it gets from layout). If setFirstPaintViewport
       * is invoked on a frame, then this function will not be. For any given frame, this
       * function will be invoked before syncViewportInfo.
       */
+    @WrapElementForJNI(allowMultithread = true)
     public void setPageRect(float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) {
         synchronized (getLock()) {
             RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
             float ourZoom = getViewportMetrics().zoomFactor;
             setPageRect(RectUtils.scale(cssPageRect, ourZoom), cssPageRect);
             // Here the page size of the document has changed, but the document being displayed
             // is still the same. Therefore, we don't need to send anything to browser.js; any
             // changes we need to make to the display port will get sent the next time we call
             // adjustViewport().
         }
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature.
-      * The compositor invokes this function on every frame to figure out what part of the
+    /** The compositor invokes this function on every frame to figure out what part of the
       * page to display, and to inform Java of the current display port. Since it is called
       * on every frame, it needs to be ultra-fast.
       * It avoids taking any locks or allocating any objects. We keep around a
       * mCurrentViewTransform so we don't need to allocate a new ViewTransform
       * everytime we're called. NOTE: we might be able to return a ImmutableViewportMetrics
       * which would avoid the copy into mCurrentViewTransform.
       */
+    @WrapElementForJNI(allowMultithread = true)
     public ViewTransform syncViewportInfo(int x, int y, int width, int height, float resolution, boolean layersUpdated) {
         // getViewportMetrics is thread safe so we don't need to synchronize.
         // We save the viewport metrics here, so we later use it later in
         // createFrame (which will be called by nsWindow::DrawWindowUnderlay on
         // the native side, by the compositor). The viewport
         // metrics can change between here and there, as it's accessed outside
         // of the compositor thread.
         mFrameMetrics = getViewportMetrics();
@@ -686,48 +688,48 @@ public class GeckoLayerClient implements
         if (layersUpdated && mDrawListener != null) {
             /* Used by robocop for testing purposes */
             mDrawListener.drawFinished();
         }
 
         return mCurrentViewTransform;
     }
 
-    /* Invoked by JNI from the compositor thread */
+    @WrapElementForJNI(allowMultithread = true)
     public ViewTransform syncFrameMetrics(float offsetX, float offsetY, float zoom,
                 float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom,
                 boolean layersUpdated, int x, int y, int width, int height, float resolution,
                 boolean isFirstPaint)
     {
         if (isFirstPaint) {
             setFirstPaintViewport(offsetX, offsetY, zoom,
                                   cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
         }
 
         return syncViewportInfo(x, y, width, height, resolution, layersUpdated);
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
+    @WrapElementForJNI(allowMultithread = true)
     public LayerRenderer.Frame createFrame() {
         // Create the shaders and textures if necessary.
         if (!mLayerRendererInitialized) {
             mLayerRenderer.checkMonitoringEnabled();
             mLayerRenderer.createDefaultProgram();
             mLayerRendererInitialized = true;
         }
 
         return mLayerRenderer.createFrame(mFrameMetrics);
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
+    @WrapElementForJNI(allowMultithread = true)
     public void activateProgram() {
         mLayerRenderer.activateDefaultProgram();
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
+    @WrapElementForJNI(allowMultithread = true)
     public void deactivateProgram() {
         mLayerRenderer.deactivateDefaultProgram();
     }
 
     private void geometryChanged(DisplayPortMetrics displayPort) {
         /* Let Gecko know if the screensize has changed */
         sendResizeEventIfNecessary(false);
         if (getRedrawHint()) {
--- a/mobile/android/base/gfx/ImmutableViewportMetrics.java
+++ b/mobile/android/base/gfx/ImmutableViewportMetrics.java
@@ -1,15 +1,16 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.util.FloatUtils;
 
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.util.DisplayMetrics;
 
 /**
  * ImmutableViewportMetrics are used to store the viewport metrics
@@ -47,17 +48,18 @@ public class ImmutableViewportMetrics {
         marginLeft = marginTop = marginRight = marginBottom = 0;
         zoomFactor = 1.0f;
         isRTL = false;
     }
 
     /** This constructor is used by native code in AndroidJavaWrappers.cpp, be
      * careful when modifying the signature.
      */
-    private ImmutableViewportMetrics(float aPageRectLeft, float aPageRectTop,
+    @WrapElementForJNI(allowMultithread = true)
+    public ImmutableViewportMetrics(float aPageRectLeft, float aPageRectTop,
         float aPageRectRight, float aPageRectBottom, float aCssPageRectLeft,
         float aCssPageRectTop, float aCssPageRectRight, float aCssPageRectBottom,
         float aViewportRectLeft, float aViewportRectTop, float aViewportRectRight,
         float aViewportRectBottom, float aZoomFactor)
     {
         this(aPageRectLeft, aPageRectTop,
              aPageRectRight, aPageRectBottom, aCssPageRectLeft,
              aCssPageRectTop, aCssPageRectRight, aCssPageRectBottom,
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -14,17 +14,16 @@ import org.mozilla.gecko.gfx.RenderTask;
 import org.mozilla.gecko.mozglue.DirectBufferAllocator;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
-import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.opengl.GLES20;
 import android.os.SystemClock;
 import android.util.Log;
 
 import java.nio.ByteBuffer;
--- a/mobile/android/base/gfx/LayerView.java
+++ b/mobile/android/base/gfx/LayerView.java
@@ -9,17 +9,17 @@ import org.mozilla.gecko.GeckoAccessibil
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.PrefsHelper;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.TouchEventInterceptor;
 import org.mozilla.gecko.ZoomConstraints;
-import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.util.EventDispatcher;
 
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.PixelFormat;
@@ -557,17 +557,17 @@ public class LayerView extends FrameLayo
 
     public Object getNativeWindow() {
         if (mSurfaceView != null)
             return mSurfaceView.getHolder();
 
         return mTextureView.getSurfaceTexture();
     }
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "RegisterCompositorWrapper")
+    @WrapElementForJNI(allowMultithread = true, stubName = "RegisterCompositorWrapper")
     public static GLController registerCxxCompositor() {
         try {
             LayerView layerView = GeckoAppShell.getLayerView();
             GLController controller = layerView.getGLController();
             controller.compositorCreated();
             return controller;
         } catch (Exception e) {
             Log.e(LOGTAG, "Error registering compositor!", e);
--- a/mobile/android/base/gfx/NativePanZoomController.java
+++ b/mobile/android/base/gfx/NativePanZoomController.java
@@ -2,17 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.GeckoThread;
-import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.GeckoEventListener;
 
 import org.json.JSONObject;
 
 import android.graphics.PointF;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -78,22 +78,22 @@ class NativePanZoomController implements
     private native long runDelayedCallback();
 
     public native void destroy();
     public native void notifyDefaultActionPrevented(boolean prevented);
     public native boolean getRedrawHint();
     public native void setOverScrollMode(int overscrollMode);
     public native int getOverScrollMode();
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "RequestContentRepaintWrapper")
+    @WrapElementForJNI(allowMultithread = true, stubName = "RequestContentRepaintWrapper")
     private void requestContentRepaint(float x, float y, float width, float height, float resolution) {
         mTarget.forceRedraw(new DisplayPortMetrics(x, y, x + width, y + height, resolution));
     }
 
-    @GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "PostDelayedCallbackWrapper")
+    @WrapElementForJNI(allowMultithread = true, stubName = "PostDelayedCallbackWrapper")
     private void postDelayedCallback(long delay) {
         mTarget.postDelayed(mCallbackRunnable, delay);
     }
 
     class CallbackRunnable implements Runnable {
         @Override
         public void run() {
             long nextDelay = runDelayedCallback();
--- a/mobile/android/base/gfx/ProgressiveUpdateData.java
+++ b/mobile/android/base/gfx/ProgressiveUpdateData.java
@@ -1,21 +1,24 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
+
 /**
  * This is the data structure that's returned by the progressive tile update
  * callback function. It encompasses the current viewport and a boolean value
  * representing whether the front-end is interested in the current progressive
  * update continuing.
  */
+@WrapEntireClassForJNI
 public class ProgressiveUpdateData {
     public float x;
     public float y;
     public float width;
     public float height;
     public float scale;
     public boolean abort;
 
--- a/mobile/android/base/gfx/ViewTransform.java
+++ b/mobile/android/base/gfx/ViewTransform.java
@@ -1,15 +1,18 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
+
+@WrapEntireClassForJNI
 public class ViewTransform {
     public float x;
     public float y;
     public float scale;
     public float fixedLayerMarginLeft;
     public float fixedLayerMarginTop;
     public float fixedLayerMarginRight;
     public float fixedLayerMarginBottom;
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -9,20 +9,22 @@ DIRS += ['locales']
 include('android-services.mozbuild')
 
 thirdparty_source_dir = TOPSRCDIR + '/mobile/android/thirdparty/'
 
 mgjar = add_java_jar('gecko-mozglue')
 mgjar.sources += [
     'mozglue/ByteBufferInputStream.java',
     'mozglue/DirectBufferAllocator.java',
-    'mozglue/GeneratableAndroidBridgeTarget.java',
+    'mozglue/generatorannotations/GeneratorOptions.java',
+    'mozglue/generatorannotations/OptionalGeneratedParameter.java',
+    'mozglue/generatorannotations/WrapElementForJNI.java',
+    'mozglue/generatorannotations/WrapEntireClassForJNI.java',
     'mozglue/NativeReference.java',
     'mozglue/NativeZip.java',
-    'mozglue/OptionalGeneratedParameter.java',
 ]
 mgjar.generated_sources += [
     'org/mozilla/gecko/mozglue/GeckoLoader.java',
 ]
 mgjar.javac_flags += ['-Xlint:all']
 
 wsjar = add_java_jar('websockets')
 wsjar.sources += [ thirdparty_source_dir + f for f in [
--- a/mobile/android/base/mozglue/NativeZip.java
+++ b/mobile/android/base/mozglue/NativeZip.java
@@ -1,15 +1,17 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.mozglue;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
+
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.util.zip.Inflater;
 import java.util.zip.InflaterInputStream;
 
 public class NativeZip implements NativeReference {
     private static final int DEFLATE = 8;
     private static final int STORE = 0;
@@ -63,16 +65,17 @@ public class NativeZip implements Native
         return _getInputStream(mObj, path);
     }
 
     private static native long getZip(String path);
     private static native long getZipFromByteBuffer(ByteBuffer buffer);
     private static native void _release(long obj);
     private native InputStream _getInputStream(long obj, String path);
 
+    @WrapElementForJNI
     private InputStream createInputStream(ByteBuffer buffer, int compression) {
         if (compression != STORE && compression != DEFLATE) {
             throw new IllegalArgumentException("Unexpected compression: " + compression);
         }
 
         InputStream input = new ByteBufferInputStream(buffer, this);
         if (compression == DEFLATE) {
             Inflater inflater = new Inflater(true);
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/mozglue/generatorannotations/GeneratorOptions.java
@@ -0,0 +1,14 @@
+/* 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.mozglue.generatorannotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface GeneratorOptions {
+    // Specifies a custom name for the generated C++ class. If left empty, is AndroidJavaClassName.
+    String generatedClassName() default "";
+}
\ No newline at end of file
rename from mobile/android/base/mozglue/OptionalGeneratedParameter.java
rename to mobile/android/base/mozglue/generatorannotations/OptionalGeneratedParameter.java
--- a/mobile/android/base/mozglue/OptionalGeneratedParameter.java
+++ b/mobile/android/base/mozglue/generatorannotations/OptionalGeneratedParameter.java
@@ -1,13 +1,13 @@
 /* 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.mozglue;
+package org.mozilla.gecko.mozglue.generatorannotations;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
  * Used to annotate parameters which are optional on the C++ side of the bridge. The annotation is
  * used by the annotation processor to generate the appropriate C++ headers so calls into the Java
  * method all have the optional params set to the default value.
rename from mobile/android/base/mozglue/GeneratableAndroidBridgeTarget.java
rename to mobile/android/base/mozglue/generatorannotations/WrapElementForJNI.java
--- a/mobile/android/base/mozglue/GeneratableAndroidBridgeTarget.java
+++ b/mobile/android/base/mozglue/generatorannotations/WrapElementForJNI.java
@@ -1,13 +1,13 @@
 /* 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.mozglue;
+package org.mozilla.gecko.mozglue.generatorannotations;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
  * This annotation is used to tag methods that are to have wrapper methods generated in the android
  * bridge. Such methods will be protected from destruction by Proguard, and allow us to avoid writing
  * by hand large amounts of boring boilerplate.
@@ -16,17 +16,17 @@ import java.lang.annotation.RetentionPol
  * the first letter in upper case. The stubName property may be used to specify a custom name for the
  * generated method stub.
  *
  * allowMultithreaded should be used as sparingly as possible - the resulting code will allow the
  * Java method to be invoked from the C side from multiple threads. Often, this isn't what is wanted
  * and may lead to subtle bugs.
  */
 @Retention(RetentionPolicy.RUNTIME)
-public @interface GeneratableAndroidBridgeTarget {
+public @interface WrapElementForJNI {
     // Optional parameter specifying the name of the generated method stub. If omitted, the name
     // of the Java method will be used.
     String stubName() default "";
 
     // Optional parameter specifying if the generated method should be a static member of AndroidBridge
     // By default, an instance member is produced. This is almost always what is wanted.
     boolean generateStatic() default false;
 
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/mozglue/generatorannotations/WrapEntireClassForJNI.java
@@ -0,0 +1,15 @@
+/* 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.mozglue.generatorannotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Handy shortcut annotation. Functionally equivalent to tagging every member individually with default
+ * settings.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface WrapEntireClassForJNI {}
--- a/mobile/android/base/sqlite/MatrixBlobCursor.java
+++ b/mobile/android/base/sqlite/MatrixBlobCursor.java
@@ -12,16 +12,18 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package org.mozilla.gecko.sqlite;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
+
 import android.database.AbstractCursor;
 import android.database.CursorIndexOutOfBoundsException;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 
 /*
  * Android's AbstractCursor throws on getBlob()
@@ -45,16 +47,17 @@ public class MatrixBlobCursor extends Ab
 
     /**
      * Constructs a new cursor with the given initial capacity.
      *
      * @param columnNames names of the columns, the ordering of which
      *  determines column ordering elsewhere in this cursor
      * @param initialCapacity in rows
      */
+    @WrapElementForJNI
     public MatrixBlobCursor(String[] columnNames, int initialCapacity) {
         this.columnNames = columnNames;
         this.columnCount = columnNames.length;
 
         if (initialCapacity < 1) {
             initialCapacity = 1;
         }
 
@@ -62,16 +65,17 @@ public class MatrixBlobCursor extends Ab
     }
 
     /**
      * Constructs a new cursor.
      *
      * @param columnNames names of the columns, the ordering of which
      *  determines column ordering elsewhere in this cursor
      */
+    @WrapElementForJNI
     public MatrixBlobCursor(String[] columnNames) {
         this(columnNames, 16);
     }
 
     /**
      * Gets value at the given column for the current row.
      */
     protected Object get(int column) {
@@ -107,16 +111,17 @@ public class MatrixBlobCursor extends Ab
      * Adds a new row to the end with the given column values. Not safe
      * for concurrent use.
      *
      * @throws IllegalArgumentException if {@code columnValues.length !=
      *  columnNames.length}
      * @param columnValues in the same order as the the column names specified
      *  at cursor construction time
      */
+    @WrapElementForJNI
     public void addRow(Object[] columnValues) {
         if (columnValues.length != columnCount) {
             throw new IllegalArgumentException("columnNames.length = "
                     + columnCount + ", columnValues.length = "
                     + columnValues.length);
         }
 
         int start = rowCount++ * columnCount;
@@ -128,16 +133,17 @@ public class MatrixBlobCursor extends Ab
      * Adds a new row to the end with the given column values. Not safe
      * for concurrent use.
      *
      * @throws IllegalArgumentException if {@code columnValues.size() !=
      *  columnNames.length}
      * @param columnValues in the same order as the the column names specified
      *  at cursor construction time
      */
+    @WrapElementForJNI
     public void addRow(Iterable<?> columnValues) {
         int start = rowCount * columnCount;
         int end = start + columnCount;
         ensureCapacity(end);
 
         if (columnValues instanceof ArrayList<?>) {
             addRow((ArrayList<?>) columnValues, start);
             return;
@@ -160,16 +166,17 @@ public class MatrixBlobCursor extends Ab
                     "columnValues.size() < columnNames.length");
         }
 
         // Increase row count here in case we encounter an exception.
         rowCount++;
     }
 
     /** Optimization for {@link ArrayList}. */
+    @WrapElementForJNI
     private void addRow(ArrayList<?> columnValues, int start) {
         int size = columnValues.size();
         if (size != columnCount) {
             throw new IllegalArgumentException("columnNames.length = "
                     + columnCount + ", columnValues.size() = " + size);
         }
 
         rowCount++;
--- a/mobile/android/base/sqlite/SQLiteBridgeException.java
+++ b/mobile/android/base/sqlite/SQLiteBridgeException.java
@@ -1,15 +1,18 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sqlite;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
+
+@WrapEntireClassForJNI
 public class SQLiteBridgeException extends RuntimeException {
     static final long serialVersionUID = 1L;
 
     public SQLiteBridgeException() {}
     public SQLiteBridgeException(String msg) {
         super(msg);
     }
 }
--- a/mobile/android/base/util/Clipboard.java
+++ b/mobile/android/base/util/Clipboard.java
@@ -4,17 +4,17 @@
 
 package org.mozilla.gecko.util;
 
 import android.content.ClipData;
 import android.content.Context;
 import android.os.Build;
 import android.util.Log;
 
-import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 
 import java.util.concurrent.SynchronousQueue;
 
 public final class Clipboard {
     private static Context mContext;
     private final static String LOG_TAG = "Clipboard";
     private final static SynchronousQueue<String> sClipboardQueue = new SynchronousQueue<String>();
 
@@ -24,17 +24,17 @@ public final class Clipboard {
     public static void init(Context c) {
         if (mContext != null) {
             Log.w(LOG_TAG, "Clipboard.init() called twice!");
             return;
         }
         mContext = c;
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "GetClipboardTextWrapper")
+    @WrapElementForJNI(stubName = "GetClipboardTextWrapper")
     public static String getText() {
         // If we're on the UI thread or the background thread, we have a looper on the thread
         // and can just call this directly. For any other threads, post the call to the
         // background thread.
 
         if (ThreadUtils.isOnUiThread() || ThreadUtils.isOnBackgroundThread()) {
             return getClipboardTextImpl();
         }
@@ -50,17 +50,17 @@ public final class Clipboard {
         });
         try {
             return sClipboardQueue.take();
         } catch (InterruptedException ie) {
             return "";
         }
     }
 
-    @GeneratableAndroidBridgeTarget(stubName = "SetClipboardText")
+    @WrapElementForJNI(stubName = "SetClipboardText")
     public static void setText(final CharSequence text) {
         ThreadUtils.postToBackgroundThread(new Runnable() {
             @Override
             @SuppressWarnings("deprecation")
             public void run() {
                 if (Build.VERSION.SDK_INT >= 11) {
                     android.content.ClipboardManager cm = getClipboardManager11(mContext);
                     ClipData clip = ClipData.newPlainText("Text", text);
@@ -74,16 +74,35 @@ public final class Clipboard {
                 } else {
                     android.text.ClipboardManager cm = getClipboardManager(mContext);
                     cm.setText(text);
                 }
             }
         });
     }
 
+    /**
+     * Returns true if the clipboard is nonempty, false otherwise.
+     *
+     * @return true if the clipboard is nonempty, false otherwise.
+     */
+    @WrapElementForJNI
+    public static boolean hasText() {
+        String text = getText();
+        return text != null;
+    }
+
+    /**
+     * Deletes all text from the clipboard.
+     */
+    @WrapElementForJNI
+    public static void clearText() {
+        setText(null);
+    }
+
     private static android.content.ClipboardManager getClipboardManager11(Context context) {
         // In API Level 11 and above, CLIPBOARD_SERVICE returns android.content.ClipboardManager,
         // which is a subclass of android.text.ClipboardManager.
         return (android.content.ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
     }
 
     private static android.text.ClipboardManager getClipboardManager(Context context) {
         return (android.text.ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
--- a/mobile/android/components/build/nsAndroidHistory.cpp
+++ b/mobile/android/components/build/nsAndroidHistory.cpp
@@ -45,20 +45,17 @@ nsAndroidHistory::RegisterVisitedCallbac
 
   nsTArray<Link*>* list = mListeners.Get(uriString);
   if (! list) {
     list = new nsTArray<Link*>();
     mListeners.Put(uriString, list);
   }
   list->AppendElement(aContent);
 
-  AndroidBridge *bridge = AndroidBridge::Bridge();
-  if (bridge) {
-    bridge->CheckURIVisited(uriString);
-  }
+ GeckoAppShell::CheckURIVisited(uriString);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidHistory::UnregisterVisitedCallback(nsIURI *aURI, Link *aContent)
 {
   if (!aContent || !aURI)
@@ -91,37 +88,33 @@ nsAndroidHistory::VisitURI(nsIURI *aURI,
     return NS_OK;
 
   if (aFlags & VisitFlags::REDIRECT_SOURCE)
     return NS_OK;
 
   if (aFlags & VisitFlags::UNRECOVERABLE_ERROR)
     return NS_OK;
 
-  AndroidBridge *bridge = AndroidBridge::Bridge();
-  if (bridge) {
-    nsAutoCString uri;
-    nsresult rv = aURI->GetSpec(uri);
-    if (NS_FAILED(rv)) return rv;
-    NS_ConvertUTF8toUTF16 uriString(uri);
-    bridge->MarkURIVisited(uriString);
-  }
+  nsAutoCString uri;
+  nsresult rv = aURI->GetSpec(uri);
+  if (NS_FAILED(rv)) return rv;
+  NS_ConvertUTF8toUTF16 uriString(uri);
+  GeckoAppShell::MarkURIVisited(uriString);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidHistory::SetURITitle(nsIURI *aURI, const nsAString& aTitle)
 {
-  AndroidBridge *bridge = AndroidBridge::Bridge();
-  if (bridge) {
+  if (AndroidBridge::Bridge()) {
     nsAutoCString uri;
     nsresult rv = aURI->GetSpec(uri);
     if (NS_FAILED(rv)) return rv;
     NS_ConvertUTF8toUTF16 uriString(uri);
-    bridge->SetURITitle(uriString, aTitle);
+    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,25 +3,27 @@
  * 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;
+
 NS_IMPL_ISUPPORTS1(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::AndroidBridge::Bridge()->CreateShortcut(aTitle, aURI, aIconData, aIntent);
+  GeckoAppShell::CreateShortcut(aTitle, aURI, aIconData, aIntent);
   return NS_OK;
 }
--- a/netwerk/base/src/Tickler.cpp
+++ b/netwerk/base/src/Tickler.cpp
@@ -75,17 +75,17 @@ nsresult
 Tickler::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mTimer);
   MOZ_ASSERT(!mActive);
   MOZ_ASSERT(!mThread);
   MOZ_ASSERT(!mFD);
 
-  AndroidBridge::Bridge()->EnableNetworkNotifications();
+  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.
   PRSocketOptionData opt;
--- 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() {
-    AndroidBridge::Bridge()->CloseCamera();
+    GeckoAppShell::CloseCamera();
     mCallback = nullptr;
 }
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/system/android/nsAndroidNetworkLinkService.cpp
+++ b/netwerk/system/android/nsAndroidNetworkLinkService.cpp
@@ -5,16 +5,18 @@
  * 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_ISUPPORTS1(nsAndroidNetworkLinkService,
                    nsINetworkLinkService)
 
 nsAndroidNetworkLinkService::nsAndroidNetworkLinkService()
 {
 }
 
 nsAndroidNetworkLinkService::~nsAndroidNetworkLinkService()
@@ -26,36 +28,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::AndroidBridge::Bridge()->IsNetworkLinkUp();
+  *aIsUp = GeckoAppShell::IsNetworkLinkUp();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidNetworkLinkService::GetLinkStatusKnown(bool *aIsKnown)
 {
   NS_ENSURE_TRUE(mozilla::AndroidBridge::Bridge(), NS_ERROR_NOT_IMPLEMENTED);
 
-  *aIsKnown = mozilla::AndroidBridge::Bridge()->IsNetworkLinkKnown();
+  *aIsKnown = 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::AndroidBridge::Bridge()->NetworkLinkType();
+  *aLinkType = GeckoAppShell::NetworkLinkType();
   return NS_OK;
 }
--- a/toolkit/components/alerts/nsAlertsService.cpp
+++ b/toolkit/components/alerts/nsAlertsService.cpp
@@ -6,16 +6,17 @@
 #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"
 
@@ -122,17 +123,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::AndroidBridge::Bridge()->CloseNotification(aAlertName);
+  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);
   }
@@ -143,24 +144,24 @@ 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::AndroidBridge::Bridge()->AlertsProgressListener_OnProgress(aAlertName, aProgress, aProgressMax, aAlertText);
+  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::AndroidBridge::Bridge()->CloseNotification(aAlertName);
+  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
@@ -47,16 +47,17 @@
 #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;
@@ -2792,17 +2793,17 @@ nsDownload::SetState(DownloadState aStat
 #ifdef MOZ_WIDGET_ANDROID
         nsCOMPtr<nsIMIMEInfo> mimeInfo;
         nsAutoCString contentType;
         GetMIMEInfo(getter_AddRefs(mimeInfo));
 
         if (mimeInfo)
           mimeInfo->GetMIMEType(contentType);
 
-        mozilla::AndroidBridge::Bridge()->ScanMedia(path, NS_ConvertUTF8toUTF16(contentType));
+        GeckoAppShell::ScanMedia(path, NS_ConvertUTF8toUTF16(contentType));
 #endif
       }
 
 #ifdef XP_WIN
       // Adjust file attributes so that by default, new files are indexed
       // by desktop search services. Skip off those that land in the temp
       // folder.
       nsCOMPtr<nsIFile> tempDir, fileDir;
--- a/toolkit/components/jsdownloads/src/DownloadPlatform.cpp
+++ b/toolkit/components/jsdownloads/src/DownloadPlatform.cpp
@@ -113,17 +113,17 @@ nsresult DownloadPlatform::DownloadDone(
                                              kCFStringEncodingUTF8);
     CFNotificationCenterRef center = ::CFNotificationCenterGetDistributedCenter();
     ::CFNotificationCenterPostNotification(center, CFSTR("com.apple.DownloadFileFinished"),
                                            observedObject, nullptr, TRUE);
     ::CFRelease(observedObject);
 #endif
 #ifdef MOZ_WIDGET_ANDROID
     if (!aContentType.IsEmpty()) {
-      mozilla::AndroidBridge::Bridge()->ScanMedia(path, NS_ConvertUTF8toUTF16(aContentType));
+      mozilla::widget::android::GeckoAppShell::ScanMedia(path, NS_ConvertUTF8toUTF16(aContentType));
     }
 #endif
   }
 
 #ifdef XP_WIN
   // Adjust file attributes so that by default, new files are indexed by
   // desktop search services. Skip off those that land in the temp folder.
   nsCOMPtr<nsIFile> tempDir, fileDir;
--- a/toolkit/devtools/output-parser.js
+++ b/toolkit/devtools/output-parser.js
@@ -108,16 +108,17 @@ OutputParser.prototype = {
    *         Text to parse.
    * @param  {Object} [options]
    *         Options object. For valid options and default values see
    *         _mergeOptions().
    * @return {DocumentFragment}
    *         A document fragment. Colors will not be parsed.
    */
   parseHTMLAttribute: function(value, options={}) {
+    options.isHTMLAttribute = true;
     options = this._mergeOptions(options);
 
     return this._parse(value, options);
   },
 
   /**
    * Parse a string.
    *
@@ -127,91 +128,141 @@ OutputParser.prototype = {
    *         Options object. For valid options and default values see
    *         _mergeOptions().
    * @return {DocumentFragment}
    *         A document fragment.
    */
   _parse: function(text, options={}) {
     text = text.trim();
     this.parsed.length = 0;
-    let dirty = false;
-    let matched = null;
     let i = 0;
 
-    let trimMatchFromStart = function(match) {
-      text = text.substr(match.length);
-      dirty = true;
-      matched = null;
-    };
+    while (text.length > 0) {
+      let matched = null;
 
-    while (text.length > 0) {
+      // Prevent this loop from slowing down the browser with too
+      // many nodes being appended into output. In practice it is very unlikely
+      // that this will ever happen.
+      i++;
+      if (i > MAX_ITERATIONS) {
+        this._appendTextNode(text);
+        text = "";
+        break;
+      }
+
       matched = text.match(REGEX_QUOTES);
       if (matched) {
         let match = matched[0];
-        trimMatchFromStart(match);
+
+        text = this._trimMatchFromStart(text, match);
         this._appendTextNode(match);
+        continue;
       }
 
       matched = text.match(REGEX_WHITESPACE);
       if (matched) {
         let match = matched[0];
-        trimMatchFromStart(match);
+
+        text = this._trimMatchFromStart(text, match);
         this._appendTextNode(match);
+        continue;
       }
 
       matched = text.match(REGEX_URL);
       if (matched) {
         let [match, url] = matched;
-        trimMatchFromStart(match);
+
+        text = this._trimMatchFromStart(text, match);
         this._appendURL(match, url, options);
+        continue;
       }
 
       matched = text.match(REGEX_ALL_CSS_PROPERTIES);
       if (matched) {
         let [match] = matched;
-        trimMatchFromStart(match);
+
+        text = this._trimMatchFromStart(text, match);
         this._appendTextNode(match);
 
-        dirty = true;
+        if (options.isHTMLAttribute) {
+          [text] = this._appendColorOnMatch(text, options);
+        }
+        continue;
       }
 
-      matched = text.match(REGEX_ALL_COLORS);
-      if (matched) {
-        let match = matched[0];
-        if (this._appendColor(match, options)) {
-          trimMatchFromStart(match);
+      if (!options.isHTMLAttribute) {
+        let dirty;
+
+        [text, dirty] = this._appendColorOnMatch(text, options);
+
+        if (dirty) {
+          continue;
         }
       }
 
-      if (!dirty) {
-        // This test must always be last as it indicates use of an unknown
-        // character that needs to be removed to prevent infinite loops.
-        matched = text.match(REGEX_FIRST_WORD_OR_CHAR);
-        if (matched) {
-          let match = matched[0];
-          trimMatchFromStart(match);
-          this._appendTextNode(match);
-        }
-      }
+      // This test must always be last as it indicates use of an unknown
+      // character that needs to be removed to prevent infinite loops.
+      matched = text.match(REGEX_FIRST_WORD_OR_CHAR);
+      if (matched) {
+        let match = matched[0];
 
-      dirty = false;
-
-      // Prevent this loop from slowing down the browser with too
-      // many nodes being appended into output.
-      i++;
-      if (i > MAX_ITERATIONS) {
-        trimMatchFromStart(text);
-        this._appendTextNode(text);
+        text = this._trimMatchFromStart(text, match);
+        this._appendTextNode(match);
       }
     }
 
     return this._toDOM();
   },
 
   /**
+   * Convenience function to make the parser a little more readable.
+   *
+   * @param  {String} text
+   *         Main text
+   * @param  {String} match
+   *         Text to remove from the beginning
+   *
+   * @return {String}
+   *         The string passed as 'text' with 'match' stripped from the start.
+   */
+  _trimMatchFromStart: function(text, match) {
+    return text.substr(match.length);
+  },
+
+  /**
+   * Check if there is a color match and append it if it is valid.
+   *
+   * @param  {String} text
+   *         Main text
+   * @param  {Object} options
+   *         Options object. For valid options and default values see
+   *         _mergeOptions().
+   *
+   * @return {Array}
+   *         An array containing the remaining text and a dirty flag. This array
+   *         is designed for deconstruction using [text, dirty].
+   */
+  _appendColorOnMatch: function(text, options) {
+    let dirty;
+    let matched = text.match(REGEX_ALL_COLORS);
+
+    if (matched) {
+      let match = matched[0];
+      if (this._appendColor(match, options)) {
+        text = this._trimMatchFromStart(text, match);
+        dirty = true;
+      }
+    } else {
+      dirty = false;
+    }
+
+    return [text, dirty];
+  },
+
+  /**
    * Check if a CSS property supports a specific value.
    *
    * @param  {String} name
    *         CSS Property name to check
    * @param  {String} value
    *         CSS Property value to check
    */
   _cssPropertySupportsValue: function(name, value) {
@@ -327,17 +378,17 @@ OutputParser.prototype = {
    * node then we append the text to that node.
    *
    * @param  {String} text
    *         Text to append
    */
   _appendTextNode: function(text) {
     let lastItem = this.parsed[this.parsed.length - 1];
     if (typeof lastItem === "string") {
-      this.parsed[this.parsed.length - 1] = lastItem + text
+      this.parsed[this.parsed.length - 1] = lastItem + text;
     } else {
       this.parsed.push(text);
     }
   },
 
   /**
    * Take all output and append it into a single DocumentFragment.
    *
@@ -366,26 +417,34 @@ OutputParser.prototype = {
    *
    * @param  {Object} overrides
    *         The option values to override e.g. _mergeOptions({colors: false})
    *
    *         Valid options are:
    *           - defaultColorType: true // Convert colors to the default type
    *                                    // selected in the options panel.
    *           - colorSwatchClass: ""   // The class to use for color swatches.
+   *           - isHTMLAttribute: false // This property indicates whether we
+   *                                    // are parsing an HTML attribute value.
+   *                                    // When the value is passed in from an
+   *                                    // HTML attribute we need to check that
+   *                                    // any CSS property values are supported
+   *                                    // by the property name before
+   *                                    // processing the property value.
    *           - urlClass: ""           // The class to be used for url() links.
    *           - baseURI: ""            // A string or nsIURI used to resolve
    *                                    // relative links.
    * @return {Object}
    *         Overridden options object
    */
   _mergeOptions: function(overrides) {
     let defaults = {
       defaultColorType: true,
       colorSwatchClass: "",
+      isHTMLAttribute: false,
       urlClass: "",
       baseURI: ""
     };
 
     if (typeof overrides.baseURI === "string") {
       overrides.baseURI = Services.io.newURI(overrides.baseURI, null, null);
     }
 
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -3303,17 +3303,17 @@ var XPIProvider = {
       // All the remaining add-ons in this install location must be new.
 
       // Get the migration data for this install location.
       let locMigrateData = {};
       if (XPIDatabase.migrateData && installLocation.name in XPIDatabase.migrateData)
         locMigrateData = XPIDatabase.migrateData[installLocation.name];
       for (let id in addonStates) {
         changed = addMetadata(installLocation, id, addonStates[id],
-                              locMigrateData[id]) || changed;
+                              locMigrateData[id] || null) || changed;
       }
     }
 
     // The remaining locations that had add-ons installed in them no longer
     // have any add-ons installed in them, or the locations no longer exist.
     // The metadata for the add-ons that were in them must be removed from the
     // database.
     for (let location of knownLocations) {
@@ -6918,17 +6918,17 @@ DirectoryInstallLocation.prototype = {
     let dir = this.getStagingDir();
 
     for (let name of aLeafNames) {
       let file = dir.clone();
       file.append(name);
       recursiveRemove(file);
     }
 
-    if (this.stagingDirLock > 0)
+    if (this._stagingDirLock > 0)
       return;
 
     let dirEntries = dir.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
     try {
       if (dirEntries.nextFile)
         return;
     }
     finally {
--- 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::AndroidBridge::Bridge()->NotifyXreExit();
+    mozilla::widget::android::GeckoAppShell::NotifyXreExit();
 
     free(targs[0]);
     nsMemory::Free(data);
     return;
 }
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1644,17 +1644,17 @@ static nsresult LaunchChild(nsINativeApp
     gRestartArgc = 1;
     gRestartArgv[gRestartArgc] = nullptr;
 #endif
   }
 
   SaveToEnv("MOZ_LAUNCHED_CHILD=1");
 
 #if defined(MOZ_WIDGET_ANDROID)
-  mozilla::AndroidBridge::Bridge()->ScheduleRestart();
+  mozilla::widget::android::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;
@@ -1756,17 +1756,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::AndroidBridge::Bridge()->KillAnyZombies();
+      mozilla::widget::android::GeckoAppShell::KillAnyZombies();
       button = 1;
 #else
       const uint32_t flags =
         (nsIPromptService::BUTTON_TITLE_CANCEL * 
          nsIPromptService::BUTTON_POS_0) +
         (nsIPromptService::BUTTON_TITLE_IS_STRING * 
          nsIPromptService::BUTTON_POS_1) +
         nsIPromptService::BUTTON_POS_1_DEFAULT;
@@ -1783,17 +1783,17 @@ ProfileLockedDialog(nsIFile* aProfileDir
         if (NS_FAILED(rv)) 
           return rv;
 
         return NS_LockProfilePath(aProfileDir, aProfileLocalDir, 
                                   nullptr, aResult);
       }
     } else {
 #ifdef MOZ_WIDGET_ANDROID
-      if (mozilla::AndroidBridge::Bridge()->UnlockProfile()) {
+      if (mozilla::widget::android::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
@@ -225,17 +225,17 @@ typename Builder::Object BuildJavaThread
         break;
       }
       if (!sample) {
         sample = b.CreateObject();
         frames = b.CreateArray();
         b.DefineProperty(sample, "frames", frames);
         b.ArrayPush(samples, sample);
 
-        double sampleTime = AndroidBridge::Bridge()->GetSampleTimeJavaProfiling(0, sampleId);
+        double sampleTime = GeckoJavaSampler::GetSampleTimeJavaProfiling(0, sampleId);
         b.DefineProperty(sample, "time", sampleTime);
       }
       typename Builder::RootedObject frame(b.context(), b.CreateObject());
       b.DefineProperty(frame, "location", result.BeginReading());
       b.ArrayPush(frames, frame);
       frameId++;
     }
     if (frameId == 0) {
@@ -277,22 +277,22 @@ void TableTicker::BuildJSObject(Builder&
       typename Builder::RootedObject threadSamples(b.context(), b.CreateObject());
       sRegisteredThreads->at(i)->Profile()->BuildJSObject(b, threadSamples);
       b.ArrayPush(threads, threadSamples);
     }
   }
 
 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   if (ProfileJava()) {
-    AndroidBridge::Bridge()->PauseJavaProfiling();
+    GeckoJavaSampler::PauseJavaProfiling();
 
     typename Builder::RootedObject javaThread(b.context(), BuildJavaThreadJSObject(b));
     b.ArrayPush(threads, javaThread);
 
-    AndroidBridge::Bridge()->UnpauseJavaProfiling();
+    GeckoJavaSampler::UnpauseJavaProfiling();
   }
 #endif
 
   SetPaused(false);
 
   // Send a event asking any subprocesses (plugins) to
   // give us their information
   SubprocessClosure<Builder> closure(&b, threads);
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -23,16 +23,17 @@
 #include "nsDirectoryServiceDefs.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
@@ -670,17 +671,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::AndroidBridge::Bridge()->StartJavaProfiling(javaInterval, 1000);
+    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,16 +1,18 @@
 /* -*- 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;
+
 
 NS_IMPL_ISUPPORTS2(nsAndroidHandlerApp, nsIHandlerApp, nsISharingHandlerApp)
 
 nsAndroidHandlerApp::nsAndroidHandlerApp(const nsAString& aName,
                                          const nsAString& aDescription,
                                          const nsAString& aPackageName,
                                          const nsAString& aClassName,
                                          const nsACString& aMimeType,
@@ -60,29 +62,21 @@ nsAndroidHandlerApp::Equals(nsIHandlerAp
   *aRetval = aApp && aApp->mName.Equals(mName) &&
     aApp->mDescription.Equals(mDescription);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidHandlerApp::LaunchWithURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext)
 {
-  if (!mozilla::AndroidBridge::Bridge())
-    return NS_ERROR_FAILURE;
-
   nsCString uriSpec;
   aURI->GetSpec(uriSpec);
-  return mozilla::AndroidBridge::Bridge()->
-    OpenUriExternal(NS_ConvertUTF8toUTF16(uriSpec), NS_ConvertUTF8toUTF16(mMimeType), mPackageName, mClassName, mAction) ? 
+  return GeckoAppShell::OpenUriExternal(NS_ConvertUTF8toUTF16(uriSpec), NS_ConvertUTF8toUTF16(mMimeType), mPackageName, mClassName, mAction) ? 
     NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsAndroidHandlerApp::Share(const nsAString & data, const nsAString & title)
 {
-  if (!mozilla::AndroidBridge::Bridge())
-    return NS_ERROR_FAILURE;
-
-  return mozilla::AndroidBridge::Bridge()->
-    OpenUriExternal(data, NS_ConvertUTF8toUTF16(mMimeType), mPackageName, 
+  return GeckoAppShell::OpenUriExternal(data, NS_ConvertUTF8toUTF16(mMimeType), mPackageName, 
                     mClassName, mAction) ? NS_OK : NS_ERROR_FAILURE;
 }
 
--- a/uriloader/exthandler/android/nsExternalSharingAppService.cpp
+++ b/uriloader/exthandler/android/nsExternalSharingAppService.cpp
@@ -26,22 +26,17 @@ 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();
-  if (AndroidBridge::Bridge())
-    return AndroidBridge::Bridge()->
-      OpenUriExternal(data, mime,
-                      emptyString,emptyString, sendAction, title) ? NS_OK : NS_ERROR_FAILURE;
-
-  return NS_ERROR_FAILURE;
+  return 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,16 +5,18 @@
 #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;
+
 NS_IMPL_ISUPPORTS2(nsMIMEInfoAndroid, nsIMIMEInfo, nsIHandlerInfo)
 
 NS_IMETHODIMP
 nsMIMEInfoAndroid::LaunchDefaultWithFile(nsIFile* aFile)
 {
   LaunchWithFile(aFile);
   return NS_OK;
 }
@@ -23,21 +25,17 @@ NS_IMETHODIMP
 nsMIMEInfoAndroid::LoadUriInternal(nsIURI * aURI)
 {
   nsCString uriSpec;
   aURI->GetSpec(uriSpec);
 
   nsCString uriScheme;
   aURI->GetScheme(uriScheme);
 
-  if (mozilla::AndroidBridge::Bridge())
-    return mozilla::AndroidBridge::Bridge()->
-      OpenUriExternal(NS_ConvertUTF8toUTF16(uriSpec), (mType.Equals(uriScheme) || mType.Equals(uriSpec)) ? EmptyString() : NS_ConvertUTF8toUTF16(mType)) ? NS_OK : NS_ERROR_FAILURE;
-
-  return NS_ERROR_FAILURE;
+  return GeckoAppShell::OpenUriExternal(NS_ConvertUTF8toUTF16(uriSpec), (mType.Equals(uriScheme) || mType.Equals(uriSpec)) ? EmptyString() : NS_ConvertUTF8toUTF16(mType)) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 
 bool
 nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType,
                                           nsMIMEInfoAndroid** aMimeInfo)
 {
   nsRefPtr<nsMIMEInfoAndroid> info = new nsMIMEInfoAndroid(aMimeType);
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -34,23 +34,18 @@
 #include "nsPIDOMWindow.h"
 #include "mozilla/dom/ScreenOrientation.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIDOMClientRect.h"
 #include "StrongPointer.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "nsPrintfCString.h"
 
-#ifdef DEBUG
-#define ALOG_BRIDGE(args...) ALOG(args)
-#else
-#define ALOG_BRIDGE(args...) ((void)0)
-#endif
-
 using namespace mozilla;
+using namespace mozilla::widget::android;
 using namespace mozilla::gfx;
 
 NS_IMPL_ISUPPORTS0(nsFilePickerCallback)
 
 StaticRefPtr<AndroidBridge> AndroidBridge::sBridge;
 static unsigned sJavaEnvThreadIndex = 0;
 static jobject sGlobalContext = nullptr;
 static void JavaThreadDetachFunc(void *arg);
@@ -165,24 +160,23 @@ AndroidBridge::Init(JNIEnv *jEnv)
 {
     ALOG_BRIDGE("AndroidBridge::Init");
     jEnv->GetJavaVM(&mJavaVM);
 
     AutoLocalJNIFrame jniFrame(jEnv);
 
     mJNIEnv = nullptr;
     mThread = -1;
-    mGLControllerObj = nullptr;
+    mGLControllerObj = NULL;
     mOpenedGraphicsLibraries = false;
     mHasNativeBitmapAccess = false;
     mHasNativeWindowAccess = false;
     mHasNativeWindowFallback = false;
 
     initInit();
-    InitStubs(jEnv);
 
 #ifdef MOZ_WEBSMS_BACKEND
     mAndroidSmsMessageClass = getClassGlobalRef("android/telephony/SmsMessage");
     jCalculateLength = getStaticMethod("calculateLength", "(Ljava/lang/CharSequence;Z)[I");
 #endif
 
     jStringClass = getClassGlobalRef("java/lang/String");
 
@@ -267,16 +261,62 @@ jstring AndroidBridge::NewJavaString(Aut
 jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const char* string) {
     return NewJavaString(frame, NS_ConvertUTF8toUTF16(string));
 }
 
 jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string) {
     return NewJavaString(frame, NS_ConvertUTF8toUTF16(string));
 }
 
+extern "C" {
+    __attribute__ ((visibility("default")))
+    JNIEnv * GetJNIForThread()
+    {
+        JNIEnv *jEnv = NULL;
+        JavaVM *jVm  = mozilla::AndroidBridge::GetVM();
+        if (!jVm) {
+            __android_log_print(ANDROID_LOG_INFO, "GetJNIForThread", "Returned a null VM");
+            return NULL;
+        }
+        jEnv = static_cast<JNIEnv*>(PR_GetThreadPrivate(sJavaEnvThreadIndex));
+
+        if (jEnv)
+            return jEnv;
+
+        int status = jVm->GetEnv((void**) &jEnv, JNI_VERSION_1_2);
+        if (status) {
+
+            status = jVm->AttachCurrentThread(&jEnv, NULL);
+            if (status) {
+                __android_log_print(ANDROID_LOG_INFO, "GetJNIForThread",  "Could not attach");
+                return NULL;
+            }
+
+            PR_SetThreadPrivate(sJavaEnvThreadIndex, jEnv);
+        }
+        if (!jEnv) {
+            __android_log_print(ANDROID_LOG_INFO, "GetJNIForThread", "returning NULL");
+        }
+        return jEnv;
+    }
+}
+
+void AutoGlobalWrappedJavaObject::Dispose() {
+    if (isNull()) {
+        return;
+    }
+
+    GetJNIForThread()->DeleteGlobalRef(wrapped_obj);
+    wrapped_obj = NULL;
+}
+
+AutoGlobalWrappedJavaObject::~AutoGlobalWrappedJavaObject() {
+    Dispose();
+}
+
 static void
 getHandlersFromStringArray(JNIEnv *aJNIEnv, jobjectArray jArr, jsize aLen,
                            nsIMutableArray *aHandlersArray,
                            nsIHandlerApp **aDefaultApp,
                            const nsAString& aAction = EmptyString(),
                            const nsACString& aMimeType = EmptyCString())
 {
     nsString empty = EmptyString();
@@ -306,17 +346,17 @@ AndroidBridge::GetHandlersForMimeType(co
                                       const nsAString& aAction)
 {
     ALOG_BRIDGE("AndroidBridge::GetHandlersForMimeType");
 
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return false;
 
-    jobjectArray arr = GetHandlersForMimeTypeWrapper(aMimeType, aAction);
+    jobjectArray arr = GeckoAppShell::GetHandlersForMimeTypeWrapper(aMimeType, aAction);
     if (!arr)
         return false;
 
     jsize len = env->GetArrayLength(arr);
 
     if (!aHandlersArray)
         return len > 0;
 
@@ -335,17 +375,17 @@ AndroidBridge::GetHandlersForURL(const n
                                  const nsAString& aAction)
 {
     ALOG_BRIDGE("AndroidBridge::GetHandlersForURL");
 
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return false;
 
-    jobjectArray arr = GetHandlersForURLWrapper(aURL, aAction);
+    jobjectArray arr = GeckoAppShell::GetHandlersForURLWrapper(aURL, aAction);
     if (!arr)
         return false;
 
     jsize len = env->GetArrayLength(arr);
 
     if (!aHandlersArray)
         return len > 0;
 
@@ -360,17 +400,17 @@ void
 AndroidBridge::GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType)
 {
     ALOG_BRIDGE("AndroidBridge::GetMimeTypeFromExtensions");
 
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return;
 
-    jstring jstrType = GetMimeTypeFromExtensionsWrapper(NS_ConvertUTF8toUTF16(aFileExt));
+    jstring jstrType = GeckoAppShell::GetMimeTypeFromExtensionsWrapper(NS_ConvertUTF8toUTF16(aFileExt));
     if (!jstrType) {
         return;
     }
     nsJNIString jniStr(jstrType, env);
     CopyUTF16toUTF8(jniStr.get(), aMimeType);
 
     env->DeleteLocalRef(jstrType);
 }
@@ -379,17 +419,17 @@ void
 AndroidBridge::GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt)
 {
     ALOG_BRIDGE("AndroidBridge::GetExtensionFromMimeType");
 
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return;
 
-    jstring jstrExt = GetExtensionFromMimeTypeWrapper(NS_ConvertUTF8toUTF16(aMimeType));
+    jstring jstrExt = GeckoAppShell::GetExtensionFromMimeTypeWrapper(NS_ConvertUTF8toUTF16(aMimeType));
     if (!jstrExt) {
         return;
     }
     nsJNIString jniStr(jstrExt, env);
     CopyUTF16toUTF8(jniStr.get(), aFileExt);
 
     env->DeleteLocalRef(jstrExt);
 }
@@ -398,83 +438,53 @@ bool
 AndroidBridge::GetClipboardText(nsAString& aText)
 {
     ALOG_BRIDGE("AndroidBridge::GetClipboardText");
 
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return false;
 
-    jstring result = GetClipboardTextWrapper();
+    jstring result = Clipboard::GetClipboardTextWrapper();
     if (!result)
         return false;
 
     nsJNIString jniStr(result, env);
     aText.Assign(jniStr);
 
     env->DeleteLocalRef(result);
     return true;
 }
 
-bool
-AndroidBridge::ClipboardHasText()
-{
-    ALOG_BRIDGE("AndroidBridge::ClipboardHasText");
-
-    JNIEnv *env = GetJNIEnv();
-    if (!env)
-        return false;
-
-    AutoLocalJNIFrame jniFrame(env);
-
-    jstring jStr = GetClipboardTextWrapper();
-    bool ret = jStr;
-
-    return ret;
-}
-
-void
-AndroidBridge::EmptyClipboard()
-{
-    ALOG_BRIDGE("AndroidBridge::EmptyClipboard");
-
-    JNIEnv *env = GetJNIEnv();
-    if (!env)
-        return;
-
-    AutoLocalJNIFrame jniFrame(env, 0);
-    env->CallStaticVoidMethod(mClipboardClass, jSetClipboardText, nullptr);
-}
-
 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));
     }
 
-    ShowAlertNotificationWrapper(aImageUrl, aAlertTitle, aAlertText, aAlertCookie, aAlertName);
+    GeckoAppShell::ShowAlertNotificationWrapper(aImageUrl, aAlertTitle, aAlertText, aAlertCookie, aAlertName);
 }
 
 int
 AndroidBridge::GetDPI()
 {
     static int sDPI = 0;
     if (sDPI)
         return sDPI;
 
     const int DEFAULT_DPI = 160;
 
-    sDPI = GetDpiWrapper();
+    sDPI = GeckoAppShell::GetDpiWrapper();
     if (!sDPI) {
         return DEFAULT_DPI;
     }
 
     return sDPI;
 }
 
 int
@@ -483,72 +493,60 @@ AndroidBridge::GetScreenDepth()
     ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
 
     static int sDepth = 0;
     if (sDepth)
         return sDepth;
 
     const int DEFAULT_DEPTH = 16;
 
-    sDepth = GetScreenDepthWrapper();
+    sDepth = GeckoAppShell::GetScreenDepthWrapper();
     if (!sDepth)
         return DEFAULT_DEPTH;
 
     return sDepth;
 }
 
 void
 AndroidBridge::ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString& aExtensions)
 {
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return;
 
-    jstring jstr = ShowFilePickerForExtensionsWrapper(aExtensions);
+    jstring jstr = GeckoAppShell::ShowFilePickerForExtensionsWrapper(aExtensions);
     if (jstr == nullptr) {
         return;
     }
 
     aFilePath.Assign(nsJNIString(jstr, env));
     env->DeleteLocalRef(jstr);
 }
 
 void
 AndroidBridge::ShowFilePickerForMimeType(nsAString& aFilePath, const nsAString& aMimeType)
 {
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return;
 
-    jstring jstr = ShowFilePickerForMimeTypeWrapper(aMimeType);
+    jstring jstr = GeckoAppShell::ShowFilePickerForMimeTypeWrapper(aMimeType);
     if (jstr == nullptr) {
         return;
     }
 
     aFilePath.Assign(nsJNIString(jstr, env));
     env->DeleteLocalRef(jstr);
 }
 
 void
 AndroidBridge::ShowFilePickerAsync(const nsAString& aMimeType, nsFilePickerCallback* callback)
 {
     callback->AddRef();
-    ShowFilePickerAsyncWrapper(aMimeType, (int64_t) callback);
-}
-
-void
-AndroidBridge::HideProgressDialogOnce()
-{
-    static bool once = false;
-    if (once)
-        return;
-
-    HideProgressDialog();
-
-    once = true;
+    GeckoAppShell::ShowFilePickerAsyncWrapper(aMimeType, (int64_t) callback);
 }
 
 void
 AndroidBridge::Vibrate(const nsTArray<uint32_t>& aPattern)
 {
     ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
 
     uint32_t len = aPattern.Length();
@@ -566,17 +564,17 @@ AndroidBridge::Vibrate(const nsTArray<ui
     // 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;
         }
-        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.
 
     jlongArray array = env->NewLongArray(len + 1);
     if (!array) {
@@ -592,34 +590,34 @@ 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);
 
-    VibrateA(array, -1/*don't repeat*/);
+    GeckoAppShell::VibrateA(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();
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env);
 
-    jintArray arr = GetSystemColoursWrapper();
+    jintArray arr = GeckoAppShell::GetSystemColoursWrapper();
     if (!arr)
         return;
 
     uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr));
     jint *elements = env->GetIntArrayElements(arr, 0);
 
     uint32_t colorsCount = sizeof(AndroidSystemColors) / sizeof(nscolor);
     if (len < colorsCount)
@@ -647,17 +645,17 @@ AndroidBridge::GetIconForExtension(const
         return;
 
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env);
 
-    jbyteArray arr = GetIconForExtensionWrapper(NS_ConvertUTF8toUTF16(aFileExt), aIconSize);
+    jbyteArray 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);
 
@@ -675,72 +673,60 @@ AndroidBridge::SetLayerClient(JNIEnv* en
     // 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
-        env->DeleteGlobalRef(mLayerClient->wrappedObject());
         delete mLayerClient;
         mLayerClient = nullptr;
     }
 
-    AndroidGeckoLayerClient *client = new AndroidGeckoLayerClient();
-    client->Init(env->NewGlobalRef(jobj));
-    mLayerClient = client;
+    mLayerClient = GeckoLayerClient::Wrap(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)
 {
-    ALOG_BRIDGE("AndroidBridge::RegisterCompositor");
-    if (mGLControllerObj) {
+    if (mGLControllerObj != NULL && !mGLControllerObj->isNull()) {
         // we already have this set up, no need to do it again
         return;
     }
 
-    if (!env) {
-        env = GetJNIForThread();    // called on the compositor thread
-    }
-    if (!env) {
-        return;
-    }
-
-    jobject glController = RegisterCompositorWrapper();
+    jobject glController = LayerView::RegisterCompositorWrapper();
     if (!glController) {
         return;
     }
 
-    mGLControllerObj = env->NewGlobalRef(glController);
-    env->DeleteLocalRef(glController);
+    mGLControllerObj = GLController::Wrap(glController);
 }
 
 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
     if (!env) {
         return nullptr;
     }
 
-    jobject eglSurface = CreateEGLSurfaceForCompositorWrapper(mGLControllerObj);
+    jobject eglSurface = mGLControllerObj->CreateEGLSurfaceForCompositorWrapper();
     if (!eglSurface)
         return nullptr;
 
     EGLSurface ret = reinterpret_cast<EGLSurface>(env->GetIntField(eglSurface, jEGLSurfacePointerField));
     env->DeleteLocalRef(eglSurface);
     return ret;
 }
 
@@ -802,21 +788,16 @@ AndroidBridge::GetStaticStringField(cons
 
 // Available for places elsewhere in the code to link to.
 bool
 mozilla_AndroidBridge_SetMainThread(pthread_t thr)
 {
     return AndroidBridge::Bridge()->SetMainThread(thr);
 }
 
-jclass GetGeckoAppShellClass()
-{
-    return mozilla::AndroidBridge::GetGeckoAppShellClass();
-}
-
 void*
 AndroidBridge::GetNativeSurface(JNIEnv* env, jobject surface) {
     if (!env || !mHasNativeWindowFallback || !jSurfacePointerField)
         return nullptr;
 
     return (void*)env->GetIntField(surface, jSurfacePointerField);
 }
 
@@ -1003,17 +984,17 @@ AndroidBridge::ValidateBitmap(jobject bi
 bool
 AndroidBridge::InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps)
 {
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return false;
 
     AutoLocalJNIFrame jniFrame(env);
-    jintArray arr = InitCameraWrapper(NS_ConvertUTF8toUTF16(contentType), (int32_t) camera, (int32_t) width, (int32_t) height);
+    jintArray 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);
 
     *width = elements[1];
     *height = elements[2];
@@ -1034,17 +1015,17 @@ AndroidBridge::GetCurrentBatteryInformat
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env);
 
     // 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 = GetCurrentBatteryInformationWrapper();
+    jdoubleArray arr = GeckoAppShell::GetCurrentBatteryInformationWrapper();
     if (!arr || env->GetArrayLength(arr) != 3) {
         return;
     }
 
     jdouble* info = env->GetDoubleArrayElements(arr, 0);
 
     aBatteryInfo->level() = info[0];
     aBatteryInfo->charging() = info[1] == 1.0f;
@@ -1058,17 +1039,17 @@ AndroidBridge::HandleGeckoMessage(const 
 {
     ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
 
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env);
-    jstring returnMessage = HandleGeckoMessageWrapper(aMessage);
+    jstring returnMessage = GeckoAppShell::HandleGeckoMessageWrapper(aMessage);
 
     if (!returnMessage)
         return;
 
     nsJNIString jniStr(returnMessage, env);
     aRet.Assign(jniStr);
     ALOG_BRIDGE("leaving %s", __PRETTY_FUNCTION__);
 }
@@ -1125,41 +1106,41 @@ AndroidBridge::SendMessage(const nsAStri
                            nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::SendMessage");
 
     uint32_t requestId;
     if (!QueueSmsRequest(aRequest, &requestId))
         return;
 
-    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;
 
-    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;
 
-    DeleteMessageWrapper(aMessageId, requestId);
+    GeckoAppShell::DeleteMessageWrapper(aMessageId, requestId);
 }
 
 void
 AndroidBridge::CreateMessageList(const dom::mobilemessage::SmsFilterData& aFilter, bool aReverse,
                                  nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::CreateMessageList");
 
@@ -1178,31 +1159,31 @@ AndroidBridge::CreateMessageList(const d
                                           jStringClass,
                                           NewJavaString(&jniFrame, EmptyString()));
 
     for (uint32_t i = 0; i < aFilter.numbers().Length(); ++i) {
         env->SetObjectArrayElement(numbers, i,
                                    NewJavaString(&jniFrame, aFilter.numbers()[i]));
     }
 
-    CreateMessageListWrapper(aFilter.startDate(), aFilter.endDate(),
+    GeckoAppShell::CreateMessageListWrapper(aFilter.startDate(), aFilter.endDate(),
                              numbers, aFilter.numbers().Length(),
                              aFilter.delivery(), aReverse, requestId);
 }
 
 void
 AndroidBridge::GetNextMessageInList(int32_t aListId, nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::GetNextMessageInList");
 
     uint32_t requestId;
     if (!QueueSmsRequest(aRequest, &requestId))
         return;
 
-    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);
 
@@ -1244,17 +1225,17 @@ AndroidBridge::GetCurrentNetworkInformat
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env);
 
     // To prevent calling too many methods through JNI, the Java method returns
     // an array of double even if we actually want a double, two booleans, and an integer.
 
-    jdoubleArray arr = GetCurrentNetworkInformationWrapper();
+    jdoubleArray arr = GeckoAppShell::GetCurrentNetworkInformationWrapper();
     if (!arr || env->GetArrayLength(arr) != 4) {
         return;
     }
 
     jdouble* info = env->GetDoubleArrayElements(arr, 0);
 
     aNetworkInfo->bandwidth() = info[0];
     aNetworkInfo->canBeMetered() = info[1] == 1.0f;
@@ -1437,17 +1418,17 @@ jobject
 AndroidBridge::GetGlobalContextRef() {
     if (sGlobalContext == nullptr) {
         JNIEnv *env = GetJNIForThread();
         if (!env)
             return 0;
 
         AutoLocalJNIFrame jniFrame(env, 4);
 
-        jobject context = GetContext();
+        jobject 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;
@@ -1488,58 +1469,101 @@ AndroidBridge::UnlockWindow(void* window
     }
 
     return true;
 }
 
 void
 AndroidBridge::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect)
 {
-    AndroidGeckoLayerClient *client = mLayerClient;
+    GeckoLayerClient *client = mLayerClient;
     if (!client)
         return;
 
-    client->SetFirstPaintViewport(aOffset, aZoom, aCssPageRect);
+    client->SetFirstPaintViewport((float)aOffset.x, (float)aOffset.y, aZoom.scale,
+                                  aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
 }
 
 void
 AndroidBridge::SetPageRect(const CSSRect& aCssPageRect)
 {
-    AndroidGeckoLayerClient *client = mLayerClient;
+    GeckoLayerClient *client = mLayerClient;
     if (!client)
         return;
 
-    client->SetPageRect(aCssPageRect);
+    client->SetPageRect(aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
 }
 
 void
 AndroidBridge::SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
                                 bool aLayersUpdated, ScreenPoint& aScrollOffset, CSSToScreenScale& aScale,
                                 LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
 {
-    AndroidGeckoLayerClient *client = mLayerClient;
-    if (!client)
+    GeckoLayerClient *client = mLayerClient;
+    if (!client) {
+        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!");
 
-    client->SyncViewportInfo(aDisplayPort, aDisplayResolution, aLayersUpdated,
-                             aScrollOffset, aScale, aFixedLayerMargins,
-                             aOffset);
+    if (!viewTransformJObj) {
+        return;
+    }
+
+    ViewTransform* viewTransform = ViewTransform::Wrap(viewTransformJObj);
+    aScrollOffset = ScreenPoint(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;
 }
 
 void AndroidBridge::SyncFrameMetrics(const ScreenPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
                                      bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
                                      bool aIsFirstPaint, LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
 {
-    AndroidGeckoLayerClient *client = mLayerClient;
-    if (!client)
+    GeckoLayerClient *client = mLayerClient;
+    if (!client) {
+        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);
 
-    client->SyncFrameMetrics(aScrollOffset, aZoom, aCssPageRect,
-                             aLayersUpdated, aDisplayPort, aDisplayResolution,
-                             aIsFirstPaint, aFixedLayerMargins, aOffset);
+    NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
+    if (!viewTransformJObj) {
+        return;
+    }
+    ViewTransform* viewTransform = ViewTransform::Wrap(viewTransformJObj);
+
+    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;
 }
 
 AndroidBridge::AndroidBridge()
   : mLayerClient(nullptr),
     mNativePanZoomController(nullptr)
 {
 }
 
@@ -1594,55 +1618,22 @@ static void
 JavaThreadDetachFunc(void *arg)
 {
     JNIEnv *env = (JNIEnv*) arg;
     JavaVM *vm = nullptr;
     env->GetJavaVM(&vm);
     vm->DetachCurrentThread();
 }
 
-extern "C" {
-    __attribute__ ((visibility("default")))
-    JNIEnv * GetJNIForThread()
-    {
-        JNIEnv *jEnv = nullptr;
-        JavaVM *jVm  = mozilla::AndroidBridge::GetVM();
-        if (!jVm) {
-            __android_log_print(ANDROID_LOG_INFO, "GetJNIForThread", "Returned a null VM");
-            return nullptr;
-        }
-        jEnv = static_cast<JNIEnv*>(PR_GetThreadPrivate(sJavaEnvThreadIndex));
-
-        if (jEnv)
-            return jEnv;
-
-        int status = jVm->GetEnv((void**) &jEnv, JNI_VERSION_1_2);
-        if (status) {
-
-            status = jVm->AttachCurrentThread(&jEnv, nullptr);
-            if (status) {
-                __android_log_print(ANDROID_LOG_INFO, "GetJNIForThread",  "Could not attach");
-                return nullptr;
-            }
-            
-            PR_SetThreadPrivate(sJavaEnvThreadIndex, jEnv);
-        }
-        if (!jEnv) {
-            __android_log_print(ANDROID_LOG_INFO, "GetJNIForThread", "returning NULL");
-        }
-        return jEnv;
-    }
-}
-
 uint32_t
 AndroidBridge::GetScreenOrientation()
 {
     ALOG_BRIDGE("AndroidBridge::GetScreenOrientation");
 
-    int16_t orientation = GetScreenOrientationWrapper();
+    int16_t orientation = GeckoAppShell::GetScreenOrientationWrapper();
 
     if (!orientation)
         return dom::eScreenOrientation_None;
 
     return static_cast<dom::ScreenOrientation>(orientation);
 }
 
 void
@@ -1658,17 +1649,17 @@ AndroidBridge::GetProxyForURI(const nsAC
                               const int32_t      aPort,
                               nsACString & aResult)
 {
     JNIEnv* env = GetJNIEnv();
     if (!env)
         return NS_ERROR_FAILURE;
 
     AutoLocalJNIFrame jniFrame(env);
-    jstring jstrRet = GetProxyForURIWrapper(NS_ConvertUTF8toUTF16(aSpec),
+    jstring jstrRet = GeckoAppShell::GetProxyForURIWrapper(NS_ConvertUTF8toUTF16(aSpec),
                                             NS_ConvertUTF8toUTF16(aScheme),
                                             NS_ConvertUTF8toUTF16(aHost),
                                             aPort);
 
     if (!jstrRet)
         return NS_ERROR_FAILURE;
 
     nsJNIString jniStr(jstrRet, env);
@@ -1694,34 +1685,34 @@ 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();
-    AddPluginViewWrapper(view, cssRect.x, cssRect.y, cssRect.width, cssRect.height, isFullScreen);
+    GeckoAppShell::AddPluginViewWrapper(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();
     if (!env)
         return false;
 
     AutoLocalJNIFrame jniFrame(env);
 
-    jstring jstrThreadName = GetThreadNameJavaProfilingWrapper(aThreadId);
+    jstring jstrThreadName = GeckoJavaSampler::GetThreadNameJavaProfilingWrapper(aThreadId);
 
     if (!jstrThreadName)
         return false;
 
     nsJNIString jniStr(jstrThreadName, env);
     CopyUTF16toUTF8(jniStr.get(), aResult);
     return true;
 }
@@ -1731,17 +1722,17 @@ AndroidBridge::GetFrameNameJavaProfiling
                                           uint32_t aFrameId, nsCString & aResult)
 {
     JNIEnv* env = GetJNIForThread();
     if (!env)
         return false;
 
     AutoLocalJNIFrame jniFrame(env);
 
-    jstring jstrSampleName = GetFrameNameJavaProfilingWrapper(aThreadId, aSampleId, aFrameId);
+    jstring jstrSampleName = GeckoJavaSampler::GetFrameNameJavaProfilingWrapper(aThreadId, aSampleId, aFrameId);
 
     if (!jstrSampleName)
         return false;
 
     nsJNIString jniStr(jstrSampleName, env);
     CopyUTF16toUTF8(jniStr.get(), aResult);
     env->DeleteLocalRef(jstrSampleName);
     return true;
@@ -1852,71 +1843,144 @@ nsresult AndroidBridge::CaptureThumbnail
     }
     NS_ENSURE_SUCCESS(rv, rv);
     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 (!env || !mLayerClient)
+    if (!env || !mLayerClient || mLayerClient->isNull()) {
+
+        ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return;
+    }
     AutoLocalJNIFrame jniFrame(env, 0);
-    mLayerClient->GetDisplayPort(&jniFrame, aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, metrics, displayPort);
+
+    float x, y, width, height,
+        pageLeft, pageTop, pageRight, pageBottom,
+        cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
+        zoom;
+    metrics->GetX(&x);
+    metrics->GetY(&y);
+    metrics->GetWidth(&width);
+    metrics->GetHeight(&height);
+    metrics->GetPageLeft(&pageLeft);
+    metrics->GetPageTop(&pageTop);
+    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);
+
+    jobject jobj = mLayerClient->GetDisplayPort(aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, jmetrics.wrappedObject());
+    if (!jobj) {
+        ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
+        return;
+    }
+    DisplayPortMetrics* displayPortMetrics = DisplayPortMetrics::Wrap(jobj);
+
+    AndroidRectF rect(env, displayPortMetrics->getMPosition());
+    if (jniFrame.CheckForException()) {
+        ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
+        return;
+    }
+
+    float resolution = displayPortMetrics->getResolution();
+    if (jniFrame.CheckForException()) {
+        ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
+        return;
+    }
+
+    *displayPort = new nsAndroidDisplayport(rect, resolution);
+    (*displayPort)->AddRef();
+
+    delete displayPortMetrics;
+    ALOG_BRIDGE("Exit: %s", __PRETTY_FUNCTION__);
 }
 
 void
 AndroidBridge::ContentDocumentChanged()
 {
-    JNIEnv* env = GetJNIEnv();
-    if (!env || !mLayerClient)
+    if (!mLayerClient) {
         return;
-    AutoLocalJNIFrame jniFrame(env, 0);
-    mLayerClient->ContentDocumentChanged(&jniFrame);
+    }
+    mLayerClient->ContentDocumentChanged();
 }
 
 bool
 AndroidBridge::IsContentDocumentDisplayed()
 {
     JNIEnv* env = GetJNIEnv();
     if (!env || !mLayerClient)
         return false;
-    AutoLocalJNIFrame jniFrame(env, 0);
-    return mLayerClient->IsContentDocumentDisplayed(&jniFrame);
+
+    return mLayerClient->IsContentDocumentDisplayed();
 }
 
 bool
 AndroidBridge::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, gfx::Rect& aViewport, float& aScaleX, float& aScaleY)
 {
-    AndroidGeckoLayerClient *client = mLayerClient;
-    if (!client)
+    GeckoLayerClient *client = mLayerClient;
+    if (!client) {
+        ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return false;
+    }
 
-    return client->ProgressiveUpdateCallback(aHasPendingNewThebesContent, aDisplayPort, aDisplayResolution, aDrawingCritical, aViewport, aScaleX, aScaleY);
+    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* progressiveUpdateData = ProgressiveUpdateData::Wrap(progressiveUpdateDataJObj);
+
+    aViewport.x = progressiveUpdateData->getx();
+    aViewport.y = progressiveUpdateData->gety();
+    aViewport.width = progressiveUpdateData->getwidth();
+    aViewport.height = progressiveUpdateData->getheight();
+    aScaleX = aScaleY = progressiveUpdateData->getscale();
+
+    bool ret = progressiveUpdateData->getabort();
+    delete progressiveUpdateData;
+
+    return ret;
 }
 
-jobject
+NativePanZoomController*
 AndroidBridge::SetNativePanZoomController(jobject obj)
 {
-    jobject old = mNativePanZoomController;
-    mNativePanZoomController = obj;
+    NativePanZoomController* old = mNativePanZoomController;
+    mNativePanZoomController = NativePanZoomController::Wrap(obj);
     return old;
 }
 
 void
 AndroidBridge::RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics)
 {
     ALOG_BRIDGE("AndroidBridge::RequestContentRepaint");
 
     CSSToScreenScale resolution = aFrameMetrics.mZoom;
     ScreenRect dp = (aFrameMetrics.mDisplayPort + aFrameMetrics.mScrollOffset) * resolution;
 
-    RequestContentRepaintWrapper(mNativePanZoomController,
-        dp.x, dp.y, dp.width, dp.height, resolution.scale);
+    mNativePanZoomController->RequestContentRepaintWrapper(dp.x, dp.y, dp.width, dp.height, resolution.scale);
 }
 
 void
 AndroidBridge::HandleDoubleTap(const CSSIntPoint& aPoint)
 {
     nsCString data = nsPrintfCString("{ \"x\": %d, \"y\": %d }", aPoint.x, aPoint.y);
     nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeBroadcastEvent(
             NS_LITERAL_CSTRING("Gesture:DoubleTap"), data));
@@ -1963,17 +2027,17 @@ AndroidBridge::PostDelayedTask(Task* aTa
     if (i == mDelayedTaskQueue.Length()) {
         // this new task will run after all the existing tasks in the queue
         mDelayedTaskQueue.AppendElement(newTask);
     }
     if (i == 0) {
         // if we're inserting it at the head of the queue, notify Java because
         // we need to get a callback at an earlier time than the last scheduled
         // callback
-        PostDelayedCallbackWrapper(mNativePanZoomController, (int64_t)aDelayMs);
+        mNativePanZoomController->PostDelayedCallbackWrapper((int64_t)aDelayMs);
     }
 }
 
 int64_t
 AndroidBridge::RunDelayedTasks()
 {
     while (mDelayedTaskQueue.Length() > 0) {
         DelayedTask* nextTask = mDelayedTaskQueue[0];
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -9,17 +9,17 @@
 #include <jni.h>
 #include <android/log.h>
 #include <cstdlib>
 #include <pthread.h>
 
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 
-#include "AndroidJavaWrappers.h"
+#include "GeneratedJNIWrappers.h"
 
 #include "nsIMutableArray.h"
 #include "nsIMIMEInfo.h"
 #include "nsColor.h"
 #include "gfxRect.h"
 
 #include "nsIAndroidBridge.h"
 #include "nsIMobileMessageCallback.h"
@@ -36,24 +36,25 @@
 class nsWindow;
 class nsIDOMMozSmsMessage;
 class nsIObserver;
 
 /* See the comment in AndroidBridge about this function before using it */
 extern "C" JNIEnv * GetJNIForThread();
 
 extern bool mozilla_AndroidBridge_SetMainThread(pthread_t);
-extern jclass GetGeckoAppShellClass();
 
 namespace base {
 class Thread;
 } // end namespace base
 
 typedef void* EGLSurface;
 
+using namespace mozilla::widget::android;
+
 namespace mozilla {
 
 namespace hal {
 class BatteryInformation;
 class NetworkInformation;
 } // namespace hal
 
 namespace dom {
@@ -155,20 +156,16 @@ public:
                 return nullptr;
             }
             return sBridge->mJNIEnv;
 
         }
         return nullptr;
     }
 
-    static jclass GetGeckoAppShellClass() {
-        return sBridge->mGeckoAppShellClass;
-    }
-
     // The bridge needs to be constructed via ConstructBridge first,
     // and then once the Gecko main thread is spun up (Gecko side),
     // SetMainThread should be called which will create the JNIEnv for
     // us to use.  toolkit/xre/nsAndroidStartup.cpp calls
     // SetMainThread.
     bool SetMainThread(pthread_t thr);
 
     /* These are all implemented in Java */
@@ -178,36 +175,32 @@ public:
     nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer);
     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, gfx::Rect& aViewport, float& aScaleX, float& aScaleY);
 
     void SetLayerClient(JNIEnv* env, jobject jobj);
-    AndroidGeckoLayerClient &GetLayerClient() { return *mLayerClient; }
+    GeckoLayerClient* 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,
                                 nsIHandlerApp **aDefaultApp = nullptr,
                                 const nsAString& aAction = EmptyString());
 
     void GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType);
     void GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt);
 
     bool GetClipboardText(nsAString& aText);
-    
-    void EmptyClipboard();
-
-    bool ClipboardHasText();
 
     void ShowAlertNotification(const nsAString& aImageUrl,
                                const nsAString& aAlertTitle,
                                const nsAString& aAlertText,
                                const nsAString& aAlertData,
                                nsIObserver *aAlertListener,
                                const nsAString& aAlertName);
 
@@ -215,18 +208,16 @@ public:
     int GetScreenDepth();
 
     void ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString& aExtensions);
     void ShowFilePickerForMimeType(nsAString& aFilePath, const nsAString& aMimeType);
     void ShowFilePickerAsync(const nsAString& aMimeType, nsFilePickerCallback* callback);
 
     void Vibrate(const nsTArray<uint32_t>& aPattern);
 
-    void HideProgressDialogOnce();
-
     void GetSystemColors(AndroidSystemColors *aColors);
 
     void GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf);
 
     // Switch Java to composite with the Gecko Compositor thread
     void RegisterCompositor(JNIEnv* env = nullptr);
     EGLSurface CreateEGLSurfaceForCompositor();
 
@@ -335,17 +326,17 @@ protected:
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
     // the JNIEnv for the main thread
     JNIEnv *mJNIEnv;
     pthread_t mThread;
 
-    AndroidGeckoLayerClient *mLayerClient;
+    GeckoLayerClient *mLayerClient = NULL;
 
     // the android.telephony.SmsMessage class
     jclass mAndroidSmsMessageClass;
 
     AndroidBridge();
     ~AndroidBridge();
 
     void InitStubs(JNIEnv *jEnv);
@@ -376,17 +367,17 @@ protected:
 
     // For native surface stuff
     jclass jSurfaceClass;
     jfieldID jSurfacePointerField;
 
     jclass jLayerView;
 
     jfieldID jEGLSurfacePointerField;
-    jobject mGLControllerObj;
+    GLController *mGLControllerObj;
 
     // some convinient types to have around
     jclass jStringClass;
 
     // 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);
@@ -400,25 +391,24 @@ protected:
     int (* ANativeWindow_unlockAndPost)(void *window);
 
     int (* Surface_lock)(void* surface, void* surfaceInfo, void* region, bool block);
     int (* Surface_unlockAndPost)(void* surface);
     void (* Region_constructor)(void* region);
     void (* Region_set)(void* region, void* rect);
 
 private:
-    jobject mNativePanZoomController;
+    NativePanZoomController* mNativePanZoomController;
     // This will always be accessed from one thread (the APZC "controller"
     // thread, which is the Java UI thread), so we don't need to do locking
     // to touch it
     nsTArray<DelayedTask*> mDelayedTaskQueue;
 
 public:
-    #include "GeneratedJNIWrappers.h"
-    jobject SetNativePanZoomController(jobject obj);
+    NativePanZoomController* SetNativePanZoomController(jobject obj);
     // GeckoContentController methods
     void RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
     void HandleDoubleTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE;
     void HandleSingleTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE;
     void HandleLongTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE;
     void SendAsyncScrollDOMEvent(bool aIsRoot,
                                  const CSSRect& aContentRect,
                                  const CSSSize& aScrollableSize) MOZ_OVERRIDE;
--- a/widget/android/AndroidBridgeUtilities.h
+++ b/widget/android/AndroidBridgeUtilities.h
@@ -12,8 +12,22 @@
 #define getMethod(fname, ftype) \
     AndroidBridge::GetMethodID(jEnv, jClass, fname, ftype)
 
 #define getStaticField(fname, ftype) \
     AndroidBridge::GetStaticFieldID(jEnv, jClass, fname, ftype)
 
 #define getStaticMethod(fname, ftype) \
     AndroidBridge::GetStaticMethodID(jEnv, jClass, fname, ftype)
+
+#ifndef ALOG
+#if defined(DEBUG) || defined(FORCE_ALOG)
+#define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
+#else
+#define ALOG(args...) ((void)0)
+#endif
+#endif
+
+#ifdef DEBUG
+#define ALOG_BRIDGE(args...) ALOG(args)
+#else
+#define ALOG_BRIDGE(args...) ((void)0)
+#endif
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -857,20 +857,20 @@ 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;
     }
 
-    jobject oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(env->NewGlobalRef(instance));
-    if (oldRef) {
+    NativePanZoomController* oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(instance);
+    if (oldRef && !oldRef->isNull()) {
         MOZ_ASSERT(false, "Registering a new NPZC when we already have one");
-        env->DeleteGlobalRef(oldRef);
+        delete oldRef;
     }
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv* env, jobject instance, jobject event)
 {
     APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
     if (controller) {
@@ -901,21 +901,21 @@ 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;
     }
 
-    jobject oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(nullptr);
-    if (!oldRef) {
+    NativePanZoomController* oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(NULL);
+    if (!oldRef || oldRef->isNull()) {
         MOZ_ASSERT(false, "Clearing a non-existent NPZC");
     } else {
-        env->DeleteGlobalRef(oldRef);
+        delete oldRef;
     }
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented(JNIEnv* env, jobject instance, jboolean prevented)
 {
     APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
     if (controller) {
--- a/widget/android/AndroidJNIWrapper.cpp
+++ b/widget/android/AndroidJNIWrapper.cpp
@@ -9,22 +9,16 @@
 #include <dlfcn.h>
 #include <prthread.h>
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Assertions.h"
 #include "nsThreadUtils.h"
 #include "AndroidBridge.h"
 
-#ifdef DEBUG
-#define ALOG_BRIDGE(args...) ALOG(args)
-#else
-#define ALOG_BRIDGE(args...)
-#endif
-
 extern "C" {
   jclass __jsjni_GetGlobalClassRef(const char *className);
 }
 
 class GetGlobalClassRefRunnable : public nsRunnable {
   public:
     GetGlobalClassRefRunnable(const char *className, jclass *foundClass) :
         mClassName(className), mResult(foundClass) {}
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -1,23 +1,23 @@
 /* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AndroidJavaWrappers.h"
 #include "AndroidBridge.h"
 #include "AndroidBridgeUtilities.h"
-#include "nsIAndroidBridge.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIWidget.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;
@@ -86,77 +86,38 @@ jclass AndroidLocation::jLocationClass =
 jmethodID AndroidLocation::jGetLatitudeMethod = 0;
 jmethodID AndroidLocation::jGetLongitudeMethod = 0;
 jmethodID AndroidLocation::jGetAltitudeMethod = 0;
 jmethodID AndroidLocation::jGetAccuracyMethod = 0;
 jmethodID AndroidLocation::jGetBearingMethod = 0;
 jmethodID AndroidLocation::jGetSpeedMethod = 0;
 jmethodID AndroidLocation::jGetTimeMethod = 0;
 
-jclass AndroidGeckoLayerClient::jGeckoLayerClientClass = 0;
-jclass AndroidGeckoLayerClient::jViewportClass = 0;
-jclass AndroidGeckoLayerClient::jDisplayportClass = 0;
-jmethodID AndroidGeckoLayerClient::jSetFirstPaintViewport = 0;
-jmethodID AndroidGeckoLayerClient::jSetPageRect = 0;
-jmethodID AndroidGeckoLayerClient::jSyncViewportInfoMethod = 0;
-jmethodID AndroidGeckoLayerClient::jSyncFrameMetricsMethod = 0;
-jmethodID AndroidGeckoLayerClient::jCreateFrameMethod = 0;
-jmethodID AndroidGeckoLayerClient::jActivateProgramMethod = 0;
-jmethodID AndroidGeckoLayerClient::jDeactivateProgramMethod = 0;
-jmethodID AndroidGeckoLayerClient::jGetDisplayPort = 0;
-jmethodID AndroidGeckoLayerClient::jContentDocumentChanged = 0;
-jmethodID AndroidGeckoLayerClient::jIsContentDocumentDisplayed = 0;
-jmethodID AndroidGeckoLayerClient::jViewportCtor = 0;
-jfieldID AndroidGeckoLayerClient::jDisplayportPosition = 0;
-jfieldID AndroidGeckoLayerClient::jDisplayportResolution = 0;
-jmethodID AndroidGeckoLayerClient::jProgressiveUpdateCallbackMethod = 0;
-
 jclass AndroidLayerRendererFrame::jLayerRendererFrameClass = 0;
 jmethodID AndroidLayerRendererFrame::jBeginDrawingMethod = 0;
 jmethodID AndroidLayerRendererFrame::jDrawBackgroundMethod = 0;
 jmethodID AndroidLayerRendererFrame::jDrawForegroundMethod = 0;
 jmethodID AndroidLayerRendererFrame::jEndDrawingMethod = 0;
 
-jclass AndroidViewTransform::jViewTransformClass = 0;
-jfieldID AndroidViewTransform::jXField = 0;
-jfieldID AndroidViewTransform::jYField = 0;
-jfieldID AndroidViewTransform::jScaleField = 0;
-jfieldID AndroidViewTransform::jFixedLayerMarginLeft = 0;
-jfieldID AndroidViewTransform::jFixedLayerMarginTop = 0;
-jfieldID AndroidViewTransform::jFixedLayerMarginRight = 0;
-jfieldID AndroidViewTransform::jFixedLayerMarginBottom = 0;
-jfieldID AndroidViewTransform::jOffsetXField = 0;
-jfieldID AndroidViewTransform::jOffsetYField = 0;
-
-jclass AndroidProgressiveUpdateData::jProgressiveUpdateDataClass = 0;
-jfieldID AndroidProgressiveUpdateData::jXField = 0;
-jfieldID AndroidProgressiveUpdateData::jYField = 0;
-jfieldID AndroidProgressiveUpdateData::jWidthField = 0;
-jfieldID AndroidProgressiveUpdateData::jHeightField = 0;
-jfieldID AndroidProgressiveUpdateData::jScaleField = 0;
-jfieldID AndroidProgressiveUpdateData::jShouldAbortField = 0;
-
 RefCountedJavaObject::~RefCountedJavaObject() {
     if (mObject)
         GetJNIForThread()->DeleteGlobalRef(mObject);
     mObject = nullptr;
 }
 
 void
 mozilla::InitAndroidJavaWrappers(JNIEnv *jEnv)
 {
     AndroidGeckoEvent::InitGeckoEventClass(jEnv);
     AndroidPoint::InitPointClass(jEnv);
     AndroidLocation::InitLocationClass(jEnv);
     AndroidRect::InitRectClass(jEnv);
     AndroidRectF::InitRectFClass(jEnv);
-    AndroidGeckoLayerClient::InitGeckoLayerClientClass(jEnv);
     AndroidLayerRendererFrame::InitLayerRendererFrameClass(jEnv);
-    AndroidViewTransform::InitViewTransformClass(jEnv);
-    AndroidProgressiveUpdateData::InitProgressiveUpdateDataClass(jEnv);
+    InitStubs(jEnv);
 }
 
 void
 AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv)
 {
     initInit();
 
     jGeckoEventClass = getClassGlobalRef("org/mozilla/gecko/GeckoEvent");
@@ -286,91 +247,28 @@ AndroidRectF::InitRectFClass(JNIEnv *jEn
 
     jBottomField = getField("bottom", "F");
     jLeftField = getField("left", "F");
     jTopField = getField("top", "F");
     jRightField = getField("right", "F");
 }
 
 void
-AndroidGeckoLayerClient::InitGeckoLayerClientClass(JNIEnv *jEnv)
-{
-    initInit();
-
-    jGeckoLayerClientClass = getClassGlobalRef("org/mozilla/gecko/gfx/GeckoLayerClient");
-
-    jProgressiveUpdateCallbackMethod = getMethod("progressiveUpdateCallback",
-                                                 "(ZFFFFFZ)Lorg/mozilla/gecko/gfx/ProgressiveUpdateData;");
-    jSetFirstPaintViewport = getMethod("setFirstPaintViewport", "(FFFFFFF)V");
-    jSetPageRect = getMethod("setPageRect", "(FFFF)V");
-    jSyncViewportInfoMethod = getMethod("syncViewportInfo",
-                                        "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;");
-    jSyncFrameMetricsMethod = getMethod("syncFrameMetrics",
-                                        "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;");
-    jCreateFrameMethod = getMethod("createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;");
-    jActivateProgramMethod = getMethod("activateProgram", "()V");
-    jDeactivateProgramMethod = getMethod("deactivateProgram", "()V");
-    jGetDisplayPort = getMethod("getDisplayPort", "(ZZILorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)Lorg/mozilla/gecko/gfx/DisplayPortMetrics;");
-    jContentDocumentChanged = getMethod("contentDocumentChanged", "()V");
-    jIsContentDocumentDisplayed = getMethod("isContentDocumentDisplayed", "()Z");
-
-    jViewportClass = getClassGlobalRef("org/mozilla/gecko/gfx/ImmutableViewportMetrics");
-    jViewportCtor = getMethod("<init>", "(FFFFFFFFFFFFF)V");
-
-    jDisplayportClass = getClassGlobalRef("org/mozilla/gecko/gfx/DisplayPortMetrics");
-    jDisplayportPosition = getField("mPosition", "Landroid/graphics/RectF;");
-    jDisplayportResolution = getField("resolution", "F");
-}
-
-void
 AndroidLayerRendererFrame::InitLayerRendererFrameClass(JNIEnv *jEnv)
 {
     initInit();
 
     jLayerRendererFrameClass = getClassGlobalRef("org/mozilla/gecko/gfx/LayerRenderer$Frame");
 
     jBeginDrawingMethod = getMethod("beginDrawing", "()V");
     jDrawBackgroundMethod = getMethod("drawBackground", "()V");
     jDrawForegroundMethod = getMethod("drawForeground", "()V");
     jEndDrawingMethod = getMethod("endDrawing", "()V");
 }
 
-void
-AndroidViewTransform::InitViewTransformClass(JNIEnv *jEnv)
-{
-    initInit();
-
-    jViewTransformClass = getClassGlobalRef("org/mozilla/gecko/gfx/ViewTransform");
-
-    jXField = getField("x", "F");
-    jYField = getField("y", "F");
-    jScaleField = getField("scale", "F");
-    jFixedLayerMarginLeft = getField("fixedLayerMarginLeft", "F");
-    jFixedLayerMarginTop = getField("fixedLayerMarginTop", "F");
-    jFixedLayerMarginRight = getField("fixedLayerMarginRight", "F");
-    jFixedLayerMarginBottom = getField("fixedLayerMarginBottom", "F");
-    jOffsetXField = getField("offsetX", "F");
-    jOffsetYField = getField("offsetY", "F");
-}
-
-void
-AndroidProgressiveUpdateData::InitProgressiveUpdateDataClass(JNIEnv *jEnv)
-{
-    initInit();
-
-    jProgressiveUpdateDataClass = getClassGlobalRef("org/mozilla/gecko/gfx/ProgressiveUpdateData");
-
-    jXField = getField("x", "F");
-    jYField = getField("y", "F");
-    jWidthField = getField("width", "F");
-    jHeightField = getField("height", "F");
-    jScaleField = getField("scale", "F");
-    jShouldAbortField = getField("abort", "Z");
-}
-
 #undef initInit
 #undef initClassGlobalRef
 #undef getField
 #undef getMethod
 
 void
 AndroidGeckoEvent::ReadPointArray(nsTArray<nsIntPoint> &points,
                                   JNIEnv *jenv,
@@ -888,23 +786,16 @@ AndroidPoint::Init(JNIEnv *jenv, jobject
         mY = jenv->GetIntField(jobj, jYField);
     } else {
         mX = 0;
         mY = 0;
     }
 }
 
 void
-AndroidGeckoLayerClient::Init(jobject jobj)
-{
-    NS_ASSERTION(wrapped_obj == nullptr, "Init called on non-null wrapped_obj!");
-    wrapped_obj = jobj;
-}
-
-void
 AndroidLayerRendererFrame::Init(JNIEnv *env, jobject jobj)
 {
     if (!isNull()) {
         Dispose(env);
     }
 
     wrapped_obj = env->NewGlobalRef(jobj);
 }
@@ -915,291 +806,18 @@ AndroidLayerRendererFrame::Dispose(JNIEn
     if (isNull()) {
         return;
     }
 
     env->DeleteGlobalRef(wrapped_obj);
     wrapped_obj = 0;
 }
 
-void
-AndroidViewTransform::Init(jobject jobj)
-{
-    NS_ABORT_IF_FALSE(wrapped_obj == nullptr, "Init called on non-null wrapped_obj!");
-    wrapped_obj = jobj;
-}
-
-void
-AndroidProgressiveUpdateData::Init(jobject jobj)
-{
-    NS_ABORT_IF_FALSE(wrapped_obj == nullptr, "Init called on non-null wrapped_obj!");
-    wrapped_obj = jobj;
-}
-
-void
-AndroidGeckoLayerClient::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect)
-{
-    NS_ASSERTION(!isNull(), "SetFirstPaintViewport called on null layer client!");
-    JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
-    if (!env)
-        return;
-
-    AutoLocalJNIFrame jniFrame(env, 0);
-    return env->CallVoidMethod(wrapped_obj, jSetFirstPaintViewport, (float)aOffset.x, (float)aOffset.y, aZoom.scale,
-                               aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
-}
-
-void
-AndroidGeckoLayerClient::SetPageRect(const CSSRect& aCssPageRect)
-{
-    NS_ASSERTION(!isNull(), "SetPageRect called on null layer client!");
-    JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
-    if (!env)
-        return;
-
-    AutoLocalJNIFrame jniFrame(env, 0);
-    return env->CallVoidMethod(wrapped_obj, jSetPageRect,
-                               aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
-}
-
-void
-AndroidGeckoLayerClient::SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
-                                          bool aLayersUpdated, ScreenPoint& aScrollOffset, CSSToScreenScale& aScale,
-                                          LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
-{
-    NS_ASSERTION(!isNull(), "SyncViewportInfo called on null layer client!");
-    JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
-    if (!env)
-        return;
-
-    AutoLocalJNIFrame jniFrame(env);
-
-    jobject viewTransformJObj = env->CallObjectMethod(wrapped_obj, jSyncViewportInfoMethod,
-                                                      aDisplayPort.x, aDisplayPort.y,
-                                                      aDisplayPort.width, aDisplayPort.height,
-                                                      aDisplayResolution.scale, aLayersUpdated);
-    if (jniFrame.CheckForException())
-        return;
-
-    NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
-
-    AndroidViewTransform viewTransform;
-    viewTransform.Init(viewTransformJObj);
-
-    aScrollOffset = ScreenPoint(viewTransform.GetX(env), viewTransform.GetY(env));
-    aScale.scale = viewTransform.GetScale(env);
-    viewTransform.GetFixedLayerMargins(env, aFixedLayerMargins);
-
-    aOffset.x = viewTransform.GetOffsetX(env);
-    aOffset.y = viewTransform.GetOffsetY(env);
-}
-
-void
-AndroidGeckoLayerClient::SyncFrameMetrics(const ScreenPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
-                                          bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
-                                          bool aIsFirstPaint, LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
-{
-    NS_ASSERTION(!isNull(), "SyncFrameMetrics called on null layer client!");
-    JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
-    if (!env)
-        return;
-
-    AutoLocalJNIFrame jniFrame(env);
-
-    // 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 = env->CallObjectMethod(wrapped_obj, jSyncFrameMetricsMethod,
-            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);
-
-    if (jniFrame.CheckForException())
-        return;
-
-    NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
-
-    AndroidViewTransform viewTransform;
-    viewTransform.Init(viewTransformJObj);
-    viewTransform.GetFixedLayerMargins(env, aFixedLayerMargins);
-    aOffset.x = viewTransform.GetOffsetX(env);
-    aOffset.y = viewTransform.GetOffsetY(env);
-}
-
-bool
-AndroidGeckoLayerClient::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
-                                                   const LayerRect& aDisplayPort,
-                                                   float aDisplayResolution,
-                                                   bool aDrawingCritical,
-                                                   gfx::Rect& aViewport,
-                                                   float& aScaleX,
-                                                   float& aScaleY)
-{
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (!env)
-        return false;
-
-    AutoJObject progressiveUpdateDataJObj(env, env->CallObjectMethod(wrapped_obj,
-                                                                     jProgressiveUpdateCallbackMethod,
-                                                                     aHasPendingNewThebesContent,
-                                                                     (float)aDisplayPort.x,
-                                                                     (float)aDisplayPort.y,
-                                                                     (float)aDisplayPort.width,
-                                                                     (float)aDisplayPort.height,
-                                                                     aDisplayResolution,
-                                                                     !aDrawingCritical));
-    if (env->ExceptionCheck()) {
-        env->ExceptionDescribe();
-        env->ExceptionClear();
-        return false;
-    }
-
-    NS_ABORT_IF_FALSE(progressiveUpdateDataJObj, "No progressive update data!");
-
-    AndroidProgressiveUpdateData progressiveUpdateData(progressiveUpdateDataJObj);
-
-    aViewport.x = progressiveUpdateData.GetX(env);
-    aViewport.y = progressiveUpdateData.GetY(env);
-    aViewport.width = progressiveUpdateData.GetWidth(env);
-    aViewport.height = progressiveUpdateData.GetHeight(env);
-    aScaleX = aScaleY = progressiveUpdateData.GetScale(env);
-
-    return progressiveUpdateData.GetShouldAbort(env);
-}
-
-jobject ConvertToJavaViewportMetrics(JNIEnv* env, nsIAndroidViewport* metrics) {
-    float x, y, width, height,
-        pageLeft, pageTop, pageRight, pageBottom,
-        cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
-        zoom;
-    metrics->GetX(&x);
-    metrics->GetY(&y);
-    metrics->GetWidth(&width);
-    metrics->GetHeight(&height);
-    metrics->GetPageLeft(&pageLeft);
-    metrics->GetPageTop(&pageTop);
-    metrics->GetPageRight(&pageRight);
-    metrics->GetPageBottom(&pageBottom);
-    metrics->GetCssPageLeft(&cssPageLeft);
-    metrics->GetCssPageTop(&cssPageTop);
-    metrics->GetCssPageRight(&cssPageRight);
-    metrics->GetCssPageBottom(&cssPageBottom);
-    metrics->GetZoom(&zoom);
-
-    jobject jobj = env->NewObject(AndroidGeckoLayerClient::jViewportClass, AndroidGeckoLayerClient::jViewportCtor,
-                                  pageLeft, pageTop, pageRight, pageBottom,
-                                  cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
-                                  x, y, x + width, y + height,
-                                  zoom);
-    return jobj;
-}
-
-class nsAndroidDisplayport MOZ_FINAL : public nsIAndroidDisplayport
-{
-public:
-    NS_DECL_ISUPPORTS
-    virtual nsresult GetLeft(float *aLeft) { *aLeft = mLeft; return NS_OK; }
-    virtual nsresult GetTop(float *aTop) { *aTop = mTop; return NS_OK; }
-    virtual nsresult GetRight(float *aRight) { *aRight = mRight; return NS_OK; }
-    virtual nsresult GetBottom(float *aBottom) { *aBottom = mBottom; return NS_OK; }
-    virtual nsresult GetResolution(float *aResolution) { *aResolution = mResolution; return NS_OK; }
-    virtual nsresult SetLeft(float aLeft) { mLeft = aLeft; return NS_OK; }
-    virtual nsresult SetTop(float aTop) { mTop = aTop; return NS_OK; }
-    virtual nsresult SetRight(float aRight) { mRight = aRight; return NS_OK; }
-    virtual nsresult SetBottom(float aBottom) { mBottom = aBottom; return NS_OK; }
-    virtual nsresult SetResolution(float aResolution) { mResolution = aResolution; return NS_OK; }
-
-    nsAndroidDisplayport(AndroidRectF aRect, float aResolution):
-        mLeft(aRect.Left()), mTop(aRect.Top()), mRight(aRect.Right()), mBottom(aRect.Bottom()), mResolution(aResolution) {}
-
-private:
-    ~nsAndroidDisplayport() {}
-    float mLeft, mTop, mRight, mBottom, mResolution;
-};
-
 NS_IMPL_ISUPPORTS1(nsAndroidDisplayport, nsIAndroidDisplayport)
 
-void createDisplayPort(AutoLocalJNIFrame *jniFrame, jobject jobj, nsIAndroidDisplayport** displayPort) {
-    JNIEnv* env = jniFrame->GetEnv();
-    AndroidRectF rect(env, env->GetObjectField(jobj, AndroidGeckoLayerClient::jDisplayportPosition));
-    if (jniFrame->CheckForException()) return;
-    float resolution = env->GetFloatField(jobj, AndroidGeckoLayerClient::jDisplayportResolution);
-    if (jniFrame->CheckForException()) return;
-    *displayPort = new nsAndroidDisplayport(rect, resolution);
-}
-
-void
-AndroidGeckoLayerClient::GetDisplayPort(AutoLocalJNIFrame *jniFrame, bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort)
-{
-    jobject jmetrics = ConvertToJavaViewportMetrics(jniFrame->GetEnv(), metrics);
-    if (jniFrame->CheckForException()) return;
-    if (!jmetrics)
-        return;
-    jobject jobj = jniFrame->GetEnv()->CallObjectMethod(wrapped_obj, jGetDisplayPort, aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, jmetrics);
-    if (jniFrame->CheckForException()) return;
-    createDisplayPort(jniFrame, jobj, displayPort);
-    (*displayPort)->AddRef();
-}
-
-void
-AndroidGeckoLayerClient::ContentDocumentChanged(AutoLocalJNIFrame *jniFrame)
-{
-    jniFrame->GetEnv()->CallVoidMethod(wrapped_obj, jContentDocumentChanged);
-}
-
-bool
-AndroidGeckoLayerClient::IsContentDocumentDisplayed(AutoLocalJNIFrame *jniFrame)
-{
-    return jniFrame->GetEnv()->CallBooleanMethod(wrapped_obj, jIsContentDocumentDisplayed);
-}
-
-bool
-AndroidGeckoLayerClient::CreateFrame(AutoLocalJNIFrame *jniFrame, AndroidLayerRendererFrame& aFrame)
-{
-    if (!jniFrame || !jniFrame->GetEnv())
-        return false;
-
-    jobject frameJObj = jniFrame->GetEnv()->CallObjectMethod(wrapped_obj, jCreateFrameMethod);
-    if (jniFrame->CheckForException())
-        return false;
-    NS_ABORT_IF_FALSE(frameJObj, "No frame object!");
-
-    aFrame.Init(jniFrame->GetEnv(), frameJObj);
-    return true;
-}
-
-bool
-AndroidGeckoLayerClient::ActivateProgram(AutoLocalJNIFrame *jniFrame)
-{
-    if (!jniFrame || !jniFrame->GetEnv())
-        return false;
-
-    jniFrame->GetEnv()->CallVoidMethod(wrapped_obj, jActivateProgramMethod);
-    if (jniFrame->CheckForException())
-        return false;
-
-    return true;
-}
-
-bool
-AndroidGeckoLayerClient::DeactivateProgram(AutoLocalJNIFrame *jniFrame)
-{
-    if (!jniFrame || !jniFrame->GetEnv())
-        return false;
-
-    jniFrame->GetEnv()->CallVoidMethod(wrapped_obj, jDeactivateProgramMethod);
-    if (jniFrame->CheckForException())
-        return false;
-
-    return true;
-}
-
 bool
 AndroidLayerRendererFrame::BeginDrawing(AutoLocalJNIFrame *jniFrame)
 {
     if (!jniFrame || !jniFrame->GetEnv())
         return false;
 
     jniFrame->GetEnv()->CallVoidMethod(wrapped_obj, jBeginDrawingMethod);
     if (jniFrame->CheckForException())
@@ -1242,116 +860,16 @@ AndroidLayerRendererFrame::EndDrawing(Au
 
     jniFrame->GetEnv()->CallVoidMethod(wrapped_obj, jEndDrawingMethod);
     if (jniFrame->CheckForException())
         return false;
 
     return true;
 }
 
-float
-AndroidViewTransform::GetX(JNIEnv *env)
-{
-    if (!env)
-        return 0.0f;
-    return env->GetFloatField(wrapped_obj, jXField);
-}
-
-float
-AndroidViewTransform::GetY(JNIEnv *env)
-{
-    if (!env)
-        return 0.0f;
-    return env->GetFloatField(wrapped_obj, jYField);
-}
-
-float
-AndroidViewTransform::GetScale(JNIEnv *env)
-{
-    if (!env)
-        return 0.0f;
-    return env->GetFloatField(wrapped_obj, jScaleField);
-}
-
-void
-AndroidViewTransform::GetFixedLayerMargins(JNIEnv *env, LayerMargin &aFixedLayerMargins)
-{
-    if (!env)
-        return;
-
-    aFixedLayerMargins.top = env->GetFloatField(wrapped_obj, jFixedLayerMarginTop);
-    aFixedLayerMargins.right = env->GetFloatField(wrapped_obj, jFixedLayerMarginRight);
-    aFixedLayerMargins.bottom = env->GetFloatField(wrapped_obj, jFixedLayerMarginBottom);
-    aFixedLayerMargins.left = env->GetFloatField(wrapped_obj, jFixedLayerMarginLeft);
-}
-
-float
-AndroidViewTransform::GetOffsetX(JNIEnv *env)
-{
-    if (!env)
-        return 0.0f;
-    return env->GetFloatField(wrapped_obj, jOffsetXField);
-}
-
-float
-AndroidViewTransform::GetOffsetY(JNIEnv *env)
-{
-    if (!env)
-        return 0.0f;
-    return env->GetFloatField(wrapped_obj, jOffsetYField);
-}
-
-float
-AndroidProgressiveUpdateData::GetX(JNIEnv *env)
-{
-    if (!env)
-        return 0.0f;
-    return env->GetFloatField(wrapped_obj, jXField);
-}
-
-float
-AndroidProgressiveUpdateData::GetY(JNIEnv *env)
-{
-    if (!env)
-        return 0.0f;
-    return env->GetFloatField(wrapped_obj, jYField);
-}
-
-float
-AndroidProgressiveUpdateData::GetWidth(JNIEnv *env)
-{
-    if (!env)
-        return 0.0f;
-    return env->GetFloatField(wrapped_obj, jWidthField);
-}
-
-float
-AndroidProgressiveUpdateData::GetHeight(JNIEnv *env)
-{
-    if (!env)
-        return 0.0f;
-    return env->GetFloatField(wrapped_obj, jHeightField);
-}
-
-float
-AndroidProgressiveUpdateData::GetScale(JNIEnv *env)
-{
-    if (!env)
-        return 0.0f;
-    return env->GetFloatField(wrapped_obj, jScaleField);
-}
-
-bool
-AndroidProgressiveUpdateData::GetShouldAbort(JNIEnv *env)
-{
-    if (!env)
-        return false;
-    return env->GetBooleanField(wrapped_obj, jShouldAbortField);
-}
-
 void
 AndroidRect::Init(JNIEnv *jenv, jobject jobj)
 {
     NS_ASSERTION(wrapped_obj == nullptr, "Init called on non-null wrapped_obj!");
 
     wrapped_obj = jobj;
 
     if (jobj) {
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -10,39 +10,31 @@
 #include <android/input.h>
 #include <android/log.h>
 
 #include "nsGeoPosition.h"
 #include "nsRect.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsIObserver.h"
+#include "nsIAndroidBridge.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/dom/Touch.h"
 #include "mozilla/EventForwards.h"
 #include "InputData.h"
 #include "Units.h"
 
 //#define FORCE_ALOG 1
 
-#ifndef ALOG
-#if defined(DEBUG) || defined(FORCE_ALOG)
-#define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
-#else
-#define ALOG(args...) ((void)0)
-#endif
-#endif
-
 class nsIAndroidDisplayport;
 class nsIAndroidViewport;
 class nsIWidget;
 
 namespace mozilla {
 
-class AndroidGeckoLayerClient;
 class AutoLocalJNIFrame;
 
 void InitAndroidJavaWrappers(JNIEnv *jEnv);
 
 /*
  * Note: do not store global refs to any WrappedJavaObject;
  * these are live only during a particular JNI method, as
  * NewGlobalRef is -not- called on the jobject.
@@ -70,29 +62,61 @@ public:
 private:
     int32_t mRefCnt;
     jobject mObject;
 };
 
 class WrappedJavaObject {
 public:
     WrappedJavaObject() :
-        wrapped_obj(0)
+        wrapped_obj(NULL)
     { }
 
-    WrappedJavaObject(jobject jobj) {
+    WrappedJavaObject(jobject jobj) : wrapped_obj(NULL) {
         Init(jobj);
     }
 
     void Init(jobject jobj) {
         wrapped_obj = jobj;
     }
 
     bool isNull() const {
-        return wrapped_obj == 0;
+        return wrapped_obj == NULL;
+    }
+
+    jobject wrappedObject() const {
+        return wrapped_obj;
+    }
+
+protected:
+    jobject wrapped_obj;
+};
+
+class AutoGlobalWrappedJavaObject : protected WrappedJavaObject{
+public:
+    AutoGlobalWrappedJavaObject() :
+        wrapped_obj(NULL)
+    { }
+
+    AutoGlobalWrappedJavaObject(jobject jobj, JNIEnv* env) : wrapped_obj(NULL) {
+        Init(jobj, env);
+    }
+
+    virtual ~AutoGlobalWrappedJavaObject();
+    void Dispose();
+
+    void Init(jobject jobj, JNIEnv* env) {
+        if (!isNull()) {
+            env->DeleteGlobalRef(wrapped_obj);
+        }
+        wrapped_obj = env->NewGlobalRef(jobj);
+    }
+
+    bool isNull() const {
+        return wrapped_obj == NULL;
     }
 
     jobject wrappedObject() const {
         return wrapped_obj;
     }
 
 protected:
     jobject wrapped_obj;
@@ -181,71 +205,16 @@ protected:
 
     static jclass jRectClass;
     static jfieldID jBottomField;
     static jfieldID jLeftField;
     static jfieldID jRightField;
     static jfieldID jTopField;
 };
 
-class AndroidViewTransform : public WrappedJavaObject {
-public:
-    static void InitViewTransformClass(JNIEnv *jEnv);
-
-    void Init(jobject jobj);
-
-    AndroidViewTransform() {}
-    AndroidViewTransform(jobject jobj) { Init(jobj); }
-
-    float GetX(JNIEnv *env);
-    float GetY(JNIEnv *env);
-    float GetScale(JNIEnv *env);
-    void GetFixedLayerMargins(JNIEnv *env, LayerMargin &aFixedLayerMargins);
-    float GetOffsetX(JNIEnv *env);
-    float GetOffsetY(JNIEnv *env);
-
-private:
-    static jclass jViewTransformClass;
-    static jfieldID jXField;
-    static jfieldID jYField;
-    static jfieldID jScaleField;
-    static jfieldID jFixedLayerMarginLeft;
-    static jfieldID jFixedLayerMarginTop;
-    static jfieldID jFixedLayerMarginRight;
-    static jfieldID jFixedLayerMarginBottom;
-    static jfieldID jOffsetXField;
-    static jfieldID jOffsetYField;
-};
-
-class AndroidProgressiveUpdateData : public WrappedJavaObject {
-public:
-    static void InitProgressiveUpdateDataClass(JNIEnv *jEnv);
-
-    void Init(jobject jobj);
-
-    AndroidProgressiveUpdateData() {}
-    AndroidProgressiveUpdateData(jobject jobj) { Init(jobj); }
-
-    float GetX(JNIEnv *env);
-    float GetY(JNIEnv *env);
-    float GetWidth(JNIEnv *env);
-    float GetHeight(JNIEnv *env);
-    float GetScale(JNIEnv *env);
-    bool GetShouldAbort(JNIEnv *env);
-
-private:
-    static jclass jProgressiveUpdateDataClass;
-    static jfieldID jXField;
-    static jfieldID jYField;
-    static jfieldID jWidthField;
-    static jfieldID jHeightField;
-    static jfieldID jScaleField;
-    static jfieldID jShouldAbortField;
-};
-
 class AndroidLayerRendererFrame : public WrappedJavaObject {
 public:
     static void InitLayerRendererFrameClass(JNIEnv *jEnv);
 
     void Init(JNIEnv *env, jobject jobj);
     void Dispose(JNIEnv *env);
 
     bool BeginDrawing(AutoLocalJNIFrame *jniFrame);
@@ -256,63 +225,16 @@ public:
 private:
     static jclass jLayerRendererFrameClass;
     static jmethodID jBeginDrawingMethod;
     static jmethodID jDrawBackgroundMethod;
     static jmethodID jDrawForegroundMethod;
     static jmethodID jEndDrawingMethod;
 };
 
-class AndroidGeckoLayerClient : public WrappedJavaObject {
-public:
-    static void InitGeckoLayerClientClass(JNIEnv *jEnv);
-
-    void Init(jobject jobj);
-
-    AndroidGeckoLayerClient() {}
-    AndroidGeckoLayerClient(jobject jobj) { Init(jobj); }
-
-    void SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect);
-    void SetPageRect(const CSSRect& aCssPageRect);
-    void SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
-                          bool aLayersUpdated, ScreenPoint& aScrollOffset, CSSToScreenScale& aScale,
-                          LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset);
-    void SyncFrameMetrics(const ScreenPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
-                          bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
-                          bool aIsFirstPaint, LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset);
-    bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, gfx::Rect& aViewport, float& aScaleX, float& aScaleY);
-    bool CreateFrame(AutoLocalJNIFrame *jniFrame, AndroidLayerRendererFrame& aFrame);
-    bool ActivateProgram(AutoLocalJNIFrame *jniFrame);
-    bool DeactivateProgram(AutoLocalJNIFrame *jniFrame);
-    void GetDisplayPort(AutoLocalJNIFrame *jniFrame, bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort);
-    void ContentDocumentChanged(AutoLocalJNIFrame *jniFrame);
-    bool IsContentDocumentDisplayed(AutoLocalJNIFrame *jniFrame);
-
-protected:
-    static jclass jGeckoLayerClientClass;
-    static jmethodID jSetFirstPaintViewport;
-    static jmethodID jSetPageRect;
-    static jmethodID jSyncViewportInfoMethod;
-    static jmethodID jSyncFrameMetricsMethod;
-    static jmethodID jCreateFrameMethod;
-    static jmethodID jActivateProgramMethod;
-    static jmethodID jDeactivateProgramMethod;
-    static jmethodID jGetDisplayPort;
-    static jmethodID jContentDocumentChanged;
-    static jmethodID jIsContentDocumentDisplayed;
-    static jmethodID jProgressiveUpdateCallbackMethod;
-
-public:
-    static jclass jViewportClass;
-    static jclass jDisplayportClass;
-    static jmethodID jViewportCtor;
-    static jfieldID jDisplayportPosition;
-    static jfieldID jDisplayportResolution;
-};
-
 enum {
     // These keycode masks are not defined in android/keycodes.h:
     AKEYCODE_ESCAPE             = 111,
     AKEYCODE_FORWARD_DEL        = 112,
     AKEYCODE_CTRL_LEFT          = 113,
     AKEYCODE_CTRL_RIGHT         = 114,
     AKEYCODE_CAPS_LOCK          = 115,
     AKEYCODE_SCROLL_LOCK        = 116,
@@ -428,16 +350,39 @@ enum {
     AMETA_META_RIGHT_ON         = 0x00040000,
 
     AMETA_ALT_MASK              = AMETA_ALT_LEFT_ON   | AMETA_ALT_RIGHT_ON   | AMETA_ALT_ON,
     AMETA_CTRL_MASK             = AMETA_CTRL_LEFT_ON  | AMETA_CTRL_RIGHT_ON  | AMETA_CTRL_ON,
     AMETA_META_MASK             = AMETA_META_LEFT_ON  | AMETA_META_RIGHT_ON  | AMETA_META_ON,
     AMETA_SHIFT_MASK            = AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON | AMETA_SHIFT_ON,
 };
 
+class nsAndroidDisplayport MOZ_FINAL : public nsIAndroidDisplayport
+{
+public:
+    NS_DECL_ISUPPORTS
+    virtual nsresult GetLeft(float *aLeft) { *aLeft = mLeft; return NS_OK; }
+    virtual nsresult GetTop(float *aTop) { *aTop = mTop; return NS_OK; }
+    virtual nsresult GetRight(float *aRight) { *aRight = mRight; return NS_OK; }
+    virtual nsresult GetBottom(float *aBottom) { *aBottom = mBottom; return NS_OK; }
+    virtual nsresult GetResolution(float *aResolution) { *aResolution = mResolution; return NS_OK; }
+    virtual nsresult SetLeft(float aLeft) { mLeft = aLeft; return NS_OK; }
+    virtual nsresult SetTop(float aTop) { mTop = aTop; return NS_OK; }
+    virtual nsresult SetRight(float aRight) { mRight = aRight; return NS_OK; }
+    virtual nsresult SetBottom(float aBottom) { mBottom = aBottom; return NS_OK; }
+    virtual nsresult SetResolution(float aResolution) { mResolution = aResolution; return NS_OK; }
+
+    nsAndroidDisplayport(AndroidRectF aRect, float aResolution):
+        mLeft(aRect.Left()), mTop(aRect.Top()), mRight(aRect.Right()), mBottom(aRect.Bottom()), mResolution(aResolution) {}
+
+private:
+    ~nsAndroidDisplayport() {}
+    float mLeft, mTop, mRight, mBottom, mResolution;
+};
+
 class AndroidMotionEvent
 {
 public:
     enum {
         ACTION_DOWN = 0,
         ACTION_UP = 1,
         ACTION_MOVE = 2,
         ACTION_CANCEL = 3,
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -1,25 +1,100 @@
 // 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.
 
+#include "GeneratedJNIWrappers.h"
+#include "AndroidBridgeUtilities.h"
 #include "nsXPCOMStrings.h"
 #include "AndroidBridge.h"
-#include "AndroidBridgeUtilities.h"
-
-#ifdef DEBUG
-#define ALOG_BRIDGE(args...) ALOG(args)
-#else
-#define ALOG_BRIDGE(args...) ((void)0)
-#endif
-
-using namespace mozilla;
-void AndroidBridge::InitStubs(JNIEnv *jEnv) {
+
+namespace mozilla {
+namespace widget {
+namespace android {
+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::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::jGetContext = 0;
+jmethodID GeckoAppShell::jGetCurrentBatteryInformationWrapper = 0;
+jmethodID GeckoAppShell::jGetCurrentNetworkInformationWrapper = 0;
+jmethodID GeckoAppShell::jGetDensity = 0;
+jmethodID GeckoAppShell::jGetDpiWrapper = 0;
+jmethodID GeckoAppShell::jGetExtensionFromMimeTypeWrapper = 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::jHideProgressDialog = 0;
+jmethodID GeckoAppShell::jInitCameraWrapper = 0;
+jmethodID GeckoAppShell::jIsNetworkLinkKnown = 0;
+jmethodID GeckoAppShell::jIsNetworkLinkUp = 0;
+jmethodID GeckoAppShell::jIsTablet = 0;
+jmethodID GeckoAppShell::jKillAnyZombies = 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::jScanMedia = 0;
+jmethodID GeckoAppShell::jScheduleRestart = 0;
+jmethodID GeckoAppShell::jSendMessageWrapper = 0;
+jmethodID GeckoAppShell::jSetFullScreen = 0;
+jmethodID GeckoAppShell::jSetKeepScreenOn = 0;
+jmethodID GeckoAppShell::jSetSelectedLocale = 0;
+jmethodID GeckoAppShell::jSetURITitle = 0;
+jmethodID GeckoAppShell::jShowAlertNotificationWrapper = 0;
+jmethodID GeckoAppShell::jShowFilePickerAsyncWrapper = 0;
+jmethodID GeckoAppShell::jShowFilePickerForExtensionsWrapper = 0;
+jmethodID GeckoAppShell::jShowFilePickerForMimeTypeWrapper = 0;
+jmethodID GeckoAppShell::jShowInputMethodPicker = 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 *jEnv) {
     initInit();
 
     mGeckoAppShellClass = getClassGlobalRef("org/mozilla/gecko/GeckoAppShell");
     jAcknowledgeEvent = getStaticMethod("acknowledgeEvent", "()V");
     jAddPluginViewWrapper = getStaticMethod("addPluginView", "(Landroid/view/View;FFFFZ)V");
     jAlertsProgressListener_OnProgress = getStaticMethod("alertsProgressListener_OnProgress", "(Ljava/lang/String;JJLjava/lang/String;)V");
     jCancelVibrate = getStaticMethod("cancelVibrate", "()V");
     jCheckURIVisited = getStaticMethod("checkUriVisited", "(Ljava/lang/String;)V");
@@ -90,46 +165,33 @@ void AndroidBridge::InitStubs(JNIEnv *jE
     jShowFilePickerForExtensionsWrapper = getStaticMethod("showFilePickerForExtensions", "(Ljava/lang/String;)Ljava/lang/String;");
     jShowFilePickerForMimeTypeWrapper = getStaticMethod("showFilePickerForMimeType", "(Ljava/lang/String;)Ljava/lang/String;");
     jShowInputMethodPicker = getStaticMethod("showInputMethodPicker", "()V");
     jUnlockProfile = getStaticMethod("unlockProfile", "()Z");
     jUnlockScreenOrientation = getStaticMethod("unlockScreenOrientation", "()V");
     jUnregisterSurfaceTextureFrameListener = getStaticMethod("unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V");
     jVibrate1 = getStaticMethod("vibrate", "(J)V");
     jVibrateA = getStaticMethod("vibrate", "([JI)V");
-
-    mGeckoJavaSamplerClass = getClassGlobalRef("org/mozilla/gecko/GeckoJavaSampler");
-    jGetFrameNameJavaProfilingWrapper = getStaticMethod("getFrameName", "(III)Ljava/lang/String;");
-    jGetSampleTimeJavaProfiling = getStaticMethod("getSampleTime", "(II)D");
-    jGetThreadNameJavaProfilingWrapper = getStaticMethod("getThreadName", "(I)Ljava/lang/String;");
-    jPauseJavaProfiling = getStaticMethod("pause", "()V");
-    jStartJavaProfiling = getStaticMethod("start", "(II)V");
-    jStopJavaProfiling = getStaticMethod("stop", "()V");
-    jUnpauseJavaProfiling = getStaticMethod("unpause", "()V");
-
-    mThumbnailHelperClass = getClassGlobalRef("org/mozilla/gecko/ThumbnailHelper");
-    jSendThumbnail = getStaticMethod("notifyThumbnail", "(Ljava/nio/ByteBuffer;IZ)V");
-
-    mGLControllerClass = getClassGlobalRef("org/mozilla/gecko/gfx/GLController");
-    jCreateEGLSurfaceForCompositorWrapper = getMethod("createEGLSurfaceForCompositor", "()Ljavax/microedition/khronos/egl/EGLSurface;");
-
-    mLayerViewClass = getClassGlobalRef("org/mozilla/gecko/gfx/LayerView");
-    jRegisterCompositorWrapper = getStaticMethod("registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;");
-
-    mNativePanZoomControllerClass = getClassGlobalRef("org/mozilla/gecko/gfx/NativePanZoomController");
-    jPostDelayedCallbackWrapper = getMethod("postDelayedCallback", "(J)V");
-    jRequestContentRepaintWrapper = getMethod("requestContentRepaint", "(FFFFF)V");
-
-    mClipboardClass = getClassGlobalRef("org/mozilla/gecko/util/Clipboard");
-    jGetClipboardTextWrapper = getStaticMethod("getText", "()Ljava/lang/String;");
-    jSetClipboardText = getStaticMethod("setText", "(Ljava/lang/CharSequence;)V");
 }
 
-void AndroidBridge::AcknowledgeEvent() {
-    JNIEnv *env = GetJNIEnv();
+GeckoAppShell* GeckoAppShell::Wrap(jobject obj) {
+    JNIEnv *env = GetJNIForThread();
+
+    if (!env) {
+        ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
+        return NULL;
+    }
+
+    GeckoAppShell* ret = new GeckoAppShell(obj, env);
+    env->DeleteLocalRef(obj);
+    return ret;
+}
+
+void GeckoAppShell::AcknowledgeEvent() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -141,21 +203,22 @@ void AndroidBridge::AcknowledgeEvent() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::AddPluginViewWrapper(jobject a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, bool a5) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::AddPluginViewWrapper(jobject a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, bool a5) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -175,53 +238,55 @@ void AndroidBridge::AddPluginViewWrapper
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::AlertsProgressListener_OnProgress(const nsAString& a0, int64_t a1, int64_t a2, const nsAString& a3) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::AlertsProgressListener_OnProgress(const nsAString& a0, int64_t a1, int64_t a2, const nsAString& a3) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
     jvalue args[4];
-    args[0].l = NewJavaString(env, a0);
+    args[0].l = AndroidBridge::NewJavaString(env, a0);
     args[1].j = a1;
     args[2].j = a2;
-    args[3].l = NewJavaString(env, a3);
+    args[3].l = AndroidBridge::NewJavaString(env, a3);
 
     env->CallStaticVoidMethodA(mGeckoAppShellClass, jAlertsProgressListener_OnProgress, args);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::CancelVibrate() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::CancelVibrate() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -233,49 +298,51 @@ void AndroidBridge::CancelVibrate() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::CheckURIVisited(const nsAString& a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::CheckURIVisited(const nsAString& a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     env->CallStaticVoidMethod(mGeckoAppShellClass, jCheckURIVisited, j0);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::ClearMessageList(int32_t a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::ClearMessageList(int32_t a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -287,21 +354,22 @@ void AndroidBridge::ClearMessageList(int
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::CloseCamera() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::CloseCamera() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -313,49 +381,51 @@ void AndroidBridge::CloseCamera() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::CloseNotification(const nsAString& a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::CloseNotification(const nsAString& a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     env->CallStaticVoidMethod(mGeckoAppShellClass, jCloseNotification, j0);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::CreateMessageListWrapper(int64_t a0, int64_t a1, jobjectArray a2, int32_t a3, int32_t a4, bool a5, int32_t a6) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::CreateMessageListWrapper(int64_t a0, int64_t a1, jobjectArray a2, int32_t a3, int32_t a4, bool a5, int32_t a6) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -376,53 +446,55 @@ void AndroidBridge::CreateMessageListWra
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::CreateShortcut(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::CreateShortcut(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(4) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
     jvalue args[4];
-    args[0].l = NewJavaString(env, a0);
-    args[1].l = NewJavaString(env, a1);
-    args[2].l = NewJavaString(env, a2);
-    args[3].l = NewJavaString(env, a3);
+    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);
 
     env->CallStaticVoidMethodA(mGeckoAppShellClass, jCreateShortcut, args);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::DeleteMessageWrapper(int32_t a0, int32_t a1) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::DeleteMessageWrapper(int32_t a0, int32_t a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -434,21 +506,22 @@ void AndroidBridge::DeleteMessageWrapper
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::DisableBatteryNotifications() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::DisableBatteryNotifications() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -460,21 +533,22 @@ void AndroidBridge::DisableBatteryNotifi
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::DisableNetworkNotifications() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::DisableNetworkNotifications() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -486,21 +560,22 @@ void AndroidBridge::DisableNetworkNotifi
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::DisableScreenOrientationNotifications() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::DisableScreenOrientationNotifications() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -512,21 +587,22 @@ void AndroidBridge::DisableScreenOrienta
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::DisableSensor(int32_t a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::DisableSensor(int32_t a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -538,21 +614,22 @@ void AndroidBridge::DisableSensor(int32_
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::EnableBatteryNotifications() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::EnableBatteryNotifications() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -564,21 +641,22 @@ void AndroidBridge::EnableBatteryNotific
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::EnableLocation(bool a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::EnableLocation(bool a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -590,21 +668,22 @@ void AndroidBridge::EnableLocation(bool 
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::EnableLocationHighAccuracy(bool a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::EnableLocationHighAccuracy(bool a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -616,21 +695,22 @@ void AndroidBridge::EnableLocationHighAc
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::EnableNetworkNotifications() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::EnableNetworkNotifications() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -642,21 +722,22 @@ void AndroidBridge::EnableNetworkNotific
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::EnableScreenOrientationNotifications() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::EnableScreenOrientationNotifications() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -668,21 +749,22 @@ void AndroidBridge::EnableScreenOrientat
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::EnableSensor(int32_t a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::EnableSensor(int32_t a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -694,20 +776,21 @@ void AndroidBridge::EnableSensor(int32_t
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-jobject AndroidBridge::GetContext() {
+jobject GeckoAppShell::GetContext() {
     JNIEnv *env = GetJNIForThread();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
@@ -720,22 +803,23 @@ jobject AndroidBridge::GetContext() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
     return ret;
 }
 
-jdoubleArray AndroidBridge::GetCurrentBatteryInformationWrapper() {
-    JNIEnv *env = GetJNIEnv();
+jdoubleArray GeckoAppShell::GetCurrentBatteryInformationWrapper() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -747,22 +831,23 @@ jdoubleArray AndroidBridge::GetCurrentBa
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jdoubleArray ret = static_cast<jdoubleArray>(env->PopLocalFrame(temp));
     return ret;
 }
 
-jdoubleArray AndroidBridge::GetCurrentNetworkInformationWrapper() {
-    JNIEnv *env = GetJNIEnv();
+jdoubleArray GeckoAppShell::GetCurrentNetworkInformationWrapper() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -774,22 +859,23 @@ jdoubleArray AndroidBridge::GetCurrentNe
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jdoubleArray ret = static_cast<jdoubleArray>(env->PopLocalFrame(temp));
     return ret;
 }
 
-jfloat AndroidBridge::GetDensity() {
-    JNIEnv *env = GetJNIEnv();
+jfloat GeckoAppShell::GetDensity() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return 0.0;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -801,22 +887,23 @@ jfloat AndroidBridge::GetDensity() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return 0.0;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-int32_t AndroidBridge::GetDpiWrapper() {
-    JNIEnv *env = GetJNIEnv();
+int32_t GeckoAppShell::GetDpiWrapper() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return 0;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -828,140 +915,145 @@ int32_t AndroidBridge::GetDpiWrapper() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return 0;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-jstring AndroidBridge::GetExtensionFromMimeTypeWrapper(const nsAString& a0) {
-    JNIEnv *env = GetJNIEnv();
+jstring GeckoAppShell::GetExtensionFromMimeTypeWrapper(const nsAString& a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return nullptr;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetExtensionFromMimeTypeWrapper, j0);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
     return ret;
 }
 
-jobjectArray AndroidBridge::GetHandlersForMimeTypeWrapper(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = GetJNIEnv();
+jobjectArray GeckoAppShell::GetHandlersForMimeTypeWrapper(const nsAString& a0, const nsAString& a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(3) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return nullptr;
     }
 
-    jstring j0 = NewJavaString(env, a0);
-    jstring j1 = NewJavaString(env, a1);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+    jstring j1 = AndroidBridge::NewJavaString(env, a1);
 
     jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetHandlersForMimeTypeWrapper, j0, j1);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jobjectArray ret = static_cast<jobjectArray>(env->PopLocalFrame(temp));
     return ret;
 }
 
-jobjectArray AndroidBridge::GetHandlersForURLWrapper(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = GetJNIEnv();
+jobjectArray GeckoAppShell::GetHandlersForURLWrapper(const nsAString& a0, const nsAString& a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(3) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return nullptr;
     }
 
-    jstring j0 = NewJavaString(env, a0);
-    jstring j1 = NewJavaString(env, a1);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+    jstring j1 = AndroidBridge::NewJavaString(env, a1);
 
     jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetHandlersForURLWrapper, j0, j1);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jobjectArray ret = static_cast<jobjectArray>(env->PopLocalFrame(temp));
     return ret;
 }
 
-jbyteArray AndroidBridge::GetIconForExtensionWrapper(const nsAString& a0, int32_t a1) {
-    JNIEnv *env = GetJNIEnv();
+jbyteArray GeckoAppShell::GetIconForExtensionWrapper(const nsAString& a0, int32_t a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return nullptr;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetIconForExtensionWrapper, j0, a1);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jbyteArray ret = static_cast<jbyteArray>(env->PopLocalFrame(temp));
     return ret;
 }
 
-void AndroidBridge::GetMessageWrapper(int32_t a0, int32_t a1) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::GetMessageWrapper(int32_t a0, int32_t a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -973,50 +1065,52 @@ void AndroidBridge::GetMessageWrapper(in
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-jstring AndroidBridge::GetMimeTypeFromExtensionsWrapper(const nsAString& a0) {
-    JNIEnv *env = GetJNIEnv();
+jstring GeckoAppShell::GetMimeTypeFromExtensionsWrapper(const nsAString& a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return nullptr;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetMimeTypeFromExtensionsWrapper, j0);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
     return ret;
 }
 
-void AndroidBridge::GetNextMessageInListWrapper(int32_t a0, int32_t a1) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::GetNextMessageInListWrapper(int32_t a0, int32_t a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1028,54 +1122,56 @@ void AndroidBridge::GetNextMessageInList
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-jstring AndroidBridge::GetProxyForURIWrapper(const nsAString& a0, const nsAString& a1, const nsAString& a2, int32_t a3) {
-    JNIEnv *env = GetJNIEnv();
+jstring GeckoAppShell::GetProxyForURIWrapper(const nsAString& a0, const nsAString& a1, const nsAString& a2, int32_t a3) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(4) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return nullptr;
     }
 
     jvalue args[4];
-    args[0].l = NewJavaString(env, a0);
-    args[1].l = NewJavaString(env, a1);
-    args[2].l = NewJavaString(env, a2);
+    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);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
     return ret;
 }
 
-int32_t AndroidBridge::GetScreenDepthWrapper() {
-    JNIEnv *env = GetJNIEnv();
+int32_t GeckoAppShell::GetScreenDepthWrapper() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return 0;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1087,22 +1183,23 @@ int32_t AndroidBridge::GetScreenDepthWra
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return 0;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-int16_t AndroidBridge::GetScreenOrientationWrapper() {
-    JNIEnv *env = GetJNIEnv();
+int16_t GeckoAppShell::GetScreenOrientationWrapper() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return 0;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1114,22 +1211,23 @@ int16_t AndroidBridge::GetScreenOrientat
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return 0;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-bool AndroidBridge::GetShowPasswordSetting() {
-    JNIEnv *env = GetJNIEnv();
+bool GeckoAppShell::GetShowPasswordSetting() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return false;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1141,22 +1239,23 @@ bool AndroidBridge::GetShowPasswordSetti
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return false;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-jintArray AndroidBridge::GetSystemColoursWrapper() {
-    JNIEnv *env = GetJNIEnv();
+jintArray GeckoAppShell::GetSystemColoursWrapper() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1168,51 +1267,53 @@ jintArray AndroidBridge::GetSystemColour
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jintArray ret = static_cast<jintArray>(env->PopLocalFrame(temp));
     return ret;
 }
 
-jstring AndroidBridge::HandleGeckoMessageWrapper(const nsAString& a0) {
-    JNIEnv *env = GetJNIEnv();
+jstring GeckoAppShell::HandleGeckoMessageWrapper(const nsAString& a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return nullptr;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jHandleGeckoMessageWrapper, j0);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
     return ret;
 }
 
-void AndroidBridge::HideProgressDialog() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::HideProgressDialog() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1224,54 +1325,56 @@ void AndroidBridge::HideProgressDialog()
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-jintArray AndroidBridge::InitCameraWrapper(const nsAString& a0, int32_t a1, int32_t a2, int32_t a3) {
-    JNIEnv *env = GetJNIEnv();
+jintArray GeckoAppShell::InitCameraWrapper(const nsAString& a0, int32_t a1, int32_t a2, int32_t a3) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return nullptr;
     }
 
     jvalue args[4];
-    args[0].l = NewJavaString(env, a0);
+    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);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jintArray ret = static_cast<jintArray>(env->PopLocalFrame(temp));
     return ret;
 }
 
-bool AndroidBridge::IsNetworkLinkKnown() {
-    JNIEnv *env = GetJNIEnv();
+bool GeckoAppShell::IsNetworkLinkKnown() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return false;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1283,22 +1386,23 @@ bool AndroidBridge::IsNetworkLinkKnown()
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return false;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-bool AndroidBridge::IsNetworkLinkUp() {
-    JNIEnv *env = GetJNIEnv();
+bool GeckoAppShell::IsNetworkLinkUp() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return false;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1310,22 +1414,23 @@ bool AndroidBridge::IsNetworkLinkUp() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return false;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-bool AndroidBridge::IsTablet() {
-    JNIEnv *env = GetJNIEnv();
+bool GeckoAppShell::IsTablet() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return false;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1337,22 +1442,23 @@ bool AndroidBridge::IsTablet() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return false;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-void AndroidBridge::KillAnyZombies() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::KillAnyZombies() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1364,21 +1470,22 @@ void AndroidBridge::KillAnyZombies() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::LockScreenOrientation(int32_t a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::LockScreenOrientation(int32_t a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1390,49 +1497,51 @@ void AndroidBridge::LockScreenOrientatio
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::MarkURIVisited(const nsAString& a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::MarkURIVisited(const nsAString& a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     env->CallStaticVoidMethod(mGeckoAppShellClass, jMarkURIVisited, j0);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::MoveTaskToBack() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::MoveTaskToBack() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1444,21 +1553,22 @@ void AndroidBridge::MoveTaskToBack() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-int32_t AndroidBridge::NetworkLinkType() {
-    JNIEnv *env = GetJNIEnv();
+int32_t GeckoAppShell::NetworkLinkType() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return 0;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1470,22 +1580,23 @@ int32_t AndroidBridge::NetworkLinkType()
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return 0;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-void AndroidBridge::NotifyDefaultPrevented(bool a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::NotifyDefaultPrevented(bool a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1497,155 +1608,145 @@ void AndroidBridge::NotifyDefaultPrevent
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::NotifyIME(int32_t a0) {
-    if (!sBridge) {
-        ALOG_BRIDGE("Aborted: No sBridge - %s", __PRETTY_FUNCTION__);
-        return;
-    }
-
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::NotifyIME(int32_t a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
-    env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass, sBridge->jNotifyIME, a0);
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyIME, a0);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::NotifyIMEChange(const nsAString& a0, int32_t a1, int32_t a2, int32_t a3) {
-    if (!sBridge) {
-        ALOG_BRIDGE("Aborted: No sBridge - %s", __PRETTY_FUNCTION__);
-        return;
-    }
-
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::NotifyIMEChange(const nsAString& a0, int32_t a1, int32_t a2, int32_t a3) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
     jvalue args[4];
-    args[0].l = NewJavaString(env, a0);
+    args[0].l = AndroidBridge::NewJavaString(env, a0);
     args[1].i = a1;
     args[2].i = a2;
     args[3].i = a3;
 
-    env->CallStaticVoidMethodA(sBridge->mGeckoAppShellClass, sBridge->jNotifyIMEChange, args);
+    env->CallStaticVoidMethodA(mGeckoAppShellClass, jNotifyIMEChange, args);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::NotifyIMEContext(int32_t a0, const nsAString& a1, const nsAString& a2, const nsAString& a3) {
-    if (!sBridge) {
-        ALOG_BRIDGE("Aborted: No sBridge - %s", __PRETTY_FUNCTION__);
-        return;
-    }
-
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::NotifyIMEContext(int32_t a0, const nsAString& a1, const nsAString& a2, const nsAString& a3) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(3) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
     jvalue args[4];
     args[0].i = a0;
-    args[1].l = NewJavaString(env, a1);
-    args[2].l = NewJavaString(env, a2);
-    args[3].l = NewJavaString(env, a3);
-
-    env->CallStaticVoidMethodA(sBridge->mGeckoAppShellClass, sBridge->jNotifyIMEContext, args);
+    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);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::NotifyWakeLockChanged(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::NotifyWakeLockChanged(const nsAString& a0, const nsAString& a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
-    jstring j0 = NewJavaString(env, a0);
-    jstring j1 = NewJavaString(env, a1);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+    jstring j1 = AndroidBridge::NewJavaString(env, a1);
 
     env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyWakeLockChanged, j0, j1);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::NotifyXreExit() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::NotifyXreExit() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1657,56 +1758,58 @@ void AndroidBridge::NotifyXreExit() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-bool AndroidBridge::OpenUriExternal(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3, const nsAString& a4, const nsAString& a5) {
-    JNIEnv *env = GetJNIEnv();
+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) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return false;
     }
 
     if (env->PushLocalFrame(6) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return false;
     }
 
     jvalue args[6];
-    args[0].l = NewJavaString(env, a0);
-    args[1].l = NewJavaString(env, a1);
-    args[2].l = NewJavaString(env, a2);
-    args[3].l = NewJavaString(env, a3);
-    args[4].l = NewJavaString(env, a4);
-    args[5].l = NewJavaString(env, a5);
+    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);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return false;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-void AndroidBridge::PerformHapticFeedback(bool a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::PerformHapticFeedback(bool a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1718,21 +1821,22 @@ void AndroidBridge::PerformHapticFeedbac
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-bool AndroidBridge::PumpMessageLoop() {
-    JNIEnv *env = GetJNIEnv();
+bool GeckoAppShell::PumpMessageLoop() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return false;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1744,22 +1848,23 @@ bool AndroidBridge::PumpMessageLoop() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return false;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-void AndroidBridge::RegisterSurfaceTextureFrameListener(jobject a0, int32_t a1) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::RegisterSurfaceTextureFrameListener(jobject a0, int32_t a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1771,21 +1876,22 @@ void AndroidBridge::RegisterSurfaceTextu
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::RemovePluginView(jobject a0, bool a1) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::RemovePluginView(jobject a0, bool a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1797,50 +1903,52 @@ void AndroidBridge::RemovePluginView(job
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::ScanMedia(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::ScanMedia(const nsAString& a0, const nsAString& a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
-    jstring j0 = NewJavaString(env, a0);
-    jstring j1 = NewJavaString(env, a1);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+    jstring j1 = AndroidBridge::NewJavaString(env, a1);
 
     env->CallStaticVoidMethod(mGeckoAppShellClass, jScanMedia, j0, j1);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::ScheduleRestart() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::ScheduleRestart() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1852,52 +1960,54 @@ void AndroidBridge::ScheduleRestart() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::SendMessageWrapper(const nsAString& a0, const nsAString& a1, int32_t a2) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::SendMessageWrapper(const nsAString& a0, const nsAString& a1, int32_t a2) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
     jvalue args[3];
-    args[0].l = NewJavaString(env, a0);
-    args[1].l = NewJavaString(env, a1);
+    args[0].l = AndroidBridge::NewJavaString(env, a0);
+    args[1].l = AndroidBridge::NewJavaString(env, a1);
     args[2].i = a2;
 
     env->CallStaticVoidMethodA(mGeckoAppShellClass, jSendMessageWrapper, args);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::SetFullScreen(bool a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::SetFullScreen(bool a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1909,21 +2019,22 @@ void AndroidBridge::SetFullScreen(bool a
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::SetKeepScreenOn(bool a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::SetKeepScreenOn(bool a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -1935,197 +2046,204 @@ void AndroidBridge::SetKeepScreenOn(bool
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::SetSelectedLocale(const nsAString& a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::SetSelectedLocale(const nsAString& a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     env->CallStaticVoidMethod(mGeckoAppShellClass, jSetSelectedLocale, j0);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::SetURITitle(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::SetURITitle(const nsAString& a0, const nsAString& a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
-    jstring j0 = NewJavaString(env, a0);
-    jstring j1 = NewJavaString(env, a1);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+    jstring j1 = AndroidBridge::NewJavaString(env, a1);
 
     env->CallStaticVoidMethod(mGeckoAppShellClass, jSetURITitle, j0, j1);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::ShowAlertNotificationWrapper(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3, const nsAString& a4) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::ShowAlertNotificationWrapper(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3, const nsAString& a4) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(5) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
     jvalue args[5];
-    args[0].l = NewJavaString(env, a0);
-    args[1].l = NewJavaString(env, a1);
-    args[2].l = NewJavaString(env, a2);
-    args[3].l = NewJavaString(env, a3);
-    args[4].l = NewJavaString(env, a4);
+    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);
 
     env->CallStaticVoidMethodA(mGeckoAppShellClass, jShowAlertNotificationWrapper, args);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::ShowFilePickerAsyncWrapper(const nsAString& a0, int64_t a1) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::ShowFilePickerAsyncWrapper(const nsAString& a0, int64_t a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     env->CallStaticVoidMethod(mGeckoAppShellClass, jShowFilePickerAsyncWrapper, j0, a1);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-jstring AndroidBridge::ShowFilePickerForExtensionsWrapper(const nsAString& a0) {
-    JNIEnv *env = GetJNIEnv();
+jstring GeckoAppShell::ShowFilePickerForExtensionsWrapper(const nsAString& a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return nullptr;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jShowFilePickerForExtensionsWrapper, j0);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
     return ret;
 }
 
-jstring AndroidBridge::ShowFilePickerForMimeTypeWrapper(const nsAString& a0) {
-    JNIEnv *env = GetJNIEnv();
+jstring GeckoAppShell::ShowFilePickerForMimeTypeWrapper(const nsAString& a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return nullptr;
     }
 
     if (env->PushLocalFrame(2) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         return nullptr;
     }
 
-    jstring j0 = NewJavaString(env, a0);
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
 
     jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jShowFilePickerForMimeTypeWrapper, j0);
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return nullptr;
     }
+
     jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
     return ret;
 }
 
-void AndroidBridge::ShowInputMethodPicker() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::ShowInputMethodPicker() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -2137,21 +2255,22 @@ void AndroidBridge::ShowInputMethodPicke
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-bool AndroidBridge::UnlockProfile() {
-    JNIEnv *env = GetJNIEnv();
+bool GeckoAppShell::UnlockProfile() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return false;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -2163,22 +2282,23 @@ bool AndroidBridge::UnlockProfile() {
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return false;
     }
+
     env->PopLocalFrame(NULL);
     return temp;
 }
 
-void AndroidBridge::UnlockScreenOrientation() {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::UnlockScreenOrientation() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -2190,20 +2310,21 @@ void AndroidBridge::UnlockScreenOrientat
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::UnregisterSurfaceTextureFrameListener(jobject a0) {
+void GeckoAppShell::UnregisterSurfaceTextureFrameListener(jobject a0) {
     JNIEnv *env = GetJNIForThread();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
@@ -2216,21 +2337,22 @@ void AndroidBridge::UnregisterSurfaceTex
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::Vibrate1(int64_t a0) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::Vibrate1(int64_t a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(0) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -2242,21 +2364,22 @@ void AndroidBridge::Vibrate1(int64_t a0)
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
 
-void AndroidBridge::VibrateA(jlongArray a0, int32_t a1) {
-    JNIEnv *env = GetJNIEnv();
+void GeckoAppShell::VibrateA(jlongArray a0, int32_t a1) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
     if (!env) {
         ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
         return;
     }
 
     if (env->PushLocalFrame(1) != 0) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
@@ -2268,20 +2391,219 @@ void AndroidBridge::VibrateA(jlongArray 
 
     if (env->ExceptionCheck()) {
         ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
         env->ExceptionDescribe();
         env->ExceptionClear();
         env->PopLocalFrame(NULL);
         return;
     }
+
     env->PopLocalFrame(NULL);
 }
-
-jstring AndroidBridge::GetFrameNameJavaProfilingWrapper(int32_t a0, int32_t a1, int32_t a2) {
+jclass JavaDomKeyLocation::mDomKeyLocationClass = 0;
+jmethodID JavaDomKeyLocation::jvalueOf = 0;
+jmethodID JavaDomKeyLocation::jvalues = 0;
+jfieldID JavaDomKeyLocation::jDOM_KEY_LOCATION_JOYSTICK = 0;
+jfieldID JavaDomKeyLocation::jDOM_KEY_LOCATION_LEFT = 0;
+jfieldID JavaDomKeyLocation::jDOM_KEY_LOCATION_MOBILE = 0;
+jfieldID JavaDomKeyLocation::jDOM_KEY_LOCATION_NUMPAD = 0;
+jfieldID JavaDomKeyLocation::jDOM_KEY_LOCATION_RIGHT = 0;
+jfieldID JavaDomKeyLocation::jDOM_KEY_LOCATION_STANDARD = 0;
+jfieldID JavaDomKeyLocation::jvalue = 0;
+void JavaDomKeyLocation::InitStubs(JNIEnv *jEnv) {
+    initInit();
+
+    mDomKeyLocationClass = getClassGlobalRef("org/mozilla/gecko/GeckoEvent$DomKeyLocation");
+    jvalueOf = getStaticMethod("valueOf", "(Ljava/lang/String;)Lorg/mozilla/gecko/GeckoEvent$DomKeyLocation;");
+    jvalues = getStaticMethod("values", "()[Lorg/mozilla/gecko/GeckoEvent$DomKeyLocation;");
+    jDOM_KEY_LOCATION_JOYSTICK = getStaticField("DOM_KEY_LOCATION_JOYSTICK", "Lorg/mozilla/gecko/GeckoEvent$DomKeyLocation;");
+    jDOM_KEY_LOCATION_LEFT = getStaticField("DOM_KEY_LOCATION_LEFT", "Lorg/mozilla/gecko/GeckoEvent$DomKeyLocation;");
+    jDOM_KEY_LOCATION_MOBILE = getStaticField("DOM_KEY_LOCATION_MOBILE", "Lorg/mozilla/gecko/GeckoEvent$DomKeyLocation;");
+    jDOM_KEY_LOCATION_NUMPAD = getStaticField("DOM_KEY_LOCATION_NUMPAD", "Lorg/mozilla/gecko/GeckoEvent$DomKeyLocation;");
+    jDOM_KEY_LOCATION_RIGHT = getStaticField("DOM_KEY_LOCATION_RIGHT", "Lorg/mozilla/gecko/GeckoEvent$DomKeyLocation;");
+    jDOM_KEY_LOCATION_STANDARD = getStaticField("DOM_KEY_LOCATION_STANDARD", "Lorg/mozilla/gecko/GeckoEvent$DomKeyLocation;");
+    jvalue = getField("value", "I");
+}
+
+JavaDomKeyLocation* JavaDomKeyLocation::Wrap(jobject obj) {
+    JNIEnv *env = GetJNIForThread();
+
+    if (!env) {
+        ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
+        return NULL;
+    }
+
+    JavaDomKeyLocation* ret = new JavaDomKeyLocation(obj, env);
+    env->DeleteLocalRef(obj);
+    return ret;
+}
+
+jobject JavaDomKeyLocation::valueOf(const nsAString& a0) {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env) {
+        ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
+        return nullptr;
+    }
+
+    if (env->PushLocalFrame(2) != 0) {
+        ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+        return nullptr;
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    jobject temp = env->CallStaticObjectMethod(mDomKeyLocationClass, jvalueOf, j0);
+
+    if (env->ExceptionCheck()) {
+        ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+        env->PopLocalFrame(NULL);
+        return nullptr;
+    }
+
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobjectArray JavaDomKeyLocation::values() {
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env) {
+        ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
+        return nullptr;
+    }
+
+    if (env->PushLocalFrame(1) != 0) {
+        ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+        return nullptr;
+    }
+
+    jobject temp = env->CallStaticObjectMethod(mDomKeyLocationClass, jvalues);
+
+    if (env->ExceptionCheck()) {
+        ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+        env->PopLocalFrame(NULL);
+        return nullptr;
+    }
+
+    jobjectArray ret = static_cast<jobjectArray>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject JavaDomKeyLocation::getDOM_KEY_LOCATION_JOYSTICK() {
+    JNIEnv *env = GetJNIForThread();
+    if (!env) {
+        ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
+        return nullptr;
+    }
+
+    return static_cast<jobject>(env->GetStaticObjectField(mDomKeyLocationClass, jDOM_KEY_LOCATION_JOYSTICK));
+}
+
+jobject JavaDomKeyLocation::getDOM_KEY_LOCATION_LEFT() {
+    JNIEnv *env = GetJNIForThread();
+    if (!env) {
+        ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
+        return nullptr;
+    }
+
+    return static_cast<jobject>(env->GetStaticObjectField(mDomKeyLocationClass, jDOM_KEY_LOCATION_LEFT));
+}
+
+jobject JavaDomKeyLocation::getDOM_KEY_LOCATION_MOBILE() {
+    JNIEnv *env = GetJNIForThread();
+    if (!env) {
+        ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
+        return nullptr;
+    }
+
+    return static_cast<jobject>(env->GetStaticObjectField(mDomKeyLocationClass, jDOM_KEY_LOCATION_MOBILE));
+}
+