mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 777402 - Implement support for packaged apps via the installPackage function in the mozapps DOM API in desktop web runtime. r=myk,wesj,fabrice
This commit is contained in:
parent
9be674ac0e
commit
19539a7071
@ -106,15 +106,21 @@ this.webappsUI = {
|
||||
label: bundle.getString("webapps.install"),
|
||||
accessKey: bundle.getString("webapps.install.accesskey"),
|
||||
callback: function() {
|
||||
let app = WebappsInstaller.install(aData);
|
||||
let app = WebappsInstaller.init(aData);
|
||||
|
||||
if (app) {
|
||||
let localDir = null;
|
||||
if (app.appProfile) {
|
||||
localDir = app.appProfile.localDir;
|
||||
}
|
||||
|
||||
DOMApplicationRegistry.confirmInstall(aData, false, localDir);
|
||||
installationSuccessNotification(aData, app, aWindow);
|
||||
DOMApplicationRegistry.confirmInstall(aData, false, localDir, null,
|
||||
function (aManifest) {
|
||||
if (WebappsInstaller.install(aData, aManifest)) {
|
||||
installationSuccessNotification(aData, app, aWindow);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
DOMApplicationRegistry.denyInstall(aData);
|
||||
}
|
||||
@ -122,7 +128,8 @@ this.webappsUI = {
|
||||
};
|
||||
|
||||
let requestingURI = aWindow.makeURI(aData.from);
|
||||
let manifest = new ManifestHelper(aData.app.manifest, aData.app.origin);
|
||||
let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
|
||||
let manifest = new ManifestHelper(jsonManifest, aData.app.origin);
|
||||
|
||||
let host;
|
||||
try {
|
||||
|
@ -118,19 +118,9 @@ WebappsRegistry.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
// mozIDOMApplicationRegistry implementation
|
||||
|
||||
install: function(aURL, aParams) {
|
||||
let uri = this._validateURL(aURL);
|
||||
|
||||
let request = this.createRequest();
|
||||
|
||||
if (!this._ensureForeground(request)) {
|
||||
return request;
|
||||
}
|
||||
|
||||
_prepareInstall: function(aURL, aRequest, aParams, isPackage) {
|
||||
let installURL = this._window.location.href;
|
||||
let requestID = this.getRequestId(request);
|
||||
let requestID = this.getRequestId(aRequest);
|
||||
let receipts = (aParams && aParams.receipts &&
|
||||
Array.isArray(aParams.receipts)) ? aParams.receipts
|
||||
: [];
|
||||
@ -139,20 +129,36 @@ WebappsRegistry.prototype = {
|
||||
: [];
|
||||
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
cpmm.sendAsyncMessage("Webapps:Install",
|
||||
{ app: {
|
||||
installOrigin: this._getOrigin(installURL),
|
||||
origin: this._getOrigin(uri),
|
||||
manifestURL: uri,
|
||||
receipts: receipts,
|
||||
categories: categories
|
||||
},
|
||||
from: installURL,
|
||||
oid: this._id,
|
||||
requestID: requestID,
|
||||
appId: principal.appId,
|
||||
isBrowser: principal.isInBrowserElement
|
||||
});
|
||||
|
||||
return { app: {
|
||||
installOrigin: this._getOrigin(installURL),
|
||||
origin: this._getOrigin(aURL),
|
||||
manifestURL: aURL,
|
||||
receipts: receipts,
|
||||
categories: categories
|
||||
},
|
||||
|
||||
from: installURL,
|
||||
oid: this._id,
|
||||
requestID: requestID,
|
||||
appId: principal.appId,
|
||||
isBrowser: principal.isInBrowserElement,
|
||||
isPackage: isPackage
|
||||
};
|
||||
},
|
||||
|
||||
// mozIDOMApplicationRegistry implementation
|
||||
|
||||
install: function(aURL, aParams) {
|
||||
let uri = this._validateURL(aURL);
|
||||
|
||||
let request = this.createRequest();
|
||||
|
||||
if (this._ensureForeground(request)) {
|
||||
cpmm.sendAsyncMessage("Webapps:Install",
|
||||
this._prepareInstall(uri, request, aParams, false));
|
||||
}
|
||||
|
||||
return request;
|
||||
},
|
||||
|
||||
@ -201,42 +207,16 @@ WebappsRegistry.prototype = {
|
||||
["Webapps:Install:Return:OK"]);
|
||||
},
|
||||
|
||||
// mozIDOMApplicationRegistry2 implementation
|
||||
|
||||
installPackage: function(aURL, aParams) {
|
||||
let uri = this._validateURL(aURL);
|
||||
|
||||
let request = this.createRequest();
|
||||
|
||||
if (!this._ensureForeground(request)) {
|
||||
return request;
|
||||
if (this._ensureForeground(request)) {
|
||||
cpmm.sendAsyncMessage("Webapps:InstallPackage",
|
||||
this._prepareInstall(uri, request, aParams, true));
|
||||
}
|
||||
|
||||
let installURL = this._window.location.href;
|
||||
let requestID = this.getRequestId(request);
|
||||
let receipts = (aParams && aParams.receipts &&
|
||||
Array.isArray(aParams.receipts)) ? aParams.receipts
|
||||
: [];
|
||||
let categories = (aParams && aParams.categories &&
|
||||
Array.isArray(aParams.categories)) ? aParams.categories
|
||||
: [];
|
||||
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
cpmm.sendAsyncMessage("Webapps:InstallPackage",
|
||||
{ app: {
|
||||
installOrigin: this._getOrigin(installURL),
|
||||
origin: this._getOrigin(uri),
|
||||
manifestURL: uri,
|
||||
receipts: receipts,
|
||||
categories: categories
|
||||
},
|
||||
from: installURL,
|
||||
oid: this._id,
|
||||
requestID: requestID,
|
||||
isPackage: true,
|
||||
appId: principal.appId,
|
||||
isBrowser: principal.isInBrowserElement
|
||||
});
|
||||
return request;
|
||||
},
|
||||
|
||||
@ -266,22 +246,13 @@ WebappsRegistry.prototype = {
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
|
||||
Ci.mozIDOMApplicationRegistry,
|
||||
#ifdef MOZ_B2G
|
||||
Ci.mozIDOMApplicationRegistry2,
|
||||
#elifdef MOZ_WIDGET_ANDROID
|
||||
Ci.mozIDOMApplicationRegistry2,
|
||||
#endif
|
||||
Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
|
||||
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"),
|
||||
contractID: "@mozilla.org/webapps;1",
|
||||
interfaces: [Ci.mozIDOMApplicationRegistry,
|
||||
#ifdef MOZ_B2G
|
||||
Ci.mozIDOMApplicationRegistry2,
|
||||
#elifdef MOZ_WIDGET_ANDROID
|
||||
Ci.mozIDOMApplicationRegistry2,
|
||||
#endif
|
||||
],
|
||||
Ci.mozIDOMApplicationRegistry2],
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
classDescription: "Webapps Registry"})
|
||||
}
|
||||
|
@ -1841,15 +1841,6 @@ this.DOMApplicationRegistry = {
|
||||
app.installOrigin + ": " + aError);
|
||||
}.bind(this);
|
||||
|
||||
// Disallow reinstalls from the same manifest URL for now.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=821288
|
||||
if (this.getAppLocalIdByManifestURL(app.manifestURL) !==
|
||||
Ci.nsIScriptSecurityManager.NO_APP_ID ||
|
||||
this._appId(app.origin) !== null) {
|
||||
sendError("REINSTALL_FORBIDDEN");
|
||||
return;
|
||||
}
|
||||
|
||||
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
xhr.open("GET", app.manifestURL, true);
|
||||
@ -1872,6 +1863,13 @@ this.DOMApplicationRegistry = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disallow reinstalls from the same manifest URL for now.
|
||||
if (this._appIdForManifestURL(app.manifestURL) !== null &&
|
||||
this._isLaunchable(app)) {
|
||||
sendError("REINSTALL_FORBIDDEN");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(AppsUtils.checkManifest(manifest, app) &&
|
||||
manifest.package_path)) {
|
||||
sendError("INVALID_MANIFEST");
|
||||
@ -1988,7 +1986,7 @@ this.DOMApplicationRegistry = {
|
||||
appObject.id = id;
|
||||
appObject.localId = localId;
|
||||
appObject.basePath = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], true, true).path;
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
|
||||
let dir = this._getAppDir(id);
|
||||
let manFile = dir.clone();
|
||||
manFile.append(manifestName);
|
||||
let jsonManifest = aData.isPackage ? app.updateManifest : app.manifest;
|
||||
@ -2062,7 +2060,7 @@ this.DOMApplicationRegistry = {
|
||||
if (!aData.isPackage) {
|
||||
this.updateAppHandlers(null, app.manifest, app);
|
||||
if (aInstallSuccessCallback) {
|
||||
aInstallSuccessCallback(manifest);
|
||||
aInstallSuccessCallback(app.manifest);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2074,7 +2072,7 @@ this.DOMApplicationRegistry = {
|
||||
// Success! Move the zip out of TmpD.
|
||||
let app = DOMApplicationRegistry.webapps[aId];
|
||||
let zipFile = FileUtils.getFile("TmpD", ["webapps", aId, "application.zip"], true);
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", aId], true, true);
|
||||
let dir = this._getAppDir(id);
|
||||
zipFile.moveTo(dir, "application.zip");
|
||||
let tmpDir = FileUtils.getDir("TmpD", ["webapps", aId], true, true);
|
||||
try {
|
||||
|
@ -7,11 +7,8 @@
|
||||
EXTRA_COMPONENTS += [
|
||||
'AppsService.js',
|
||||
'AppsService.manifest',
|
||||
'Webapps.manifest',
|
||||
]
|
||||
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'Webapps.js',
|
||||
'Webapps.manifest',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
|
@ -138,7 +138,7 @@ interface mozIDOMApplicationMgmt : nsISupports
|
||||
nsIDOMDOMRequest uninstall(in mozIDOMApplication app);
|
||||
};
|
||||
|
||||
[scriptable, uuid(abfc6c15-8b92-4b9a-b892-52e6ae76f379)]
|
||||
[scriptable, uuid(52710c5f-b2a2-4b27-b5b9-f679a1bcc79b)]
|
||||
interface mozIDOMApplicationRegistry : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -169,5 +169,18 @@ interface mozIDOMApplicationRegistry : nsISupports
|
||||
*/
|
||||
nsIDOMDOMRequest getInstalled();
|
||||
|
||||
/**
|
||||
* Install a packaged web app.
|
||||
*
|
||||
* @param packageUrl : the URL of the webapps manifest.
|
||||
* @param parameters : A structure with optional information.
|
||||
* {
|
||||
* receipts: ... Will be used to specify the payment receipts for this installation.
|
||||
* categories: ... Will be used to specify the categories of the webapp.
|
||||
* }
|
||||
* @returns : A DOMRequest object, returning the app object in |result| if install succeeds.
|
||||
*/
|
||||
nsIDOMDOMRequest installPackage(in DOMString packageUrl, [optional] in jsval parameters);
|
||||
|
||||
readonly attribute mozIDOMApplicationMgmt mgmt;
|
||||
};
|
||||
|
@ -6,19 +6,8 @@
|
||||
|
||||
interface nsIDOMDOMRequest;
|
||||
|
||||
[scriptable, uuid(34498a66-3aee-4b80-8b8b-a9c5d5ba32b6)]
|
||||
// This interface is still here for backwards compatibility.
|
||||
[scriptable, uuid(5bd838b2-cf3d-406e-bbef-f633cf9e68de)]
|
||||
interface mozIDOMApplicationRegistry2 : mozIDOMApplicationRegistry
|
||||
{
|
||||
/**
|
||||
* Install a packaged web app.
|
||||
*
|
||||
* @param packageUrl : the URL of the webapps manifest.
|
||||
* @param parameters : A structure with optional information.
|
||||
* {
|
||||
* receipts: ... Will be used to specify the payment receipts for this installation.
|
||||
* categories: ... Will be used to specify the categories of the webapp.
|
||||
* }
|
||||
* @returns : A DOMRequest object, returning the app object in |result| if install succeeds.
|
||||
*/
|
||||
nsIDOMDOMRequest installPackage(in DOMString packageUrl, [optional] in jsval parameters);
|
||||
};
|
||||
|
@ -24,7 +24,6 @@ var steps = [
|
||||
invalidManifest,
|
||||
permissionDenied,
|
||||
invalidContent,
|
||||
installPackageNotImplemented,
|
||||
invalidLaunchPath,
|
||||
invalidLaunchPath2,
|
||||
invalidEntryPoint,
|
||||
@ -167,12 +166,6 @@ function invalidMessage(next) {
|
||||
};
|
||||
}
|
||||
|
||||
function installPackageNotImplemented(next) {
|
||||
ok(!("installPackage" in navigator.mozApps),
|
||||
"installPackage not in navigator.mozApps");
|
||||
next();
|
||||
}
|
||||
|
||||
function fileURL(next) {
|
||||
try {
|
||||
navigator.mozApps.install("file:///nonexistent");
|
||||
|
@ -24,6 +24,7 @@ var props = {
|
||||
getInstalled: "function",
|
||||
getSelf: "function",
|
||||
install: "function",
|
||||
installPackage: "function",
|
||||
mgmt: "object",
|
||||
};
|
||||
|
||||
|
@ -6722,10 +6722,9 @@ var WebappsUI = {
|
||||
doInstall: function doInstall(aData) {
|
||||
let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
|
||||
let manifest = new ManifestHelper(jsonManifest, aData.app.origin);
|
||||
let name = manifest.name ? manifest.name : manifest.fullLaunchPath();
|
||||
let showPrompt = true;
|
||||
|
||||
if (!showPrompt || Services.prompt.confirm(null, Strings.browser.GetStringFromName("webapps.installTitle"), name + "\n" + aData.app.origin)) {
|
||||
if (!showPrompt || Services.prompt.confirm(null, Strings.browser.GetStringFromName("webapps.installTitle"), manifest.name + "\n" + aData.app.origin)) {
|
||||
// Get a profile for the app to be installed in. We'll download everything before creating the icons.
|
||||
let origin = aData.app.origin;
|
||||
let profilePath = sendMessageToJava({
|
||||
@ -6737,10 +6736,12 @@ var WebappsUI = {
|
||||
if (profilePath) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(profilePath);
|
||||
|
||||
|
||||
let self = this;
|
||||
DOMApplicationRegistry.confirmInstall(aData, false, file, null,
|
||||
function (manifest) {
|
||||
function (aManifest) {
|
||||
let localeManifest = new ManifestHelper(aManifest, aData.app.origin);
|
||||
|
||||
// the manifest argument is the manifest from within the zip file,
|
||||
// TODO so now would be a good time to ask about permissions.
|
||||
self.makeBase64Icon(self.getBiggestIcon(manifest.icons, Services.io.newURI(aData.app.origin, null, null)),
|
||||
@ -6760,7 +6761,7 @@ var WebappsUI = {
|
||||
// aData.app.origin may now point to the app: url that hosts this app
|
||||
sendMessageToJava({
|
||||
type: "WebApps:PostInstall",
|
||||
name: manifest.name,
|
||||
name: localeManifest.name,
|
||||
manifestURL: aData.app.manifestURL,
|
||||
originalOrigin: origin,
|
||||
origin: aData.app.origin,
|
||||
@ -6770,7 +6771,7 @@ var WebappsUI = {
|
||||
// For packaged apps, put a notification in the notification bar.
|
||||
let message = Strings.browser.GetStringFromName("webapps.alertSuccess");
|
||||
let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
alerts.showAlertNotification("drawable://alert_app", manifest.name, message, true, "", {
|
||||
alerts.showAlertNotification("drawable://alert_app", localeManifest.name, message, true, "", {
|
||||
observe: function () {
|
||||
self.openURL(aData.app.manifestURL, aData.app.origin);
|
||||
}
|
||||
@ -6779,7 +6780,7 @@ var WebappsUI = {
|
||||
} catch(ex) {
|
||||
console.log(ex);
|
||||
}
|
||||
self.writeDefaultPrefs(file, manifest);
|
||||
self.writeDefaultPrefs(file, localeManifest);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ class WebappCollection(object):
|
||||
"""A list-like object that collects webapps and updates the webapp manifests"""
|
||||
|
||||
json_template = Template(""""$name": {
|
||||
"name": "$name",
|
||||
"origin": "$origin",
|
||||
"installOrigin": "$origin",
|
||||
"receipt": null,
|
||||
|
@ -21,13 +21,18 @@ this.WebappOSUtils = {
|
||||
// doesn't have a name property. We then need to use the manifest.
|
||||
// For some mozApps calls, the aApp object doesn't have a manifest
|
||||
// associated, and so we need to use the name property.
|
||||
// They're guaranteed to be always identical to the application
|
||||
// name in the user locale.
|
||||
if (aApp.name) {
|
||||
name = aApp.name;
|
||||
} else {
|
||||
name = aApp.manifest.name;
|
||||
let manifest =
|
||||
new ManifestHelper(aApp.updateManifest || aApp.manifest, aApp.origin);
|
||||
name = manifest.name;
|
||||
}
|
||||
|
||||
return this.sanitizeStringForFilename(name).toLowerCase() + "-" + AppsUtils.computeHash(aApp.manifestURL);
|
||||
return this.sanitizeStringForFilename(name).toLowerCase() + "-" +
|
||||
AppsUtils.computeHash(aApp.manifestURL);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -17,113 +17,174 @@ Cu.import("resource://gre/modules/WebappOSUtils.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
|
||||
this.WebappsInstaller = {
|
||||
shell: null,
|
||||
|
||||
/**
|
||||
* Initializes the app object that takes care of the installation
|
||||
* and creates the profile directory for an application
|
||||
*
|
||||
* @param aData the data provided to the install function
|
||||
*
|
||||
* @returns NativeApp on success, null on error
|
||||
*/
|
||||
init: function(aData) {
|
||||
#ifdef XP_WIN
|
||||
this.shell = new WinNativeApp(aData);
|
||||
#elifdef XP_MACOSX
|
||||
this.shell = new MacNativeApp(aData);
|
||||
#elifdef XP_UNIX
|
||||
this.shell = new LinuxNativeApp(aData);
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("browser.mozApps.installer.dry_run")) {
|
||||
return this.shell;
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
try {
|
||||
this.shell.createAppProfile();
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error installing app: " + ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.shell;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a native installation of the web app in the OS
|
||||
*
|
||||
* @param aData the manifest data provided by the web app
|
||||
* @param aData the data provided to the install function
|
||||
* @param aManifest the manifest data provided by the web app
|
||||
*
|
||||
* @returns bool true on success, false if an error was thrown
|
||||
* @returns true on success, false if an error was thrown
|
||||
*/
|
||||
install: function(aData) {
|
||||
|
||||
install: function(aData, aManifest) {
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("browser.mozApps.installer.dry_run")) {
|
||||
return true;
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
#ifdef XP_WIN
|
||||
let shell = new WinNativeApp(aData);
|
||||
#elifdef XP_MACOSX
|
||||
let shell = new MacNativeApp(aData);
|
||||
#elifdef XP_UNIX
|
||||
let shell = new LinuxNativeApp(aData);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
this.shell.init(aData, aManifest);
|
||||
|
||||
try {
|
||||
shell.install();
|
||||
this.shell.install();
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error installing app: " + ex);
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
let data = {
|
||||
"installDir": shell.installDir.path,
|
||||
"app": aData.app
|
||||
"installDir": this.shell.installDir.path,
|
||||
"app": {
|
||||
"manifest": aManifest,
|
||||
"origin": aData.app.origin
|
||||
}
|
||||
};
|
||||
Services.obs.notifyObservers(null, "webapp-installed", JSON.stringify(data));
|
||||
|
||||
return shell;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function implements the common constructor for
|
||||
* the Windows, Mac and Linux native app shells. It reads and parses
|
||||
* the data from the app manifest and stores it in the NativeApp
|
||||
* object. It's meant to be called as NativeApp.call(this, aData)
|
||||
* from the platform-specific constructor.
|
||||
* the Windows, Mac and Linux native app shells. It sets
|
||||
* the app unique name. It's meant to be called as
|
||||
* NativeApp.call(this, aData) from the platform-specific
|
||||
* constructor.
|
||||
*
|
||||
* @param aData the data object provided by the web app with
|
||||
* all the app settings and specifications.
|
||||
* @param aData the data object provided to the install function
|
||||
*
|
||||
*/
|
||||
function NativeApp(aData) {
|
||||
let app = this.app = aData.app;
|
||||
this.uniqueName = WebappOSUtils.getUniqueName(aData.app);
|
||||
|
||||
this.uniqueName = WebappOSUtils.getUniqueName(app);
|
||||
let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
|
||||
let manifest = new ManifestHelper(jsonManifest, aData.app.origin);
|
||||
|
||||
let origin = Services.io.newURI(app.origin, null, null);
|
||||
|
||||
let biggestIcon = getBiggestIconURL(app.manifest.icons);
|
||||
try {
|
||||
let iconURI = Services.io.newURI(biggestIcon, null, null);
|
||||
if (iconURI.scheme == "data") {
|
||||
this.iconURI = iconURI;
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
if (!this.iconURI) {
|
||||
try {
|
||||
this.iconURI = Services.io.newURI(origin.resolve(biggestIcon), null, null);
|
||||
}
|
||||
catch (ex) {}
|
||||
}
|
||||
|
||||
this.appName = sanitize(app.manifest.name);
|
||||
this.appName = sanitize(manifest.name);
|
||||
this.appNameAsFilename = stripStringForFilename(this.appName);
|
||||
|
||||
if(app.manifest.developer && app.manifest.developer.name) {
|
||||
let devName = app.manifest.developer.name.substr(0, 128);
|
||||
devName = sanitize(devName);
|
||||
if (devName) {
|
||||
this.developerName = devName;
|
||||
}
|
||||
}
|
||||
|
||||
let shortDesc = this.appName;
|
||||
if (app.manifest.description) {
|
||||
let firstLine = app.manifest.description.split("\n")[0];
|
||||
shortDesc = firstLine.length <= 256
|
||||
? firstLine
|
||||
: firstLine.substr(0, 253) + "...";
|
||||
}
|
||||
this.shortDescription = sanitize(shortDesc);
|
||||
|
||||
// The app registry is the Firefox profile from which the app
|
||||
// was installed.
|
||||
this.registryFolder = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
this.webappJson = {
|
||||
"registryDir": this.registryFolder.path,
|
||||
"app": app
|
||||
};
|
||||
|
||||
this.runtimeFolder = Services.dirsvc.get("GreD", Ci.nsIFile);
|
||||
}
|
||||
|
||||
NativeApp.prototype = {
|
||||
uniqueName: null,
|
||||
appName: null,
|
||||
appNameAsFilename: null,
|
||||
iconURI: null,
|
||||
developerName: null,
|
||||
shortDescription: null,
|
||||
categories: null,
|
||||
webappJson: null,
|
||||
runtimeFolder: null,
|
||||
|
||||
/**
|
||||
* This function reads and parses the data from the app
|
||||
* manifest and stores it in the NativeApp object.
|
||||
*
|
||||
* @param aData the data object provided to the install function
|
||||
* @param aManifest the manifest data provided by the web app
|
||||
*
|
||||
*/
|
||||
init: function(aData, aManifest) {
|
||||
let manifest = new ManifestHelper(aManifest, aData.app.origin);
|
||||
|
||||
let origin = Services.io.newURI(aData.app.origin, null, null);
|
||||
|
||||
let biggestIcon = getBiggestIconURL(manifest.icons);
|
||||
try {
|
||||
let iconURI = Services.io.newURI(biggestIcon, null, null);
|
||||
if (iconURI.scheme == "data") {
|
||||
this.iconURI = iconURI;
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
if (!this.iconURI) {
|
||||
try {
|
||||
this.iconURI = Services.io.newURI(origin.resolve(biggestIcon), null, null);
|
||||
}
|
||||
catch (ex) {}
|
||||
}
|
||||
|
||||
if (manifest.developer && manifest.developer.name) {
|
||||
let devName = sanitize(manifest.developer.name.substr(0, 128));
|
||||
if (devName) {
|
||||
this.developerName = devName;
|
||||
}
|
||||
}
|
||||
|
||||
if (manifest.description) {
|
||||
let firstLine = manifest.description.split("\n")[0];
|
||||
let shortDesc = firstLine.length <= 256
|
||||
? firstLine
|
||||
: firstLine.substr(0, 253) + "…";
|
||||
this.shortDescription = sanitize(shortDesc);
|
||||
} else {
|
||||
this.shortDescription = this.appName;
|
||||
}
|
||||
|
||||
this.categories = aData.app.categories.slice(0);
|
||||
|
||||
// The app registry is the Firefox profile from which the app
|
||||
// was installed.
|
||||
let registryFolder = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
this.webappJson = {
|
||||
"registryDir": registryFolder.path,
|
||||
"app": {
|
||||
"manifest": aManifest,
|
||||
"origin": aData.app.origin
|
||||
}
|
||||
};
|
||||
|
||||
this.runtimeFolder = Services.dirsvc.get("GreD", Ci.nsIFile);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef XP_WIN
|
||||
/*************************************
|
||||
* Windows app installer
|
||||
@ -151,8 +212,7 @@ function NativeApp(aData) {
|
||||
/**
|
||||
* Constructor for the Windows native app shell
|
||||
*
|
||||
* @param aData the data object provided by the web app with
|
||||
* all the app settings and specifications.
|
||||
* @param aData the data object provided to the install function
|
||||
*/
|
||||
function WinNativeApp(aData) {
|
||||
NativeApp.call(this, aData);
|
||||
@ -160,21 +220,18 @@ function WinNativeApp(aData) {
|
||||
}
|
||||
|
||||
WinNativeApp.prototype = {
|
||||
__proto__: NativeApp.prototype,
|
||||
|
||||
/**
|
||||
* Install the app in the system by creating the folder structure,
|
||||
* Install the app in the system
|
||||
*
|
||||
*/
|
||||
install: function() {
|
||||
// Remove previously installed app (for update purposes)
|
||||
this._removeInstallation(true);
|
||||
|
||||
try {
|
||||
this._createDirectoryStructure();
|
||||
this._copyPrebuiltFiles();
|
||||
this._createConfigFiles();
|
||||
this._createShortcutFiles();
|
||||
this._writeSystemKeys();
|
||||
this._createAppProfile();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
throw(ex);
|
||||
@ -221,6 +278,11 @@ WinNativeApp.prototype = {
|
||||
this.iconFile.append("default.ico");
|
||||
|
||||
this.uninstallSubkeyStr = this.uniqueName;
|
||||
|
||||
// Remove previously installed app (for update purposes)
|
||||
this._removeInstallation(true);
|
||||
|
||||
this._createDirectoryStructure();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -269,15 +331,17 @@ WinNativeApp.prototype = {
|
||||
* Creates the main directory structure.
|
||||
*/
|
||||
_createDirectoryStructure: function() {
|
||||
if (!this.installDir.exists())
|
||||
if (!this.installDir.exists()) {
|
||||
this.installDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
}
|
||||
|
||||
this.uninstallDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the profile to be used for this app.
|
||||
*/
|
||||
_createAppProfile: function() {
|
||||
createAppProfile: function() {
|
||||
let profSvc = Cc["@mozilla.org/toolkit/profile-service;1"]
|
||||
.getService(Ci.nsIToolkitProfileService);
|
||||
|
||||
@ -453,6 +517,8 @@ function MacNativeApp(aData) {
|
||||
}
|
||||
|
||||
MacNativeApp.prototype = {
|
||||
__proto__: NativeApp.prototype,
|
||||
|
||||
_init: function() {
|
||||
this.appSupportDir = Services.dirsvc.get("ULibDir", Ci.nsILocalFile);
|
||||
this.appSupportDir.append("Application Support");
|
||||
@ -482,15 +548,17 @@ MacNativeApp.prototype = {
|
||||
|
||||
this.iconFile = this.resourcesDir.clone();
|
||||
this.iconFile.append("appicon.icns");
|
||||
|
||||
// Remove previously installed app (for update purposes)
|
||||
this._removeInstallation(true);
|
||||
|
||||
this._createDirectoryStructure();
|
||||
},
|
||||
|
||||
install: function() {
|
||||
this._removeInstallation(true);
|
||||
try {
|
||||
this._createDirectoryStructure();
|
||||
this._copyPrebuiltFiles();
|
||||
this._createConfigFiles();
|
||||
this._createAppProfile();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
throw(ex);
|
||||
@ -510,15 +578,16 @@ MacNativeApp.prototype = {
|
||||
},
|
||||
|
||||
_createDirectoryStructure: function() {
|
||||
if (!this.appProfileDir.exists())
|
||||
if (!this.appProfileDir.exists()) {
|
||||
this.appProfileDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
}
|
||||
|
||||
this.contentsDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
this.macOSDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
this.resourcesDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
},
|
||||
|
||||
_createAppProfile: function() {
|
||||
createAppProfile: function() {
|
||||
let profSvc = Cc["@mozilla.org/toolkit/profile-service;1"]
|
||||
.getService(Ci.nsIToolkitProfileService);
|
||||
|
||||
@ -650,6 +719,8 @@ function LinuxNativeApp(aData) {
|
||||
}
|
||||
|
||||
LinuxNativeApp.prototype = {
|
||||
__proto__: NativeApp.prototype,
|
||||
|
||||
_init: function() {
|
||||
// The ${InstallDir} and desktop entry filename are: sanitized app name +
|
||||
// "-" + manifest url hash
|
||||
@ -685,16 +756,17 @@ LinuxNativeApp.prototype = {
|
||||
|
||||
this.desktopINI.append("applications");
|
||||
this.desktopINI.append("owa-" + this.uniqueName + ".desktop");
|
||||
|
||||
// Remove previously installed app (for update purposes)
|
||||
this._removeInstallation(true);
|
||||
|
||||
this._createDirectoryStructure();
|
||||
},
|
||||
|
||||
install: function() {
|
||||
this._removeInstallation(true);
|
||||
|
||||
try {
|
||||
this._createDirectoryStructure();
|
||||
this._copyPrebuiltFiles();
|
||||
this._createConfigFiles();
|
||||
this._createAppProfile();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
throw(ex);
|
||||
@ -729,7 +801,7 @@ LinuxNativeApp.prototype = {
|
||||
webapprtPre.copyTo(this.installDir, this.webapprt.leafName);
|
||||
},
|
||||
|
||||
_createAppProfile: function() {
|
||||
createAppProfile: function() {
|
||||
let profSvc = Cc["@mozilla.org/toolkit/profile-service;1"]
|
||||
.getService(Ci.nsIToolkitProfileService);
|
||||
|
||||
@ -770,7 +842,7 @@ LinuxNativeApp.prototype = {
|
||||
|
||||
// The trailing semicolon is needed as written in the freedesktop specification
|
||||
let categories = "";
|
||||
for (let category of this.app.categories) {
|
||||
for (let category of this.categories) {
|
||||
let catLower = category.toLowerCase();
|
||||
if (catLower in translations) {
|
||||
categories += translations[catLower] + ";";
|
||||
|
@ -30,7 +30,7 @@ CommandLineHandler.prototype = {
|
||||
"chrome,dialog=no",
|
||||
args);
|
||||
} else {
|
||||
args.setProperty("url", WebappRT.launchURI.spec);
|
||||
args.setProperty("url", WebappRT.launchURI);
|
||||
Services.ww.openWindow(null,
|
||||
"chrome://webapprt/content/webapp.xul",
|
||||
"_blank",
|
||||
|
@ -10,17 +10,13 @@ const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "FileUtils", function() {
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
return FileUtils;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "DOMApplicationRegistry", function() {
|
||||
Cu.import("resource://gre/modules/Webapps.jsm");
|
||||
return DOMApplicationRegistry;
|
||||
});
|
||||
|
||||
this.WebappRT = {
|
||||
_config: null,
|
||||
|
||||
@ -51,10 +47,8 @@ this.WebappRT = {
|
||||
},
|
||||
|
||||
get launchURI() {
|
||||
let url = Services.io.newURI(this.config.app.origin, null, null);
|
||||
if (this.config.app.manifest.launch_path) {
|
||||
url = Services.io.newURI(this.config.app.manifest.launch_path, null, url);
|
||||
}
|
||||
return url;
|
||||
let manifest = new ManifestHelper(this.config.app.manifest,
|
||||
this.config.app.origin);
|
||||
return manifest.fullLaunchPath();
|
||||
}
|
||||
};
|
||||
|
@ -12,6 +12,7 @@ let Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Webapps.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/WebappsInstaller.jsm");
|
||||
Cu.import("resource://gre/modules/WebappOSUtils.jsm");
|
||||
|
||||
@ -42,7 +43,9 @@ this.WebappsHandler = {
|
||||
},
|
||||
|
||||
doInstall: function(data, window) {
|
||||
let {name} = data.app.manifest;
|
||||
let jsonManifest = data.isPackage ? data.app.updateManifest : data.app.manifest;
|
||||
let manifest = new ManifestHelper(jsonManifest, data.app.origin);
|
||||
let name = manifest.name;
|
||||
let bundle = Services.strings.createBundle("chrome://webapprt/locale/webapp.properties");
|
||||
|
||||
let choice = Services.prompt.confirmEx(
|
||||
@ -60,10 +63,24 @@ this.WebappsHandler = {
|
||||
{});
|
||||
|
||||
// Perform the install if the user allows it
|
||||
if (choice == 0 && WebappsInstaller.install(data)) {
|
||||
DOMApplicationRegistry.confirmInstall(data);
|
||||
}
|
||||
else {
|
||||
if (choice == 0) {
|
||||
let shell = WebappsInstaller.init(data);
|
||||
|
||||
if (shell) {
|
||||
let localDir = null;
|
||||
if (shell.appProfile) {
|
||||
localDir = shell.appProfile.localDir;
|
||||
}
|
||||
|
||||
DOMApplicationRegistry.confirmInstall(data, false, localDir, null,
|
||||
function (aManifest) {
|
||||
WebappsInstaller.install(data, aManifest);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
DOMApplicationRegistry.denyInstall(data);
|
||||
}
|
||||
} else {
|
||||
DOMApplicationRegistry.denyInstall(data);
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ function loadWebapp(manifest, parameters, onLoad) {
|
||||
onLoad();
|
||||
}
|
||||
gAppBrowser.addEventListener("load", onLoadApp, true);
|
||||
gAppBrowser.setAttribute("src", WebappRT.launchURI.spec);
|
||||
gAppBrowser.setAttribute("src", WebappRT.launchURI);
|
||||
});
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
|
Loading…
Reference in New Issue
Block a user