tenfourfox/dom/apps/AndroidUtils.jsm

125 lines
4.0 KiB
JavaScript

/* 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/. */
const { interfaces: Ci, utils: Cu } = Components;
this.EXPORTED_SYMBOLS = ["AndroidUtils"];
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Messaging",
"resource://gre/modules/Messaging.jsm");
var appsRegistry = null;
function debug() {
//dump("-*- AndroidUtils " + Array.slice(arguments) + "\n");
}
// Helper functions to manage Android native apps. We keep them in the
// registry with a `kind` equals to "android-native" and we also store
// the package name and class name in the registry.
// Communication with the android side happens through json messages.
this.AndroidUtils = {
init: function(aRegistry) {
appsRegistry = aRegistry;
Services.obs.addObserver(this, "Android:Apps:Installed", false);
Services.obs.addObserver(this, "Android:Apps:Uninstalled", false);
},
uninit: function() {
Services.obs.removeObserver(this, "Android:Apps:Installed");
Services.obs.removeObserver(this, "Android:Apps:Uninstalled");
},
getOriginAndManifestURL: function(aPackageName) {
let origin = "android://" + aPackageName.toLowerCase();
let manifestURL = origin + "/manifest.webapp";
return [origin, manifestURL];
},
getPackageAndClassFromManifestURL: function(aManifestURL) {
debug("getPackageAndClassFromManifestURL " + aManifestURL);
let app = appsRegistry.getAppByManifestURL(aManifestURL);
if (!app) {
debug("No app for " + aManifestURL);
return [];
}
return [app.android_packagename, app.android_classname];
},
buildAndroidAppData: function(aApp) {
// Use the package and class name to get a unique origin.
// We put the version with the normal case as part of the manifest url.
let [origin, manifestURL] =
this.getOriginAndManifestURL(aApp.packagename);
// We choose 96 as an arbitrary size since we can only get one icon
// from Android.
let manifest = {
name: aApp.name,
icons: { "96": aApp.icon }
}
debug("Origin is " + origin);
let appData = {
app: {
installOrigin: origin,
origin: origin,
manifest: manifest,
manifestURL: manifestURL,
manifestHash: AppsUtils.computeHash(JSON.stringify(manifest)),
appStatus: Ci.nsIPrincipal.APP_STATUS_INSTALLED,
removable: aApp.removable,
android_packagename: aApp.packagename,
android_classname: aApp.classname
},
isBrowser: false,
isPackage: false
};
return appData;
},
installAndroidApps: function() {
return Messaging.sendRequestForResult({ type: "Apps:GetList" }).then(
aApps => {
debug("Got " + aApps.apps.length + " android apps.");
let promises = [];
aApps.apps.forEach(app => {
debug("App is " + app.name + " removable? " + app.removable);
let p = new Promise((aResolveInstall, aRejectInstall) => {
let appData = this.buildAndroidAppData(app);
appsRegistry.confirmInstall(appData, null, aResolveInstall);
});
promises.push(p);
});
// Wait for all apps to be installed.
return Promise.all(promises);
}
).then(appsRegistry._saveApps.bind(appsRegistry));
},
observe: function(aSubject, aTopic, aData) {
let data;
try {
data = JSON.parse(aData);
} catch(e) {
debug(e);
return;
}
if (aTopic == "Android:Apps:Installed") {
let appData = this.buildAndroidAppData(data);
appsRegistry.confirmInstall(appData);
} else if (aTopic == "Android:Apps:Uninstalled") {
let [origin, manifestURL] =
this.getOriginAndManifestURL(data.packagename);
appsRegistry.uninstall(manifestURL);
}
},
}