Merge fx-team to m-c
authorWes Kocher <wkocher@mozilla.com>
Thu, 21 Nov 2013 19:16:50 -0800
changeset 156937 dbf94e314cde175900e0d95d211f7d163bafe4c9
parent 156918 d93ca560b15c3473400f16fc7b5661b6a9f907d5 (current diff)
parent 156936 5c11b81a0c9191ad78786fcd28c361d0f23d52a6 (diff)
child 156983 7a703a1f974b5f3c44b11e40699013d47d57748c
child 157013 cff1826bfddbe9c33ae0d91c0cac57f0e2c27303
child 157025 b2a0444bc991771fb68e92937c5b011586fee98d
child 161492 bd5d668bbac482e5203a1cfef5a8c208e94e9ba4
push id25693
push userkwierso@gmail.com
push dateFri, 22 Nov 2013 03:17:02 +0000
treeherdermozilla-central@dbf94e314cde [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));
+}
+
+jobject JavaDomKeyLocation::getDOM_KEY_LOCATION_NUMPAD() {
+    JNIEnv *env = GetJNIForThread();
+    if (!env) {
+        ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
+        return nullptr;
+    }