summaryrefslogtreecommitdiffstats
path: root/mobile/android/modules/JavaAddonManager.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/modules/JavaAddonManager.jsm')
-rw-r--r--mobile/android/modules/JavaAddonManager.jsm115
1 files changed, 115 insertions, 0 deletions
diff --git a/mobile/android/modules/JavaAddonManager.jsm b/mobile/android/modules/JavaAddonManager.jsm
new file mode 100644
index 000000000..a24535ede
--- /dev/null
+++ b/mobile/android/modules/JavaAddonManager.jsm
@@ -0,0 +1,115 @@
+// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
+/* 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/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["JavaAddonManager"];
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components; /*global Components */
+
+Cu.import("resource://gre/modules/Messaging.jsm"); /*global Messaging */
+Cu.import("resource://gre/modules/Services.jsm"); /*global Services */
+
+function resolveGeckoURI(uri) {
+ if (!uri) {
+ throw new Error("Can't resolve an empty uri");
+ }
+ if (uri.startsWith("chrome://")) {
+ let registry = Cc['@mozilla.org/chrome/chrome-registry;1'].getService(Ci["nsIChromeRegistry"]);
+ return registry.convertChromeURL(Services.io.newURI(uri, null, null)).spec;
+ } else if (uri.startsWith("resource://")) {
+ let handler = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
+ return handler.resolveURI(Services.io.newURI(uri, null, null));
+ }
+ return uri;
+}
+
+/**
+ * A promise-based API
+ */
+var JavaAddonManager = Object.freeze({
+ classInstanceFromFile: function(classname, filename) {
+ if (!classname) {
+ throw new Error("classname cannot be null");
+ }
+ if (!filename) {
+ throw new Error("filename cannot be null");
+ }
+ return Messaging.sendRequestForResult({
+ type: "JavaAddonManagerV1:Load",
+ classname: classname,
+ filename: resolveGeckoURI(filename)
+ })
+ .then((guid) => {
+ if (!guid) {
+ throw new Error("Internal error: guid should not be null");
+ }
+ return new JavaAddonV1({classname: classname, guid: guid});
+ });
+ }
+});
+
+function JavaAddonV1(options = {}) {
+ if (!(this instanceof JavaAddonV1)) {
+ return new JavaAddonV1(options);
+ }
+ if (!options.classname) {
+ throw new Error("options.classname cannot be null");
+ }
+ if (!options.guid) {
+ throw new Error("options.guid cannot be null");
+ }
+ this._classname = options.classname;
+ this._guid = options.guid;
+ this._loaded = true;
+ this._listeners = {};
+}
+
+JavaAddonV1.prototype = Object.freeze({
+ unload: function() {
+ if (!this._loaded) {
+ return;
+ }
+
+ Messaging.sendRequestForResult({
+ type: "JavaAddonManagerV1:Unload",
+ guid: this._guid
+ })
+ .then(() => {
+ this._loaded = false;
+ for (let listener of this._listeners) {
+ // If we use this.removeListener, we prefix twice.
+ Messaging.removeListener(listener);
+ }
+ this._listeners = {};
+ });
+ },
+
+ _prefix: function(message) {
+ let newMessage = Cu.cloneInto(message, {}, { cloneFunctions: false });
+ newMessage.type = this._guid + ":" + message.type;
+ return newMessage;
+ },
+
+ sendRequest: function(message) {
+ return Messaging.sendRequest(this._prefix(message));
+ },
+
+ sendRequestForResult: function(message) {
+ return Messaging.sendRequestForResult(this._prefix(message));
+ },
+
+ addListener: function(listener, message) {
+ let prefixedMessage = this._guid + ":" + message;
+ this._listeners[prefixedMessage] = listener;
+ return Messaging.addListener(listener, prefixedMessage);
+ },
+
+ removeListener: function(message) {
+ let prefixedMessage = this._guid + ":" + message;
+ delete this._listeners[prefixedMessage];
+ return Messaging.removeListener(prefixedMessage);
+ }
+});