Bug 702369 - ensure that web app install caches them into app cache on B2G [r=jonas,vingtetun,felipe]

This commit is contained in:
Fabrice Desré 2012-06-11 11:41:46 -07:00
parent 7079a51003
commit f5ff57a3d4
4 changed files with 166 additions and 50 deletions

View File

@ -37,8 +37,8 @@ function convertAppsArray(aApps, aWindow) {
let apps = Cu.createArrayIn(aWindow);
for (let i = 0; i < aApps.length; i++) {
let app = aApps[i];
apps.push(new WebappsApplication(aWindow, app.origin, app.manifest, app.manifestURL,
app.receipts, app.installOrigin, app.installTime));
apps.push(createApplicationObject(aWindow, app.origin, app.manifest, app.manifestURL,
app.receipts, app.installOrigin, app.installTime));
}
return apps;
@ -49,6 +49,12 @@ function WebappsRegistry() {
WebappsRegistry.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
__exposedProps__: {
install: 'r',
getSelf: 'r',
getInstalled: 'r',
mgmt: 'r'
},
/** from https://developer.mozilla.org/en/OpenWebApps/The_Manifest
* only the name property is mandatory
@ -76,8 +82,8 @@ WebappsRegistry.prototype = {
let app = msg.app;
switch (aMessage.name) {
case "Webapps:Install:Return:OK":
Services.DOMRequest.fireSuccess(req, new WebappsApplication(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
app.installOrigin, app.installTime));
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
app.installOrigin, app.installTime));
break;
case "Webapps:Install:Return:KO":
Services.DOMRequest.fireError(req, "DENIED");
@ -85,8 +91,8 @@ WebappsRegistry.prototype = {
case "Webapps:GetSelf:Return:OK":
if (msg.apps.length) {
app = msg.apps[0];
Services.DOMRequest.fireSuccess(req, new WebappsApplication(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
app.installOrigin, app.installTime));
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
app.installOrigin, app.installTime));
} else {
Services.DOMRequest.fireSuccess(req, null);
}
@ -200,63 +206,57 @@ WebappsRegistry.prototype = {
/**
* mozIDOMApplication object
*/
function WebappsApplication(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
this._origin = aOrigin;
this._manifestURL = aManifestURL;
this._manifest = wrapObjectIn(aManifest, aWindow);
this._receipts = aReceipts;
this._installOrigin = aInstallOrigin;
this._installTime = aInstallTime;
this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Return:KO"]);
function createApplicationObject(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication);
app.wrappedJSObject.init(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime);
return app;
}
function WebappsApplication() {
this.wrappedJSObject = this;
}
WebappsApplication.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
_origin: null,
_manifest: null,
_manifestURL: null,
_receipts: [],
_installOrigin: null,
_installTime: 0,
__exposedProps__: {
origin: 'r',
manifest: 'r',
manifestURL: 'r',
installOrigin: 'r',
installTime: 'r',
status: 'r',
progress: 'r',
onprogress: 'rw',
launch: 'r',
receipts: 'r',
uninstall: 'r'
},
get origin() {
return this._origin;
init: function(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
this.origin = aOrigin;
this.manifest = wrapObjectIn(aManifest, aWindow);
this.manifestURL = aManifestURL;
this.receipts = aReceipts;
this.installOrigin = aInstallOrigin;
this.installTime = aInstallTime;
this.status = "installed";
this.progress = NaN;
this._onprogress = null;
this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Return:KO", "Webapps:OfflineCache"]);
},
get manifest() {
return this._manifest;
set onprogress(aCallback) {
this._onprogress = aCallback;
},
get manifestURL() {
return this._manifestURL;
},
get receipts() {
return this._receipts;
},
get installOrigin() {
return this._installOrigin;
},
get installTime() {
return this._installTime;
get onprogress() {
return this._onprogress;
},
launch: function(aStartPoint) {
let request = this.createRequest();
cpmm.sendAsyncMessage("Webapps:Launch", { origin: this._origin,
cpmm.sendAsyncMessage("Webapps:Launch", { origin: this.origin,
startPoint: aStartPoint || "",
oid: this._id,
requestID: this.getRequestId(request) });
@ -265,16 +265,20 @@ WebappsApplication.prototype = {
uninstall: function() {
let request = this.createRequest();
cpmm.sendAsyncMessage("Webapps:Uninstall", { origin: this._origin,
cpmm.sendAsyncMessage("Webapps:Uninstall", { origin: this.origin,
oid: this._id,
requestID: this.getRequestId(request) });
return request;
},
uninit: function() {
this._onprogress = null;
},
receiveMessage: function(aMessage) {
var msg = aMessage.json;
let req = this.getRequest(msg.requestID);
if (msg.oid != this._id || !req)
let req = this.takeRequest(msg.requestID);
if ((msg.oid != this._id || !req) && aMessage.name !== "Webapps:OfflineCache")
return;
switch (aMessage.name) {
case "Webapps:Uninstall:Return:OK":
@ -283,8 +287,17 @@ WebappsApplication.prototype = {
case "Webapps:Uninstall:Return:KO":
Services.DOMRequest.fireError(req, "NOT_INSTALLED");
break;
case "Webapps:OfflineCache":
if (msg.manifest != this.manifestURL)
return;
this.status = msg.status;
if (this._onprogress) {
let event = new this._window.MozApplicationEvent("applicationinstall", { application: this });
this._onprogress.handleEvent(event);
}
break;
}
this.removeRequest(msg.requestID);
},
classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
@ -321,6 +334,11 @@ function WebappsApplicationMgmt(aWindow) {
WebappsApplicationMgmt.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
__exposedProps__: {
getAll: 'r',
oninstall: 'rw',
onuninstall: 'rw'
},
uninit: function() {
this._oninstall = null;
@ -376,7 +394,7 @@ WebappsApplicationMgmt.prototype = {
if (this._oninstall) {
let app = msg.app;
let event = new this._window.MozApplicationEvent("applicationinstall",
{ application : new WebappsApplication(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
{ application : createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
app.installOrigin, app.installTime) });
this._oninstall.handleEvent(event);
}
@ -384,7 +402,7 @@ WebappsApplicationMgmt.prototype = {
case "Webapps:Uninstall:Return:OK":
if (this._onuninstall) {
let event = new this._window.MozApplicationEvent("applicationuninstall",
{ application : new WebappsApplication(this._window, msg.origin, null, null, null, null, 0) });
{ application : createApplicationObject(this._window, msg.origin, null, null, null, null, 0) });
this._onuninstall.handleEvent(event);
}
break;

View File

@ -156,7 +156,9 @@ let DOMApplicationRegistry = {
origin: aApp.origin,
receipts: aApp.receipts,
installTime: aApp.installTime,
manifestURL: aApp.manifestURL
manifestURL: aApp.manifestURL,
progress: aApp.progress || 0.0,
status: aApp.status || "installed"
};
return clone;
},
@ -165,7 +167,7 @@ let DOMApplicationRegistry = {
ppmm.sendAsyncMessage("Webapps:Install:Return:KO", aData);
},
confirmInstall: function(aData, aFromSync) {
confirmInstall: function(aData, aFromSync, aProfileDir, aOfflineCacheObserver) {
let app = aData.app;
let id = app.syncId || this._appId(app.origin);
@ -191,11 +193,29 @@ let DOMApplicationRegistry = {
this._writeFile(manFile, JSON.stringify(app.manifest));
this.webapps[id] = appObject;
appObject.status = "installed";
let manifest = new DOMApplicationManifest(app.manifest, app.origin);
if (!aFromSync)
this._saveApps((function() {
ppmm.sendAsyncMessage("Webapps:Install:Return:OK", aData);
Services.obs.notifyObservers(this, "webapps-sync-install", appNote);
}).bind(this));
// if the manifest has an appcache_path property, use it to populate the appcache
if (manifest.appcache_path) {
let appcacheURI = Services.io.newURI(manifest.fullAppcachePath(), null, null);
let updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]
.getService(Ci.nsIOfflineCacheUpdateService);
let docURI = Services.io.newURI(manifest.fullLaunchPath(), null, null);
let cacheUpdate = aProfileDir ? updateService.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
: updateService.scheduleUpdate(appcacheURI, docURI, null);
cacheUpdate.addObserver(new AppcacheObserver(appObject), false);
if (aOfflineCacheObserver) {
cacheUpdate.addObserver(aOfflineCacheObserver, false);
}
}
},
_appId: function(aURI) {
@ -428,6 +448,53 @@ let DOMApplicationRegistry = {
}
};
/**
* Appcache download observer
*/
AppcacheObserver = function(aApp) {
this.app = aApp;
};
AppcacheObserver.prototype = {
// nsIOfflineCacheUpdateObserver implementation
updateStateChanged: function appObs_Update(aUpdate, aState) {
let mustSave = false;
let app = this.app;
let setStatus = function appObs_setStatus(aStatus) {
mustSave = (app.status != aStatus);
app.status = aStatus;
ppmm.sendAsyncMessage("Webapps:OfflineCache", { manifest: app.manifestURL, status: aStatus });
}
switch (aState) {
case Ci.nsIOfflineCacheUpdateObserver.STATE_ERROR:
aUpdate.removeObserver(this);
setStatus("cache-error");
break;
case Ci.nsIOfflineCacheUpdateObserver.STATE_NOUPDATE:
case Ci.nsIOfflineCacheUpdateObserver.STATE_FINISHED:
aUpdate.removeObserver(this);
setStatus("cached");
break;
case Ci.nsIOfflineCacheUpdateObserver.STATE_DOWNLOADING:
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS:
setStatus("downloading")
break;
}
// Status changed, update the stored version.
if (mustSave) {
DOMApplicationRegistry._saveApps();
}
},
applicationCacheAvailable: function appObs_CacheAvail(aApplicationCache) {
// Nothing to do.
}
};
/**
* Helper object to access manifest information with locale support
*/
@ -481,6 +548,10 @@ DOMApplicationManifest.prototype = {
return this._localeProp("icons");
},
get appcache_path() {
return this._localeProp("appcache_path");
},
iconURLForSize: function(aSize) {
let icons = this._localeProp("icons");
if (!icons)
@ -501,6 +572,11 @@ DOMApplicationManifest.prototype = {
let startPoint = aStartPoint || "";
let launchPath = this._localeProp("launch_path") || "";
return this._origin.resolve(launchPath + startPoint);
},
fullAppcachePath: function() {
let appcachePath = this._localeProp("appcache_path");
return this._origin.resolve(appcachePath ? appcachePath : "");
}
};

View File

@ -2,3 +2,6 @@
component {fff440b3-fae2-45c1-bf03-3b5a2e432270} Webapps.js
contract @mozilla.org/webapps;1 {fff440b3-fae2-45c1-bf03-3b5a2e432270}
category JavaScript-navigator-property mozApps @mozilla.org/webapps;1
component {723ed303-7757-4fb0-b261-4f78b1f6bd22} Webapps.js
contract @mozilla.org/webapps/application;1 {723ed303-7757-4fb0-b261-4f78b1f6bd22}

View File

@ -9,15 +9,34 @@
interface nsIDOMDOMRequest;
interface nsIArray;
[scriptable, uuid(b70b84f1-7ac9-4a92-bc32-8b6a7eb7879e)]
[scriptable, uuid(9583b825-46b1-4e8f-bb48-9fed660a95e6)]
interface mozIDOMApplication : nsISupports
{
readonly attribute jsval manifest;
readonly attribute DOMString manifestURL;
readonly attribute nsIArray receipts; /* an array of strings */
readonly attribute jsval receipts; /* an array of strings */
readonly attribute DOMString origin;
readonly attribute DOMString installOrigin;
readonly attribute unsigned long installTime;
readonly attribute unsigned long long installTime;
/*
* The current progress when downloading an offline cache.
*/
readonly attribute double progress;
/*
* The application status :
* "installed" : The app is in the registry, but we have no offline cache.
* "downlading" : We are downloading the offline cache.
* "cached" : We are done with the offline cache download.
* "cache-error" : An error occured while downloading the offline-cache.
*/
readonly attribute DOMString status;
/*
* fires a nsIDOMApplicationEvent when a change in appcache download or status happens
*/
attribute nsIDOMEventListener onprogress;
/* startPoint will be used when several launch_path exists for an app */
nsIDOMDOMRequest launch([optional] in DOMString startPoint);