Bug 1072090 - Add a way to enable and disable an app. r=myk,sicking

This commit is contained in:
Fabrice Desré 2014-10-23 16:40:08 -07:00
parent 73b475d68a
commit c06071e0b2
8 changed files with 227 additions and 20 deletions

View File

@ -107,6 +107,7 @@ function _setAppProperties(aObj, aApp) {
aObj.redirects = aApp.redirects;
aObj.widgetPages = aApp.widgetPages || [];
aObj.kind = aApp.kind;
aObj.enabled = aApp.enabled !== undefined ? aApp.enabled : true;
}
this.AppsUtils = {

View File

@ -424,6 +424,10 @@ WebappsApplication.prototype = {
return new this._window.DOMError(this._proxy.downloadError);
},
get enabled() {
return this._proxy.enabled;
},
download: function() {
cpmm.sendAsyncMessage("Webapps:Download",
{ manifestURL: this.manifestURL });
@ -613,7 +617,7 @@ WebappsApplication.prototype = {
case "Webapps:Launch:Return:KO":
this.removeMessageListeners(["Webapps:Launch:Return:OK",
"Webapps:Launch:Return:KO"]);
Services.DOMRequest.fireError(req, "APP_INSTALL_PENDING");
Services.DOMRequest.fireError(req, msg.error);
break;
case "Webapps:Launch:Return:OK":
this.removeMessageListeners(["Webapps:Launch:Return:OK",
@ -722,12 +726,14 @@ WebappsApplicationMgmt.prototype = {
"Webapps:Install:Return:OK",
"Webapps:GetNotInstalled:Return:OK",
"Webapps:Import:Return",
"Webapps:ExtractManifest:Return"]);
"Webapps:ExtractManifest:Return",
"Webapps:SetEnabled:Return"]);
cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
{
messages: ["Webapps:Install:Return:OK",
"Webapps:Uninstall:Return:OK",
"Webapps:Uninstall:Broadcast:Return:OK"]
"Webapps:Uninstall:Broadcast:Return:OK",
"Webapps:SetEnabled:Return"]
}
);
},
@ -736,7 +742,8 @@ WebappsApplicationMgmt.prototype = {
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
["Webapps:Install:Return:OK",
"Webapps:Uninstall:Return:OK",
"Webapps:Uninstall:Broadcast:Return:OK"]);
"Webapps:Uninstall:Broadcast:Return:OK",
"Webapps:SetEnabled:Return"]);
},
applyDownload: function(aApp) {
@ -804,6 +811,12 @@ WebappsApplicationMgmt.prototype = {
});
},
setEnabled: function(aApp, aValue) {
cpmm.sendAsyncMessage("Webapps:SetEnabled",
{ manifestURL: aApp.manifestURL,
enabled: aValue });
},
get oninstall() {
return this.__DOM_IMPL__.getEventHandler("oninstall");
},
@ -812,6 +825,10 @@ WebappsApplicationMgmt.prototype = {
return this.__DOM_IMPL__.getEventHandler("onuninstall");
},
get onenabledstatechange() {
return this.__DOM_IMPL__.getEventHandler("onenabledstatechange");
},
set oninstall(aCallback) {
this.__DOM_IMPL__.setEventHandler("oninstall", aCallback);
},
@ -820,9 +837,14 @@ WebappsApplicationMgmt.prototype = {
this.__DOM_IMPL__.setEventHandler("onuninstall", aCallback);
},
set onenabledstatechange(aCallback) {
this.__DOM_IMPL__.setEventHandler("onenabledstatechange", aCallback);
},
receiveMessage: function(aMessage) {
let msg = aMessage.data;
let req;
if (["Webapps:Import:Return",
"Webapps:ExtractManifest:Return"]
.indexOf(aMessage.name) != -1) {
@ -831,11 +853,13 @@ WebappsApplicationMgmt.prototype = {
req = this.getRequest(msg.requestID);
}
// We want Webapps:Install:Return:OK and Webapps:Uninstall:Broadcast:Return:OK
// We want Webapps:Install:Return:OK, Webapps:Uninstall:Broadcast:Return:OK
// and Webapps:SetEnabled:Return
// to be broadcasted to all instances of mozApps.mgmt.
if (!((msg.oid == this._id && req) ||
aMessage.name == "Webapps:Install:Return:OK" ||
aMessage.name == "Webapps:Uninstall:Broadcast:Return:OK")) {
aMessage.name == "Webapps:Uninstall:Broadcast:Return:OK" ||
aMessage.name == "Webapps:SetEnabled:Return")) {
return;
}
@ -879,6 +903,14 @@ WebappsApplicationMgmt.prototype = {
req.reject(new this._window.DOMError(msg.error || ""));
}
break;
case "Webapps:SetEnabled:Return":
{
let app = createContentApplicationObject(this._window, msg);
let event =
new this._window.MozApplicationEvent("enabledstatechange", { application : app });
this.__DOM_IMPL__.dispatchEvent(event);
}
break;
}
if (aMessage.name !== "Webapps:Uninstall:Broadcast:Return:OK") {
this.removeRequest(msg.requestID);

View File

@ -173,20 +173,30 @@ this.DOMApplicationRegistry = {
dirKey: DIRECTORY_NAME,
init: function() {
this.messages = ["Webapps:Install", "Webapps:Uninstall",
"Webapps:GetSelf", "Webapps:CheckInstalled",
"Webapps:GetInstalled", "Webapps:GetNotInstalled",
this.messages = ["Webapps:Install",
"Webapps:Uninstall",
"Webapps:GetSelf",
"Webapps:CheckInstalled",
"Webapps:GetInstalled",
"Webapps:GetNotInstalled",
"Webapps:Launch",
"Webapps:InstallPackage",
"Webapps:GetList", "Webapps:RegisterForMessages",
"Webapps:GetList",
"Webapps:RegisterForMessages",
"Webapps:UnregisterForMessages",
"Webapps:CancelDownload", "Webapps:CheckForUpdate",
"Webapps:Download", "Webapps:ApplyDownload",
"Webapps:Install:Return:Ack", "Webapps:AddReceipt",
"Webapps:RemoveReceipt", "Webapps:ReplaceReceipt",
"Webapps:CancelDownload",
"Webapps:CheckForUpdate",
"Webapps:Download",
"Webapps:ApplyDownload",
"Webapps:Install:Return:Ack",
"Webapps:AddReceipt",
"Webapps:RemoveReceipt",
"Webapps:ReplaceReceipt",
"Webapps:RegisterBEP",
"Webapps:Export", "Webapps:Import",
"Webapps:Export",
"Webapps:Import",
"Webapps:ExtractManifest",
"Webapps:SetEnabled",
"child-process-shutdown"];
this.frameMessages = ["Webapps:ClearBrowserData"];
@ -283,6 +293,10 @@ this.DOMApplicationRegistry = {
continue;
}
if (app.enabled === undefined) {
app.enabled = true;
}
// At startup we can't be downloading, and the $TMP directory
// will be empty so we can't just apply a staged update.
app.downloading = false;
@ -1181,13 +1195,14 @@ this.DOMApplicationRegistry = {
Services.prefs.setBoolPref("dom.mozApps.used", true);
// We need to check permissions for calls coming from mozApps.mgmt.
// These are: getNotInstalled(), applyDownload(), uninstall(), import() and
// extractManifest().
// These are: getNotInstalled(), applyDownload(), uninstall(), import(),
// extractManifest(), setEnabled().
if (["Webapps:GetNotInstalled",
"Webapps:ApplyDownload",
"Webapps:Uninstall",
"Webapps:Import",
"Webapps:ExtractManifest"].indexOf(aMessage.name) != -1) {
"Webapps:ExtractManifest",
"Webapps:SetEnabled"].indexOf(aMessage.name) != -1) {
if (!aMessage.target.assertPermission("webapps-manage")) {
debug("mozApps message " + aMessage.name +
" from a content process with no 'webapps-manage' privileges.");
@ -1322,6 +1337,9 @@ this.DOMApplicationRegistry = {
case "Webapps:ExtractManifest":
this.doExtractManifest(msg, mm);
break;
case "Webapps:SetEnabled":
this.setEnabled(msg);
break;
}
});
},
@ -1534,6 +1552,7 @@ this.DOMApplicationRegistry = {
aMm.sendAsyncMessage("Webapps:Launch:Return:OK", aData);
},
function onfailure(reason) {
aData.error = reason;
aMm.sendAsyncMessage("Webapps:Launch:Return:KO", aData);
}
);
@ -4299,6 +4318,25 @@ this.DOMApplicationRegistry = {
});
},
setEnabled: function(aData) {
debug("setEnabled " + aData.manifestURL + " : " + aData.enabled);
let id = this._appIdForManifestURL(aData.manifestURL);
if (!id || !this.webapps[id]) {
return;
}
debug("Enabling " + id);
let app = this.webapps[id];
app.enabled = aData.enabled;
this._saveApps().then(() => {
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
id: app.id
});
this.broadcastMessage("Webapps:SetEnabled:Return", app);
});
},
getManifestFor: function(aManifestURL) {
let id = this._appIdForManifestURL(aManifestURL);
let app = this.webapps[id];

View File

@ -22,6 +22,7 @@ support-files =
marketplace/*
pkg_install_iframe.html
[test_app_enabled.html]
[test_app_update.html]
[test_bug_795164.html]
[test_import_export.html]

View File

@ -0,0 +1,129 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id={1XXXXXX}
-->
<head>
<title>Test for Bug {1072090}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={1072090}">Mozilla Bug {1072090}</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
var gManifestURL = "http://test/tests/dom/apps/tests/file_app.sjs?apptype=hosted&getmanifest=true";
var gGenerator = runTest();
function go() {
SpecialPowers.pushPermissions(
[{ "type": "webapps-manage", "allow": 1, "context": document }],
function() { gGenerator.next() });
}
function continueTest() {
try {
gGenerator.next();
} catch (e if e instanceof StopIteration) {
finish();
}
}
function finish() {
SimpleTest.finish();
}
function cbError(aEvent) {
ok(false, "Error callback invoked " +
aEvent.target.error.name + " " + aEvent.target.error.message);
finish();
}
SimpleTest.waitForExplicitFinish();
/**
* Flip the `enabled` state of an app back and forth.
*/
function runTest() {
SpecialPowers.setAllAppsLaunchable(true);
SpecialPowers.autoConfirmAppInstall(continueTest);
yield undefined;
SpecialPowers.autoConfirmAppUninstall(continueTest);
yield undefined;
request = navigator.mozApps.mgmt.getAll();
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
var initialAppsCount = request.result.length;
info("Starting with " + initialAppsCount + " apps installed.");
var request = navigator.mozApps.install(gManifestURL, { });
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
var app = request.result;
ok(app, "App is non-null");
is(app.manifestURL, gManifestURL, "App manifest url is correct.");
is(app.enabled, true, "App is enabled by default after install.");
// Switch the app to disabled.
navigator.mozApps.mgmt.onenabledstatechange = function(event) {
ok(true, "onenabledstatechange received");
is(event.application.enabled, false, "Application is disabled");
is(app.enabled, false, "Application is disabled");
continueTest();
}
navigator.mozApps.mgmt.setEnabled(app, false);
yield undefined;
// Re-enable the app.
navigator.mozApps.mgmt.onenabledstatechange = function(event) {
ok(true, "onenabledstatechange received");
is(event.application.enabled, true, "Application is enabled");
is(app.enabled, true, "Application is enabled");
continueTest();
}
navigator.mozApps.mgmt.setEnabled(app, true);
yield undefined;
navigator.mozApps.mgmt.onuninstall = function(event) {
var app = event.application;
is(app.manifestURL, gManifestURL, "App uninstall event ok.");
is(app.manifest.name, "Really Rapid Release (hosted)",
"App uninstall manifest ok.");
continueTest();
}
request = navigator.mozApps.mgmt.uninstall(app);
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
yield undefined;
is(request.result, gManifestURL, "App uninstalled.");
navigator.mozApps.mgmt.onuninstall = null;
request = navigator.mozApps.mgmt.getAll();
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
}
addLoadEvent(go);
</script>
</pre>
</body>
</html>

View File

@ -77,7 +77,7 @@ function cbError(aEvent) {
SimpleTest.waitForExplicitFinish();
/**
* Install 2 apps from the same origin and uninstall them.
* Test exporting and importing hosted and packaged apps.
*/
function runTest() {
SpecialPowers.setAllAppsLaunchable(true);

View File

@ -44,11 +44,13 @@ var mgmtProps = {
uninstall: "function",
oninstall: "object",
onuninstall: "object",
onenabledstatechange: "object",
ownerGlobal: "object",
removeEventListener: "function",
setEventHandler: "function",
extractManifest: "function",
import: "function"
import: "function",
setEnabled: "function"
};
isDeeply([p for (p in navigator.mozApps.mgmt)].sort(),

View File

@ -32,6 +32,7 @@ interface DOMApplication : EventTarget {
readonly attribute DOMString installOrigin;
readonly attribute DOMTimeStamp installTime;
readonly attribute boolean removable;
readonly attribute boolean enabled;
[Cached, Pure]
readonly attribute sequence<DOMString> receipts;
@ -96,6 +97,9 @@ interface DOMApplicationsManager : EventTarget {
Promise<DOMApplication> import(Blob blob);
Promise<any> extractManifest(Blob blob);
void setEnabled(DOMApplication app, boolean state);
attribute EventHandler oninstall;
attribute EventHandler onuninstall;
attribute EventHandler onenabledstatechange;
};