mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to m-i
This commit is contained in:
commit
22b26ff040
@ -14,4 +14,5 @@ support-files =
|
||||
[browser_storage_dynamic_updates.js]
|
||||
[browser_storage_overflow.js]
|
||||
[browser_storage_sidebar.js]
|
||||
skip-if = (os == 'win' && os_version == '6.1' && e10s && !debug) # bug 1229272
|
||||
[browser_storage_values.js]
|
||||
|
@ -116,6 +116,9 @@ pref("network.predictor.enabled", true);
|
||||
pref("network.predictor.max-db-size", 2097152); // bytes
|
||||
pref("network.predictor.preserve", 50); // percentage of predictor data to keep when cleaning up
|
||||
|
||||
// Use JS mDNS as a fallback
|
||||
pref("network.mdns.use_js_fallback", true);
|
||||
|
||||
/* history max results display */
|
||||
pref("browser.display.history.maxresults", 100);
|
||||
|
||||
@ -976,3 +979,7 @@ pref("identity.fxaccounts.remote.oauth.uri", "https://oauth.accounts.firefox.com
|
||||
|
||||
// Token server used by Firefox Account-authenticated Sync.
|
||||
pref("identity.sync.tokenserver.uri", "https://token.services.mozilla.com/1.0/sync/1.5");
|
||||
|
||||
// Enable Presentation API
|
||||
pref("dom.presentation.enabled", true);
|
||||
pref("dom.presentation.discovery.enabled", true);
|
||||
|
@ -59,6 +59,64 @@ var mediaPlayerDevice = {
|
||||
}
|
||||
};
|
||||
|
||||
var fxOSTVDevice = {
|
||||
id: "app://fling-player.gaiamobile.org",
|
||||
target: "app://fling-player.gaiamobile.org/index.html",
|
||||
factory: function(aService) {
|
||||
Cu.import("resource://gre/modules/PresentationApp.jsm");
|
||||
let request = new window.PresentationRequest(this.target);
|
||||
return new PresentationApp(aService, request);
|
||||
},
|
||||
init: function() {
|
||||
Services.obs.addObserver(this, "presentation-device-change", false);
|
||||
SimpleServiceDiscovery.addExternalDiscovery(this);
|
||||
},
|
||||
observe: function(subject, topic, data) {
|
||||
let device = subject.QueryInterface(Ci.nsIPresentationDevice);
|
||||
let service = this.toService(device);
|
||||
switch (data) {
|
||||
case "add":
|
||||
SimpleServiceDiscovery.addService(service);
|
||||
break;
|
||||
case "update":
|
||||
SimpleServiceDiscovery.updateService(service);
|
||||
break;
|
||||
case "remove":
|
||||
if(SimpleServiceDiscovery.findServiceForID(device.id)) {
|
||||
SimpleServiceDiscovery.removeService(device.id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
toService: function(device) {
|
||||
return {
|
||||
location: device.id,
|
||||
target: fxOSTVDevice.target,
|
||||
friendlyName: device.name,
|
||||
uuid: device.id,
|
||||
manufacturer: "Firefox OS TV",
|
||||
modelName: "Firefox OS TV",
|
||||
};
|
||||
},
|
||||
startDiscovery: function() {
|
||||
window.navigator.mozPresentationDeviceInfo.forceDiscovery();
|
||||
|
||||
// need to update the lastPing time for known device.
|
||||
window.navigator.mozPresentationDeviceInfo.getAll()
|
||||
.then(function(devices) {
|
||||
for (let device of devices) {
|
||||
let service = fxOSTVDevice.toService(device);
|
||||
SimpleServiceDiscovery.addService(service);
|
||||
}
|
||||
});
|
||||
},
|
||||
stopDiscovery: function() {
|
||||
// do nothing
|
||||
},
|
||||
types: ["video/mp4", "video/webm"],
|
||||
extensions: ["mp4", "webm"],
|
||||
};
|
||||
|
||||
var CastingApps = {
|
||||
_castMenuId: -1,
|
||||
mirrorStartMenuId: -1,
|
||||
@ -79,6 +137,10 @@ var CastingApps = {
|
||||
mediaPlayerDevice.init();
|
||||
SimpleServiceDiscovery.registerDevice(mediaPlayerDevice);
|
||||
|
||||
// Presentation Device will notify us any time the available device list changes.
|
||||
fxOSTVDevice.init();
|
||||
SimpleServiceDiscovery.registerDevice(fxOSTVDevice);
|
||||
|
||||
// Search for devices continuously
|
||||
SimpleServiceDiscovery.search(this._interval);
|
||||
|
||||
|
@ -591,6 +591,7 @@ var BrowserApp = {
|
||||
|
||||
InitLater(() => Cu.import("resource://gre/modules/NotificationDB.jsm"));
|
||||
InitLater(() => Cu.import("resource://gre/modules/Payment.jsm"));
|
||||
InitLater(() => Cu.import("resource://gre/modules/PresentationDeviceInfoManager.jsm"));
|
||||
|
||||
InitLater(() => Services.obs.notifyObservers(window, "browser-delayed-startup-finished", ""));
|
||||
InitLater(() => Messaging.sendRequest({ type: "Gecko:DelayedStartup" }));
|
||||
|
@ -23,7 +23,7 @@
|
||||
src="chrome://passwordmgr/locale/passwordmgr.properties"/>
|
||||
|
||||
<keyset>
|
||||
<key keycode="VK_ESCAPE" oncommand="window.close();"/>
|
||||
<key keycode="VK_ESCAPE" oncommand="escapeKeyHandler();"/>
|
||||
<key key="&windowClose.key;" modifiers="accel" oncommand="escapeKeyHandler();"/>
|
||||
<key key="&focusSearch1.key;" modifiers="accel" oncommand="FocusFilterBox();"/>
|
||||
<key key="&focusSearch2.key;" modifiers="accel" oncommand="FocusFilterBox();"/>
|
||||
|
@ -1,5 +1,4 @@
|
||||
const { ContentTaskUtils } = Cu.import("resource://testing-common/ContentTaskUtils.jsm", {});
|
||||
const TIME_INTERVAL = 500;
|
||||
const PWMGR_DLG = "chrome://passwordmgr/content/passwordManager.xul";
|
||||
|
||||
var doc;
|
||||
@ -55,7 +54,7 @@ function* editUsernamePromises(site, oldUsername, newUsername) {
|
||||
is(Services.logins.findLogins({}, site, "", "").length, 1, "Correct login replaced");
|
||||
login = Services.logins.findLogins({}, site, "", "")[0];
|
||||
is(login.username, newUsername, "Correct username updated");
|
||||
is(getUsername(0), newUsername, "Correct username shown");
|
||||
is(getUsername(0), newUsername, "Correct username shown after the update");
|
||||
}
|
||||
|
||||
function* editPasswordPromises(site, oldPassword, newPassword) {
|
||||
@ -77,7 +76,7 @@ function* editPasswordPromises(site, oldPassword, newPassword) {
|
||||
is(Services.logins.findLogins({}, site, "", "").length, 1, "Correct login replaced");
|
||||
login = Services.logins.findLogins({}, site, "", "")[0];
|
||||
is(login.password, newPassword, "Correct password updated");
|
||||
is(getPassword(0), newPassword, "Correct password shown");
|
||||
is(getPassword(0), newPassword, "Correct password shown after the update");
|
||||
}
|
||||
|
||||
add_task(function* test_setup() {
|
||||
|
@ -63,6 +63,7 @@ EXTRA_JS_MODULES += [
|
||||
'RemoteSecurityUI.jsm',
|
||||
'RemoteWebProgress.jsm',
|
||||
'ResetProfile.jsm',
|
||||
'secondscreen/PresentationApp.jsm',
|
||||
'secondscreen/RokuApp.jsm',
|
||||
'secondscreen/SimpleServiceDiscovery.jsm',
|
||||
'SelectContentHelper.jsm',
|
||||
|
190
toolkit/modules/secondscreen/PresentationApp.jsm
Normal file
190
toolkit/modules/secondscreen/PresentationApp.jsm
Normal file
@ -0,0 +1,190 @@
|
||||
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
/* 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 = ["PresentationApp"];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "sysInfo", () => {
|
||||
return Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
|
||||
});
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
const STATE_UNINIT = "uninitialized" // RemoteMedia status
|
||||
const STATE_STARTED = "started"; // RemoteMedia status
|
||||
const STATE_PAUSED = "paused"; // RemoteMedia status
|
||||
const STATE_SHUTDOWN = "shutdown"; // RemoteMedia status
|
||||
|
||||
function debug(msg) {
|
||||
Services.console.logStringMessage("PresentationApp: " + msg);
|
||||
}
|
||||
|
||||
// PresentationApp is a wrapper for interacting with a Presentation Receiver Device.
|
||||
function PresentationApp(service, request) {
|
||||
this.service = service;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
PresentationApp.prototype = {
|
||||
start: function start(callback) {
|
||||
this.request.startWithDevice(this.service.uuid)
|
||||
.then((session) => {
|
||||
this._session = session;
|
||||
if (callback) {
|
||||
callback(true);
|
||||
}
|
||||
}, () => {
|
||||
if (callback) {
|
||||
callback(false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
stop: function stop(callback) {
|
||||
if (this._session && this._session.state === "connected") {
|
||||
this._session.terminate();
|
||||
}
|
||||
|
||||
delete this._session;
|
||||
|
||||
if (callback) {
|
||||
callback(true);
|
||||
}
|
||||
},
|
||||
|
||||
remoteMedia: function remoteMedia(callback, listener) {
|
||||
if (callback) {
|
||||
if (!this._session) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
callback(new RemoteMedia(this._session, listener));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* RemoteMedia provides a wrapper for using Presentation API to control Firefox TV app.
|
||||
* The server implementation must be built into the Firefox TV receiver app.
|
||||
* see https://github.com/mozilla-b2g/gaia/tree/master/tv_apps/fling-player
|
||||
*/
|
||||
function RemoteMedia(session, listener) {
|
||||
this._session = session ;
|
||||
this._listener = listener;
|
||||
this._status = STATE_UNINIT;
|
||||
|
||||
this._session.addEventListener("message", this);
|
||||
this._session.addEventListener("statechange", this);
|
||||
|
||||
if (this._listener && "onRemoteMediaStart" in this._listener) {
|
||||
Services.tm.mainThread.dispatch((function() {
|
||||
this._listener.onRemoteMediaStart(this);
|
||||
}).bind(this), Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
RemoteMedia.prototype = {
|
||||
_seq: 0,
|
||||
|
||||
handleEvent: function(e) {
|
||||
switch (e.type) {
|
||||
case "message":
|
||||
this._onmessage(e);
|
||||
break;
|
||||
case "statechange":
|
||||
this._onstatechange(e);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_onmessage: function(e) {
|
||||
DEBUG && debug("onmessage: " + e.data);
|
||||
if (this.status === STATE_SHUTDOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.data.indexOf("stopped") > -1) {
|
||||
if (this.status !== STATE_PAUSED) {
|
||||
this._status = STATE_PAUSED;
|
||||
if (this._listener && "onRemoteMediaStatus" in this._listener) {
|
||||
this._listener.onRemoteMediaStatus(this);
|
||||
}
|
||||
}
|
||||
} else if (e.data.indexOf("playing") > -1) {
|
||||
if (this.status !== STATE_STARTED) {
|
||||
this._status = STATE_STARTED;
|
||||
if (this._listener && "onRemoteMediaStatus" in this._listener) {
|
||||
this._listener.onRemoteMediaStatus(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onstatechange: function(e) {
|
||||
DEBUG && debug("onstatechange: " + this._session.state);
|
||||
if (this._session.state !== "connected") {
|
||||
this._status = STATE_SHUTDOWN;
|
||||
if (this._listener && "onRemoteMediaStop" in this._listener) {
|
||||
this._listener.onRemoteMediaStop(this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_sendCommand: function(command, data) {
|
||||
let msg = {
|
||||
'type': command,
|
||||
'seq': ++this._seq
|
||||
};
|
||||
|
||||
if (data) {
|
||||
for (var k in data) {
|
||||
msg[k] = data[k];
|
||||
}
|
||||
}
|
||||
|
||||
let raw = JSON.stringify(msg);
|
||||
DEBUG && debug("send command: " + raw);
|
||||
|
||||
this._session.send(raw);
|
||||
},
|
||||
|
||||
shutdown: function shutdown() {
|
||||
DEBUG && debug("RemoteMedia - shutdown");
|
||||
this._sendCommand("close");
|
||||
},
|
||||
|
||||
play: function play() {
|
||||
DEBUG && debug("RemoteMedia - play");
|
||||
this._sendCommand("play");
|
||||
},
|
||||
|
||||
pause: function pause() {
|
||||
DEBUG && debug("RemoteMedia - pause");
|
||||
this._sendCommand("pause");
|
||||
},
|
||||
|
||||
load: function load(data) {
|
||||
DEBUG && debug("RemoteMedia - load: " + data);
|
||||
this._sendCommand("load", { "url": data.source });
|
||||
|
||||
let deviceName;
|
||||
if (Services.appinfo.widgetToolkit == "android") {
|
||||
deviceName = sysInfo.get("device");
|
||||
} else {
|
||||
deviceName = sysInfo.get("host");
|
||||
}
|
||||
this._sendCommand("device-info", { "displayName": deviceName });
|
||||
},
|
||||
|
||||
get status() {
|
||||
return this._status;
|
||||
}
|
||||
}
|
@ -57,6 +57,7 @@ var SimpleServiceDiscovery = {
|
||||
_searchTimestamp: 0,
|
||||
_searchTimeout: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
|
||||
_searchRepeat: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
|
||||
_discoveryMethods: [],
|
||||
|
||||
_forceTrailingSlash: function(aURL) {
|
||||
// Cleanup the URL to make it consistent across devices
|
||||
@ -141,6 +142,9 @@ var SimpleServiceDiscovery = {
|
||||
// UDP broadcasts, so this is a way to skip discovery.
|
||||
this._searchFixedDevices();
|
||||
|
||||
// Look for any devices via registered external discovery mechanism.
|
||||
this._startExternalDiscovery();
|
||||
|
||||
// Perform a UDP broadcast to search for SSDP devices
|
||||
let socket = Cc["@mozilla.org/network/udp-socket;1"].createInstance(Ci.nsIUDPSocket);
|
||||
try {
|
||||
@ -226,6 +230,8 @@ var SimpleServiceDiscovery = {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._stopExternalDiscovery();
|
||||
},
|
||||
|
||||
getSupportedExtensions: function() {
|
||||
@ -409,5 +415,21 @@ var SimpleServiceDiscovery = {
|
||||
|
||||
// Make sure we remember this service is not stale
|
||||
this._services.get(service.uuid).lastPing = this._searchTimestamp;
|
||||
}
|
||||
},
|
||||
|
||||
addExternalDiscovery: function(discovery) {
|
||||
this._discoveryMethods.push(discovery);
|
||||
},
|
||||
|
||||
_startExternalDiscovery: function() {
|
||||
for (let discovery of this._discoveryMethods) {
|
||||
discovery.startDiscovery();
|
||||
}
|
||||
},
|
||||
|
||||
_stopExternalDiscovery: function() {
|
||||
for (let discovery of this._discoveryMethods) {
|
||||
discovery.stopDiscovery();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -3043,14 +3043,22 @@ this.AddonManager = {
|
||||
// The combination of all scopes.
|
||||
SCOPE_ALL: 31,
|
||||
|
||||
// 1-15 are different built-in views for the add-on type
|
||||
// Add-on type is expected to be displayed in the UI in a list.
|
||||
VIEW_TYPE_LIST: "list",
|
||||
|
||||
// Constants describing how add-on types behave.
|
||||
|
||||
// If no add-ons of a type are installed, then the category for that add-on
|
||||
// type should be hidden in the UI.
|
||||
TYPE_UI_HIDE_EMPTY: 16,
|
||||
// Indicates that this add-on type supports the ask-to-activate state.
|
||||
// That is, add-ons of this type can be set to be optionally enabled
|
||||
// on a case-by-case basis.
|
||||
TYPE_SUPPORTS_ASK_TO_ACTIVATE: 32,
|
||||
// The add-on type natively supports undo for restartless uninstalls.
|
||||
// If this flag is not specified, the UI is expected to handle this via
|
||||
// disabling the add-on, and performing the actual uninstall at a later time.
|
||||
TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL: 64,
|
||||
|
||||
// Constants for Addon.applyBackgroundUpdates.
|
||||
// Indicates that the Addon should not update automatically.
|
||||
|
@ -1718,7 +1718,7 @@ function doPendingUninstalls(aListBox) {
|
||||
var listitem = aListBox.firstChild;
|
||||
while (listitem) {
|
||||
if (listitem.getAttribute("pending") == "uninstall" &&
|
||||
!listitem.isPending("uninstall"))
|
||||
!(listitem.opRequiresRestart("UNINSTALL")))
|
||||
items.push(listitem.mAddon);
|
||||
listitem = listitem.nextSibling;
|
||||
}
|
||||
|
@ -745,6 +745,16 @@
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="typeHasFlag">
|
||||
<parameter name="aFlag"/>
|
||||
<body><![CDATA[
|
||||
let flag = AddonManager["TYPE_" + aFlag];
|
||||
let type = AddonManager.addonTypes[this.mAddon.type];
|
||||
|
||||
return !!(type.flags & flag);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="onUninstalled">
|
||||
<body><![CDATA[
|
||||
this.parentNode.removeChild(this);
|
||||
@ -1306,8 +1316,7 @@
|
||||
this._preferencesBtn.hidden = (!this.mAddon.optionsURL) ||
|
||||
this.mAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO;
|
||||
|
||||
let addonType = AddonManager.addonTypes[this.mAddon.type];
|
||||
if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) {
|
||||
if (this.typeHasFlag("SUPPORTS_ASK_TO_ACTIVATE")) {
|
||||
this._enableBtn.disabled = true;
|
||||
this._disableBtn.disabled = true;
|
||||
this._askToActivateMenuitem.disabled = !this.hasPermission("ask_to_activate");
|
||||
@ -1525,9 +1534,11 @@
|
||||
|
||||
<method name="uninstall">
|
||||
<body><![CDATA[
|
||||
// If uninstalling does not require a restart then just disable it
|
||||
// and show the undo UI.
|
||||
if (!this.opRequiresRestart("uninstall")) {
|
||||
// If uninstalling does not require a restart and the type doesn't
|
||||
// support undoing of restartless uninstalls, then we fake it by
|
||||
// just disabling it it, and doing the real uninstall later.
|
||||
if (!this.opRequiresRestart("uninstall") &&
|
||||
!this.typeHasFlag("SUPPORTS_UNDO_RESTARTLESS_UNINSTALL")) {
|
||||
this.setAttribute("wasDisabled", this.mAddon.userDisabled);
|
||||
|
||||
// We must set userDisabled to true first, this will call
|
||||
@ -1537,7 +1548,7 @@
|
||||
// This won't update any other add-on manager views (bug 582002)
|
||||
this.setAttribute("pending", "uninstall");
|
||||
} else {
|
||||
this.mAddon.uninstall();
|
||||
this.mAddon.uninstall(true);
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
@ -1773,7 +1784,7 @@
|
||||
[this.mAddon.name],
|
||||
1);
|
||||
|
||||
if (!this.isPending("uninstall"))
|
||||
if (!this.opRequiresRestart("uninstall"))
|
||||
this._restartBtn.setAttribute("hidden", true);
|
||||
|
||||
gEventManager.registerAddonListener(this, this.mAddon.id);
|
||||
|
@ -3187,6 +3187,19 @@ this.XPIProvider = {
|
||||
// install location.
|
||||
if (!manifest) {
|
||||
logger.debug("Processing uninstall of " + id + " in " + location.name);
|
||||
|
||||
try {
|
||||
let addonFile = location.getLocationForID(id);
|
||||
let addonToUninstall = syncLoadManifestFromFile(addonFile, location);
|
||||
if (addonToUninstall.bootstrap) {
|
||||
this.callBootstrapMethod(addonToUninstall, addonToUninstall._sourceBundle,
|
||||
"uninstall", BOOTSTRAP_REASONS.ADDON_UNINSTALL);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("Failed to call uninstall for " + id, e);
|
||||
}
|
||||
|
||||
try {
|
||||
location.uninstallAddon(id);
|
||||
seenFiles.push(stageDirEntry.leafName);
|
||||
@ -4764,10 +4777,14 @@ this.XPIProvider = {
|
||||
*
|
||||
* @param aAddon
|
||||
* The DBAddonInternal to uninstall
|
||||
* @param aForcePending
|
||||
* Force this addon into the pending uninstall state, even if
|
||||
* it isn't marked as requiring a restart (used e.g. while the
|
||||
* add-on manager is open and offering an "undo" button)
|
||||
* @throws if the addon cannot be uninstalled because it is in an install
|
||||
* location that does not allow it
|
||||
*/
|
||||
uninstallAddon: function(aAddon) {
|
||||
uninstallAddon: function(aAddon, aForcePending) {
|
||||
if (!(aAddon.inDatabase))
|
||||
throw new Error("Cannot uninstall addon " + aAddon.id + " because it is not installed");
|
||||
|
||||
@ -4775,6 +4792,16 @@ this.XPIProvider = {
|
||||
throw new Error("Cannot uninstall addon " + aAddon.id
|
||||
+ " from locked install location " + aAddon._installLocation.name);
|
||||
|
||||
// Inactive add-ons don't require a restart to uninstall
|
||||
let requiresRestart = this.uninstallRequiresRestart(aAddon);
|
||||
|
||||
// if makePending is true, we don't actually apply the uninstall,
|
||||
// we just mark the addon as having a pending uninstall
|
||||
let makePending = aForcePending || requiresRestart;
|
||||
|
||||
if (makePending && aAddon.pendingUninstall)
|
||||
throw new Error("Add-on is already marked to be uninstalled");
|
||||
|
||||
aAddon._hasResourceCache.clear();
|
||||
|
||||
if (aAddon._updateCheck) {
|
||||
@ -4782,16 +4809,19 @@ this.XPIProvider = {
|
||||
aAddon._updateCheck.cancel();
|
||||
}
|
||||
|
||||
// Inactive add-ons don't require a restart to uninstall
|
||||
let requiresRestart = this.uninstallRequiresRestart(aAddon);
|
||||
let wasPending = aAddon.pendingUninstall;
|
||||
|
||||
if (requiresRestart) {
|
||||
// We create an empty directory in the staging directory to indicate that
|
||||
// an uninstall is necessary on next startup.
|
||||
let stage = aAddon._installLocation.getStagingDir();
|
||||
stage.append(aAddon.id);
|
||||
if (!stage.exists())
|
||||
stage.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
if (makePending) {
|
||||
// We create an empty directory in the staging directory to indicate
|
||||
// that an uninstall is necessary on next startup. Temporary add-ons are
|
||||
// automatically uninstalled on shutdown anyway so there is no need to
|
||||
// do this for them.
|
||||
if (aAddon._installLocation.name != KEY_APP_TEMPORARY) {
|
||||
let stage = aAddon._installLocation.getStagingDir();
|
||||
stage.append(aAddon.id);
|
||||
if (!stage.exists())
|
||||
stage.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
}
|
||||
|
||||
XPIDatabase.setAddonProperties(aAddon, {
|
||||
pendingUninstall: true
|
||||
@ -4811,8 +4841,16 @@ this.XPIProvider = {
|
||||
return;
|
||||
|
||||
let wrapper = aAddon.wrapper;
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper,
|
||||
requiresRestart);
|
||||
|
||||
// If the add-on wasn't already pending uninstall then notify listeners.
|
||||
if (!wasPending) {
|
||||
// Passing makePending as the requiresRestart parameter is a little
|
||||
// strange as in some cases this operation can complete without a restart
|
||||
// so really this is now saying that the uninstall isn't going to happen
|
||||
// immediately but will happen later.
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper,
|
||||
makePending);
|
||||
}
|
||||
|
||||
// Reveal the highest priority add-on with the same ID
|
||||
function revealAddon(aAddon) {
|
||||
@ -4850,7 +4888,7 @@ this.XPIProvider = {
|
||||
}
|
||||
}
|
||||
|
||||
if (!requiresRestart) {
|
||||
if (!makePending) {
|
||||
if (aAddon.bootstrap) {
|
||||
if (aAddon.active) {
|
||||
this.callBootstrapMethod(aAddon, aAddon._sourceBundle, "shutdown",
|
||||
@ -4869,6 +4907,12 @@ this.XPIProvider = {
|
||||
|
||||
findAddonAndReveal(aAddon.id);
|
||||
}
|
||||
else if (aAddon.bootstrap && aAddon.active && !this.disableRequiresRestart(aAddon)) {
|
||||
this.callBootstrapMethod(aAddon, aAddon._sourceBundle, "shutdown",
|
||||
BOOTSTRAP_REASONS.ADDON_UNINSTALL);
|
||||
this.unloadBootstrapScope(aAddon.id);
|
||||
XPIDatabase.updateAddonActive(aAddon, false);
|
||||
}
|
||||
|
||||
// Notify any other providers that a new theme has been enabled
|
||||
if (aAddon.type == "theme" && aAddon.active)
|
||||
@ -4884,8 +4928,11 @@ this.XPIProvider = {
|
||||
cancelUninstallAddon: function(aAddon) {
|
||||
if (!(aAddon.inDatabase))
|
||||
throw new Error("Can only cancel uninstall for installed addons.");
|
||||
if (!aAddon.pendingUninstall)
|
||||
throw new Error("Add-on is not marked to be uninstalled");
|
||||
|
||||
aAddon._installLocation.cleanStagingDir([aAddon.id]);
|
||||
if (aAddon._installLocation.name != KEY_APP_TEMPORARY)
|
||||
aAddon._installLocation.cleanStagingDir([aAddon.id]);
|
||||
|
||||
XPIDatabase.setAddonProperties(aAddon, {
|
||||
pendingUninstall: false
|
||||
@ -4900,6 +4947,12 @@ this.XPIProvider = {
|
||||
let wrapper = aAddon.wrapper;
|
||||
AddonManagerPrivate.callAddonListeners("onOperationCancelled", wrapper);
|
||||
|
||||
if (aAddon.bootstrap && !aAddon.disabled && !this.enableRequiresRestart(aAddon)) {
|
||||
this.callBootstrapMethod(aAddon, aAddon._sourceBundle, "startup",
|
||||
BOOTSTRAP_REASONS.ADDON_INSTALL);
|
||||
XPIDatabase.updateAddonActive(aAddon, true);
|
||||
}
|
||||
|
||||
// Notify any other providers that this theme is now enabled again.
|
||||
if (aAddon.type == "theme" && aAddon.active)
|
||||
AddonManagerPrivate.notifyAddonChanged(aAddon.id, aAddon.type, false);
|
||||
@ -5860,12 +5913,17 @@ AddonInstall.prototype = {
|
||||
let installedUnpacked = 0;
|
||||
yield this.installLocation.requestStagingDir();
|
||||
|
||||
// Remove any staged items for this add-on
|
||||
stagedAddon.append(this.addon.id);
|
||||
yield removeAsync(stagedAddon);
|
||||
stagedAddon.leafName = this.addon.id + ".xpi";
|
||||
yield removeAsync(stagedAddon);
|
||||
|
||||
// First stage the file regardless of whether restarting is necessary
|
||||
if (this.addon.unpack || Preferences.get(PREF_XPI_UNPACK, false)) {
|
||||
logger.debug("Addon " + this.addon.id + " will be installed as " +
|
||||
"an unpacked directory");
|
||||
stagedAddon.append(this.addon.id);
|
||||
yield removeAsync(stagedAddon);
|
||||
stagedAddon.leafName = this.addon.id;
|
||||
yield OS.File.makeDir(stagedAddon.path);
|
||||
yield ZipUtils.extractFilesAsync(this.file, stagedAddon);
|
||||
installedUnpacked = 1;
|
||||
@ -5873,8 +5931,7 @@ AddonInstall.prototype = {
|
||||
else {
|
||||
logger.debug("Addon " + this.addon.id + " will be installed as " +
|
||||
"a packed xpi");
|
||||
stagedAddon.append(this.addon.id + ".xpi");
|
||||
yield removeAsync(stagedAddon);
|
||||
stagedAddon.leafName = this.addon.id + ".xpi";
|
||||
yield OS.File.copy(this.file.path, stagedAddon.path);
|
||||
}
|
||||
|
||||
@ -7054,21 +7111,13 @@ AddonWrapper.prototype = {
|
||||
return addonFor(this).isCompatibleWith(aAppVersion, aPlatformVersion);
|
||||
},
|
||||
|
||||
uninstall: function() {
|
||||
uninstall: function(alwaysAllowUndo) {
|
||||
let addon = addonFor(this);
|
||||
if (!(addon.inDatabase))
|
||||
throw new Error("Cannot uninstall an add-on that isn't installed");
|
||||
if (addon.pendingUninstall)
|
||||
throw new Error("Add-on is already marked to be uninstalled");
|
||||
XPIProvider.uninstallAddon(addon);
|
||||
XPIProvider.uninstallAddon(addon, alwaysAllowUndo);
|
||||
},
|
||||
|
||||
cancelUninstall: function() {
|
||||
let addon = addonFor(this);
|
||||
if (!(addon.inDatabase))
|
||||
throw new Error("Cannot cancel uninstall for an add-on that isn't installed");
|
||||
if (!addon.pendingUninstall)
|
||||
throw new Error("Add-on is not marked to be uninstalled");
|
||||
XPIProvider.cancelUninstallAddon(addon);
|
||||
},
|
||||
|
||||
@ -8137,18 +8186,19 @@ WinRegInstallLocation.prototype = {
|
||||
var addonTypes = [
|
||||
new AddonManagerPrivate.AddonType("extension", URI_EXTENSION_STRINGS,
|
||||
STRING_TYPE_NAME,
|
||||
AddonManager.VIEW_TYPE_LIST, 4000),
|
||||
AddonManager.VIEW_TYPE_LIST, 4000,
|
||||
AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL),
|
||||
new AddonManagerPrivate.AddonType("theme", URI_EXTENSION_STRINGS,
|
||||
STRING_TYPE_NAME,
|
||||
AddonManager.VIEW_TYPE_LIST, 5000),
|
||||
new AddonManagerPrivate.AddonType("dictionary", URI_EXTENSION_STRINGS,
|
||||
STRING_TYPE_NAME,
|
||||
AddonManager.VIEW_TYPE_LIST, 7000,
|
||||
AddonManager.TYPE_UI_HIDE_EMPTY),
|
||||
AddonManager.TYPE_UI_HIDE_EMPTY | AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL),
|
||||
new AddonManagerPrivate.AddonType("locale", URI_EXTENSION_STRINGS,
|
||||
STRING_TYPE_NAME,
|
||||
AddonManager.VIEW_TYPE_LIST, 8000,
|
||||
AddonManager.TYPE_UI_HIDE_EMPTY),
|
||||
AddonManager.TYPE_UI_HIDE_EMPTY | AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL),
|
||||
];
|
||||
|
||||
// We only register experiments support if the application supports them.
|
||||
@ -8161,7 +8211,7 @@ if (Preferences.get("experiments.supported", false)) {
|
||||
URI_EXTENSION_STRINGS,
|
||||
STRING_TYPE_NAME,
|
||||
AddonManager.VIEW_TYPE_LIST, 11000,
|
||||
AddonManager.TYPE_UI_HIDE_EMPTY));
|
||||
AddonManager.TYPE_UI_HIDE_EMPTY | AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL));
|
||||
}
|
||||
|
||||
AddonManagerPrivate.registerProvider(XPIProvider, addonTypes);
|
||||
|
1
toolkit/mozapps/extensions/test/addons/test_undoincompatible/bootstrap.js
vendored
Normal file
1
toolkit/mozapps/extensions/test/addons/test_undoincompatible/bootstrap.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
Components.utils.import("resource://xpcshell-data/BootstrapMonitor.jsm").monitor(this);
|
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>incompatible@tests.mozilla.org</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Incompatible Addon</em:name>
|
||||
<em:description>I am incompatible</em:description>
|
||||
|
||||
<em:iconURL>chrome://foo/skin/icon.png</em:iconURL>
|
||||
<em:aboutURL>chrome://foo/content/about.xul</em:aboutURL>
|
||||
<em:optionsURL>chrome://foo/content/options.xul</em:optionsURL>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>xpcshell@tests.mozilla.org</em:id>
|
||||
<em:minVersion>2</em:minVersion>
|
||||
<em:maxVersion>2</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
1
toolkit/mozapps/extensions/test/addons/test_undouninstall1/bootstrap.js
vendored
Normal file
1
toolkit/mozapps/extensions/test/addons/test_undouninstall1/bootstrap.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
Components.utils.import("resource://xpcshell-data/BootstrapMonitor.jsm").monitor(this);
|
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>undouninstall1@tests.mozilla.org</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Test Bootstrap 1</em:name>
|
||||
<em:description>Test Description</em:description>
|
||||
|
||||
<em:iconURL>chrome://foo/skin/icon.png</em:iconURL>
|
||||
<em:aboutURL>chrome://foo/content/about.xul</em:aboutURL>
|
||||
<em:optionsURL>chrome://foo/content/options.xul</em:optionsURL>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>xpcshell@tests.mozilla.org</em:id>
|
||||
<em:minVersion>1</em:minVersion>
|
||||
<em:maxVersion>1</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
@ -110,8 +110,7 @@ add_task(function*() {
|
||||
// Force XBL to apply
|
||||
item.clientTop;
|
||||
|
||||
ok(aAddon.userDisabled, "Add-on should be disabled");
|
||||
ok(!aAddon.pendingUninstall, "Add-on should not be pending uninstall");
|
||||
ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
|
||||
is_element_visible(get_class_node(item, "pending"), "Pending message should be visible");
|
||||
|
||||
yield install_addon("browser_bug596336_2");
|
||||
@ -139,8 +138,7 @@ add_task(function*() {
|
||||
// Force XBL to apply
|
||||
item.clientTop;
|
||||
|
||||
ok(aAddon.userDisabled, "Add-on should be disabled");
|
||||
ok(!aAddon.pendingUninstall, "Add-on should not be pending uninstall");
|
||||
ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
|
||||
is_element_visible(get_class_node(item, "pending"), "Pending message should be visible");
|
||||
|
||||
yield install_addon("browser_bug596336_2");
|
||||
|
@ -166,7 +166,7 @@ add_test(function() {
|
||||
|
||||
is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
|
||||
|
||||
ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
|
||||
ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
|
||||
ok(!aAddon.isActive, "Add-on should be inactive");
|
||||
|
||||
button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
|
||||
@ -221,7 +221,7 @@ add_test(function() {
|
||||
|
||||
is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
|
||||
|
||||
ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
|
||||
ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
|
||||
ok(!aAddon.isActive, "Add-on should be inactive");
|
||||
|
||||
button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
|
||||
@ -342,7 +342,7 @@ add_test(function() {
|
||||
|
||||
is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
|
||||
|
||||
ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
|
||||
ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
|
||||
ok(!aAddon.isActive, "Add-on should be inactive");
|
||||
|
||||
button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
|
||||
@ -405,7 +405,7 @@ add_test(function() {
|
||||
|
||||
is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
|
||||
|
||||
ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
|
||||
ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
|
||||
ok(!aAddon.isActive, "Add-on should be inactive");
|
||||
|
||||
button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
|
||||
@ -531,7 +531,7 @@ add_test(function() {
|
||||
isnot(item, null, "Should have found the add-on in the list");
|
||||
is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
|
||||
|
||||
ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
|
||||
ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
|
||||
ok(!aAddon.isActive, "Add-on should be inactive");
|
||||
|
||||
// Force XBL to apply
|
||||
@ -598,7 +598,7 @@ add_test(function() {
|
||||
isnot(item, null, "Should have found the add-on in the list");
|
||||
is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
|
||||
|
||||
ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
|
||||
ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
|
||||
ok(!aAddon.isActive, "Add-on should be inactive");
|
||||
|
||||
// Force XBL to apply
|
||||
@ -808,8 +808,7 @@ add_test(function() {
|
||||
item.clientTop;
|
||||
|
||||
is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
|
||||
|
||||
ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
|
||||
ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
|
||||
ok(!aAddon.isActive, "Add-on should be inactive");
|
||||
|
||||
button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
|
||||
@ -888,7 +887,7 @@ add_test(function() {
|
||||
|
||||
is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
|
||||
|
||||
ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
|
||||
ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
|
||||
ok(!aAddon.isActive, "Add-on should be inactive");
|
||||
|
||||
button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
|
||||
@ -964,7 +963,7 @@ add_test(function() {
|
||||
|
||||
is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
|
||||
|
||||
ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
|
||||
ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
|
||||
ok(!aAddon.isActive, "Add-on should be inactive");
|
||||
|
||||
button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
|
||||
@ -1046,7 +1045,7 @@ add_test(function() {
|
||||
|
||||
is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
|
||||
|
||||
ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
|
||||
ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
|
||||
ok(!aAddon.isActive, "Add-on should be inactive");
|
||||
|
||||
button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
|
||||
|
@ -682,7 +682,8 @@ function MockProvider(aUseAsyncCallbacks, aTypes) {
|
||||
id: "extension",
|
||||
name: "Extensions",
|
||||
uiPriority: 4000,
|
||||
flags: AddonManager.TYPE_UI_VIEW_LIST
|
||||
flags: AddonManager.TYPE_UI_VIEW_LIST |
|
||||
AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL,
|
||||
}] : aTypes;
|
||||
|
||||
var self = this;
|
||||
@ -1134,7 +1135,8 @@ function MockAddon(aId, aName, aType, aOperationsRequiringRestart) {
|
||||
|
||||
MockAddon.prototype = {
|
||||
get shouldBeActive() {
|
||||
return !this.appDisabled && !this._userDisabled;
|
||||
return !this.appDisabled && !this._userDisabled &&
|
||||
!(this.pendingOperations & AddonManager.PENDING_UNINSTALL);
|
||||
},
|
||||
|
||||
get appDisabled() {
|
||||
@ -1206,16 +1208,19 @@ MockAddon.prototype = {
|
||||
// Tests can implement this if they need to
|
||||
},
|
||||
|
||||
uninstall: function() {
|
||||
if (this.pendingOperations & AddonManager.PENDING_UNINSTALL)
|
||||
uninstall: function(aAlwaysAllowUndo = false) {
|
||||
if ((this.operationsRequiringRestart & AddonManager.OP_NEED_RESTART_UNINSTALL)
|
||||
&& this.pendingOperations & AddonManager.PENDING_UNINSTALL)
|
||||
throw Components.Exception("Add-on is already pending uninstall");
|
||||
|
||||
var needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL);
|
||||
var needsRestart = aAlwaysAllowUndo || !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL);
|
||||
this.pendingOperations |= AddonManager.PENDING_UNINSTALL;
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalling", this, needsRestart);
|
||||
if (!needsRestart) {
|
||||
this.pendingOperations -= AddonManager.PENDING_UNINSTALL;
|
||||
this._provider.removeAddon(this);
|
||||
} else if (!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE)) {
|
||||
this.isActive = false;
|
||||
}
|
||||
},
|
||||
|
||||
@ -1224,6 +1229,7 @@ MockAddon.prototype = {
|
||||
throw Components.Exception("Add-on is not pending uninstall");
|
||||
|
||||
this.pendingOperations -= AddonManager.PENDING_UNINSTALL;
|
||||
this.isActive = this.shouldBeActive;
|
||||
AddonManagerPrivate.callAddonListeners("onOperationCancelled", this);
|
||||
},
|
||||
|
||||
|
@ -2015,7 +2015,7 @@ function callback_soon(aFunction) {
|
||||
* its callback.
|
||||
*/
|
||||
function promiseAddonsByIDs(list) {
|
||||
return new Promise((resolve, reject) => AddonManager.getAddonsByIDs(list, resolve));
|
||||
return new Promise(resolve => AddonManager.getAddonsByIDs(list, resolve));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2026,7 +2026,20 @@ function promiseAddonsByIDs(list) {
|
||||
* @resolve {AddonWrapper} The corresponding add-on, or null.
|
||||
*/
|
||||
function promiseAddonByID(aId) {
|
||||
return new Promise((resolve, reject) => AddonManager.getAddonByID(aId, resolve));
|
||||
return new Promise(resolve => AddonManager.getAddonByID(aId, resolve));
|
||||
}
|
||||
|
||||
/**
|
||||
* A promise-based variant of AddonManager.getAddonsWithOperationsByTypes
|
||||
*
|
||||
* @param {array} aTypes The first argument to
|
||||
* AddonManager.getAddonsWithOperationsByTypes
|
||||
* @return {promise}
|
||||
* @resolve {array} The list of add-ons sent by
|
||||
* AddonManaget.getAddonsWithOperationsByTypes to its callback.
|
||||
*/
|
||||
function promiseAddonsWithOperationsByTypes(aTypes) {
|
||||
return new Promise(resolve => AddonManager.getAddonsWithOperationsByTypes(aTypes, resolve));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,421 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// This verifies that forcing undo for uninstall works for themes
|
||||
Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm");
|
||||
|
||||
const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin";
|
||||
|
||||
var defaultTheme = {
|
||||
id: "default@tests.mozilla.org",
|
||||
version: "1.0",
|
||||
name: "Test 1",
|
||||
internalName: "classic/1.0",
|
||||
targetApplications: [{
|
||||
id: "xpcshell@tests.mozilla.org",
|
||||
minVersion: "1",
|
||||
maxVersion: "1"
|
||||
}]
|
||||
};
|
||||
|
||||
var theme1 = {
|
||||
id: "theme1@tests.mozilla.org",
|
||||
version: "1.0",
|
||||
name: "Test 1",
|
||||
internalName: "theme1",
|
||||
targetApplications: [{
|
||||
id: "xpcshell@tests.mozilla.org",
|
||||
minVersion: "1",
|
||||
maxVersion: "1"
|
||||
}]
|
||||
};
|
||||
|
||||
const profileDir = gProfD.clone();
|
||||
profileDir.append("extensions");
|
||||
|
||||
function dummyLWTheme(id) {
|
||||
return {
|
||||
id: id || Math.random().toString(),
|
||||
name: Math.random().toString(),
|
||||
headerURL: "http://lwttest.invalid/a.png",
|
||||
footerURL: "http://lwttest.invalid/b.png",
|
||||
textcolor: Math.random().toString(),
|
||||
accentcolor: Math.random().toString()
|
||||
};
|
||||
}
|
||||
|
||||
// Sets up the profile by installing an add-on.
|
||||
function run_test() {
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
|
||||
startupManager();
|
||||
do_register_cleanup(promiseShutdownManager);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* checkDefault() {
|
||||
writeInstallRDFForExtension(defaultTheme, profileDir);
|
||||
yield promiseRestartManager();
|
||||
|
||||
let d = yield promiseAddonByID("default@tests.mozilla.org");
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_true(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
});
|
||||
|
||||
// Tests that uninstalling an enabled theme offers the option to undo
|
||||
add_task(function* uninstallEnabledOffersUndo() {
|
||||
writeInstallRDFForExtension(theme1, profileDir);
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
let t1 = yield promiseAddonByID("theme1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_true(t1.userDisabled);
|
||||
|
||||
t1.userDisabled = false;
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
let d = null;
|
||||
[ t1, d ] = yield promiseAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
"default@tests.mozilla.org"]);
|
||||
do_check_neq(d, null);
|
||||
do_check_false(d.isActive);
|
||||
do_check_true(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_true(t1.isActive);
|
||||
do_check_false(t1.userDisabled);
|
||||
do_check_eq(t1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "theme1");
|
||||
|
||||
prepare_test({
|
||||
"default@tests.mozilla.org": [
|
||||
"onEnabling"
|
||||
],
|
||||
"theme1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
t1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_false(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_ENABLE);
|
||||
|
||||
do_check_true(t1.isActive);
|
||||
do_check_false(t1.userDisabled);
|
||||
do_check_true(hasFlag(t1.pendingOperations, AddonManager.PENDING_UNINSTALL));
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "theme1");
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
[ t1, d ] = yield promiseAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
"default@tests.mozilla.org"]);
|
||||
do_check_neq(d, null);
|
||||
do_check_true(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_eq(t1, null);
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
});
|
||||
|
||||
//Tests that uninstalling an enabled theme can be undone
|
||||
add_task(function* canUndoUninstallEnabled() {
|
||||
writeInstallRDFForExtension(theme1, profileDir);
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
let t1 = yield promiseAddonByID("theme1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_true(t1.userDisabled);
|
||||
|
||||
t1.userDisabled = false;
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
let d = null;
|
||||
[ t1, d ] = yield promiseAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
"default@tests.mozilla.org"]);
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_false(d.isActive);
|
||||
do_check_true(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_true(t1.isActive);
|
||||
do_check_false(t1.userDisabled);
|
||||
do_check_eq(t1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "theme1");
|
||||
|
||||
prepare_test({
|
||||
"default@tests.mozilla.org": [
|
||||
"onEnabling"
|
||||
],
|
||||
"theme1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
t1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_false(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_ENABLE);
|
||||
|
||||
do_check_true(t1.isActive);
|
||||
do_check_false(t1.userDisabled);
|
||||
do_check_true(hasFlag(t1.pendingOperations, AddonManager.PENDING_UNINSTALL));
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "theme1");
|
||||
|
||||
prepare_test({
|
||||
"default@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
],
|
||||
"theme1@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
});
|
||||
t1.cancelUninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_false(d.isActive);
|
||||
do_check_true(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_true(t1.isActive);
|
||||
do_check_false(t1.userDisabled);
|
||||
do_check_eq(t1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
[ t1, d ] = yield promiseAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
"default@tests.mozilla.org"]);
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_false(d.isActive);
|
||||
do_check_true(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_true(t1.isActive);
|
||||
do_check_false(t1.userDisabled);
|
||||
do_check_eq(t1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "theme1");
|
||||
|
||||
t1.uninstall();
|
||||
yield promiseRestartManager();
|
||||
});
|
||||
|
||||
//Tests that uninstalling a disabled theme offers the option to undo
|
||||
add_task(function* uninstallDisabledOffersUndo() {
|
||||
writeInstallRDFForExtension(theme1, profileDir);
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
let [ t1, d ] = yield promiseAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
"default@tests.mozilla.org"]);
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_true(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_false(t1.isActive);
|
||||
do_check_true(t1.userDisabled);
|
||||
do_check_eq(t1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
prepare_test({
|
||||
"theme1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
t1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_true(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_false(t1.isActive);
|
||||
do_check_true(t1.userDisabled);
|
||||
do_check_true(hasFlag(t1.pendingOperations, AddonManager.PENDING_UNINSTALL));
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
[ t1, d ] = yield promiseAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
"default@tests.mozilla.org"]);
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_true(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_eq(t1, null);
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
});
|
||||
|
||||
//Tests that uninstalling a disabled theme can be undone
|
||||
add_task(function* canUndoUninstallDisabled() {
|
||||
writeInstallRDFForExtension(theme1, profileDir);
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
let [ t1, d ] = yield promiseAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
"default@tests.mozilla.org"]);
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_true(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_false(t1.isActive);
|
||||
do_check_true(t1.userDisabled);
|
||||
do_check_eq(t1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
prepare_test({
|
||||
"theme1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
t1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_true(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_false(t1.isActive);
|
||||
do_check_true(t1.userDisabled);
|
||||
do_check_true(hasFlag(t1.pendingOperations, AddonManager.PENDING_UNINSTALL));
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
prepare_test({
|
||||
"theme1@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
});
|
||||
t1.cancelUninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_true(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_false(t1.isActive);
|
||||
do_check_true(t1.userDisabled);
|
||||
do_check_eq(t1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
[ t1, d ] = yield promiseAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
"default@tests.mozilla.org"]);
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_true(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_false(t1.isActive);
|
||||
do_check_true(t1.userDisabled);
|
||||
do_check_eq(t1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
t1.uninstall();
|
||||
yield promiseRestartManager();
|
||||
});
|
||||
|
||||
//Tests that uninstalling an enabled lightweight theme offers the option to undo
|
||||
add_task(function* uninstallLWTOffersUndo() {
|
||||
// skipped since lightweight themes don't support undoable uninstall yet
|
||||
return;
|
||||
LightweightThemeManager.currentTheme = dummyLWTheme("theme1");
|
||||
|
||||
let [ t1, d ] = yield promiseAddonsByIDs(["theme1@personas.mozilla.org",
|
||||
"default@tests.mozilla.org"]);
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_false(d.isActive);
|
||||
do_check_true(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_neq(t1, null);
|
||||
do_check_true(t1.isActive);
|
||||
do_check_false(t1.userDisabled);
|
||||
do_check_eq(t1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
prepare_test({
|
||||
"default@tests.mozilla.org": [
|
||||
"onEnabling"
|
||||
],
|
||||
"theme1@personas.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
t1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_false(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_ENABLE);
|
||||
|
||||
do_check_true(t1.isActive);
|
||||
do_check_false(t1.userDisabled);
|
||||
do_check_true(hasFlag(t1.pendingOperations, AddonManager.PENDING_UNINSTALL));
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
[ t1, d ] = yield promiseAddonsByIDs(["theme1@personas.mozilla.org",
|
||||
"default@tests.mozilla.org"]);
|
||||
|
||||
do_check_neq(d, null);
|
||||
do_check_true(d.isActive);
|
||||
do_check_false(d.userDisabled);
|
||||
do_check_eq(d.pendingOperations, AddonManager.PENDING_NONE);
|
||||
|
||||
do_check_eq(t1, null);
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
});
|
792
toolkit/mozapps/extensions/test/xpcshell/test_undouninstall.js
Normal file
792
toolkit/mozapps/extensions/test/xpcshell/test_undouninstall.js
Normal file
@ -0,0 +1,792 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// This verifies that forcing undo for uninstall works
|
||||
|
||||
const APP_STARTUP = 1;
|
||||
const APP_SHUTDOWN = 2;
|
||||
const ADDON_ENABLE = 3;
|
||||
const ADDON_DISABLE = 4;
|
||||
const ADDON_INSTALL = 5;
|
||||
const ADDON_UNINSTALL = 6;
|
||||
const ADDON_UPGRADE = 7;
|
||||
const ADDON_DOWNGRADE = 8;
|
||||
|
||||
const ID = "undouninstall1@tests.mozilla.org";
|
||||
const INCOMPAT_ID = "incompatible@tests.mozilla.org";
|
||||
|
||||
var addon1 = {
|
||||
id: "addon1@tests.mozilla.org",
|
||||
version: "1.0",
|
||||
name: "Test 1",
|
||||
targetApplications: [{
|
||||
id: "xpcshell@tests.mozilla.org",
|
||||
minVersion: "1",
|
||||
maxVersion: "1"
|
||||
}]
|
||||
};
|
||||
|
||||
|
||||
const profileDir = gProfD.clone();
|
||||
profileDir.append("extensions");
|
||||
|
||||
BootstrapMonitor.init();
|
||||
|
||||
function getStartupReason(id) {
|
||||
let info = BootstrapMonitor.started.get(id);
|
||||
return info ? info.reason : undefined;
|
||||
}
|
||||
|
||||
function getShutdownReason(id) {
|
||||
let info = BootstrapMonitor.stopped.get(id);
|
||||
return info ? info.reason : undefined;
|
||||
}
|
||||
|
||||
function getInstallReason(id) {
|
||||
let info = BootstrapMonitor.installed.get(id);
|
||||
return info ? info.reason : undefined;
|
||||
}
|
||||
|
||||
function getUninstallReason(id) {
|
||||
let info = BootstrapMonitor.uninstalled.get(id);
|
||||
return info ? info.reason : undefined;
|
||||
}
|
||||
|
||||
function getStartupOldVersion(id) {
|
||||
let info = BootstrapMonitor.started.get(id);
|
||||
return info ? info.data.oldVersion : undefined;
|
||||
}
|
||||
|
||||
function getShutdownNewVersion(id) {
|
||||
let info = BootstrapMonitor.stopped.get(id);
|
||||
return info ? info.data.newVersion : undefined;
|
||||
}
|
||||
|
||||
function getInstallOldVersion(id) {
|
||||
let info = BootstrapMonitor.installed.get(id);
|
||||
return info ? info.data.oldVersion : undefined;
|
||||
}
|
||||
|
||||
function getUninstallNewVersion(id) {
|
||||
let info = BootstrapMonitor.uninstalled.get(id);
|
||||
return info ? info.data.newVersion : undefined;
|
||||
}
|
||||
|
||||
// Sets up the profile by installing an add-on.
|
||||
function run_test() {
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
|
||||
startupManager();
|
||||
do_register_cleanup(promiseShutdownManager);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* installAddon() {
|
||||
let olda1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
do_check_eq(olda1, null);
|
||||
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
yield promiseRestartManager();
|
||||
|
||||
let a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
do_check_true(isExtensionInAddonsList(profileDir, a1.id));
|
||||
do_check_eq(a1.pendingOperations, 0);
|
||||
do_check_in_crash_annotation(addon1.id, addon1.version);
|
||||
});
|
||||
|
||||
// Uninstalling an add-on should work.
|
||||
add_task(function* uninstallAddon() {
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
|
||||
let a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
do_check_eq(a1.pendingOperations, 0);
|
||||
do_check_neq(a1.operationsRequiringRestart &
|
||||
AddonManager.OP_NEEDS_RESTART_UNINSTALL, 0);
|
||||
a1.uninstall(true);
|
||||
do_check_true(hasFlag(a1.pendingOperations, AddonManager.PENDING_UNINSTALL));
|
||||
do_check_in_crash_annotation(addon1.id, addon1.version);
|
||||
|
||||
ensure_test_completed();
|
||||
|
||||
let list = yield promiseAddonsWithOperationsByTypes(null);
|
||||
|
||||
do_check_eq(list.length, 1);
|
||||
do_check_eq(list[0].id, "addon1@tests.mozilla.org");
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
do_check_eq(a1, null);
|
||||
do_check_false(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org"));
|
||||
do_check_not_in_crash_annotation(addon1.id, addon1.version);
|
||||
|
||||
var dest = profileDir.clone();
|
||||
dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
|
||||
do_check_false(dest.exists());
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
yield promiseRestartManager();
|
||||
});
|
||||
|
||||
// Cancelling the uninstall should send onOperationCancelled
|
||||
add_task(function* cancelUninstall() {
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
|
||||
let a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
do_check_true(isExtensionInAddonsList(profileDir, a1.id));
|
||||
do_check_eq(a1.pendingOperations, 0);
|
||||
a1.uninstall(true);
|
||||
do_check_true(hasFlag(a1.pendingOperations, AddonManager.PENDING_UNINSTALL));
|
||||
|
||||
ensure_test_completed();
|
||||
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
});
|
||||
a1.cancelUninstall();
|
||||
do_check_eq(a1.pendingOperations, 0);
|
||||
|
||||
ensure_test_completed();
|
||||
yield promiseRestartManager();
|
||||
|
||||
a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
do_check_true(isExtensionInAddonsList(profileDir, a1.id));
|
||||
});
|
||||
|
||||
// Uninstalling an item pending disable should still require a restart
|
||||
add_task(function* pendingDisableRequestRestart() {
|
||||
let a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
"onDisabling"
|
||||
]
|
||||
});
|
||||
a1.userDisabled = true;
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_true(hasFlag(AddonManager.PENDING_DISABLE, a1.pendingOperations));
|
||||
do_check_true(a1.isActive);
|
||||
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
a1.uninstall(true);
|
||||
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
do_check_true(hasFlag(AddonManager.PENDING_UNINSTALL, a1.pendingOperations));
|
||||
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
});
|
||||
a1.cancelUninstall();
|
||||
ensure_test_completed();
|
||||
do_check_true(hasFlag(AddonManager.PENDING_DISABLE, a1.pendingOperations));
|
||||
|
||||
yield promiseRestartManager();
|
||||
});
|
||||
|
||||
// Test that uninstalling an inactive item should still allow cancelling
|
||||
add_task(function* uninstallInactiveIsCancellable() {
|
||||
let a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
do_check_false(isExtensionInAddonsList(profileDir, a1.id));
|
||||
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
a1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
do_check_true(hasFlag(AddonManager.PENDING_UNINSTALL, a1.pendingOperations));
|
||||
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
});
|
||||
a1.cancelUninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
yield promiseRestartManager();
|
||||
});
|
||||
|
||||
//Test that an inactive item can be uninstalled
|
||||
add_task(function* uninstallInactive() {
|
||||
let a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
do_check_false(isExtensionInAddonsList(profileDir, a1.id));
|
||||
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
[ "onUninstalling", false ],
|
||||
"onUninstalled"
|
||||
]
|
||||
});
|
||||
a1.uninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID("addon1@tests.mozilla.org");
|
||||
do_check_eq(a1, null);
|
||||
});
|
||||
|
||||
// Tests that an enabled restartless add-on can be uninstalled and goes away
|
||||
// when the uninstall is committed
|
||||
add_task(function* uninstallRestartless() {
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
["onInstalling", false],
|
||||
"onInstalled"
|
||||
]
|
||||
}, [
|
||||
"onNewInstall",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded"
|
||||
]);
|
||||
yield promiseInstallAllFiles([do_get_addon("test_undouninstall1")]);
|
||||
ensure_test_completed();
|
||||
|
||||
let a1 = yield promiseAddonByID(ID);
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getInstallReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(getStartupReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
a1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID(ID);
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonInstalled(ID);
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
do_check_eq(getShutdownReason(ID), ADDON_UNINSTALL);
|
||||
do_check_true(hasFlag(AddonManager.PENDING_UNINSTALL, a1.pendingOperations));
|
||||
do_check_false(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
// complete the uinstall
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onUninstalled"
|
||||
]
|
||||
});
|
||||
a1.uninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID(ID);
|
||||
|
||||
do_check_eq(a1, null);
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
});
|
||||
|
||||
//Tests that an enabled restartless add-on can be uninstalled and then cancelled
|
||||
add_task(function* cancelUninstallOfRestartless() {
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
["onInstalling", false],
|
||||
"onInstalled"
|
||||
]
|
||||
}, [
|
||||
"onNewInstall",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded"
|
||||
]);
|
||||
yield promiseInstallAllFiles([do_get_addon("test_undouninstall1")]);
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID(ID);
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getInstallReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(getStartupReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
a1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonInstalled(ID);
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
do_check_eq(getShutdownReason(ID), ADDON_UNINSTALL);
|
||||
do_check_true(hasFlag(AddonManager.PENDING_UNINSTALL, a1.pendingOperations));
|
||||
do_check_false(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
});
|
||||
a1.cancelUninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getStartupReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
shutdownManager();
|
||||
|
||||
do_check_eq(getShutdownReason(ID), APP_SHUTDOWN);
|
||||
do_check_eq(getShutdownNewVersion(ID), undefined);
|
||||
|
||||
startupManager(false);
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getStartupReason(ID), APP_STARTUP);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
a1.uninstall();
|
||||
});
|
||||
|
||||
// Tests that reinstalling an enabled restartless add-on waiting to be
|
||||
// uninstalled aborts the uninstall and leaves the add-on enabled
|
||||
add_task(function* reinstallAddonAwaitingUninstall() {
|
||||
yield promiseInstallAllFiles([do_get_addon("test_undouninstall1")]);
|
||||
|
||||
let a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getInstallReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(getStartupReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
a1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonInstalled(ID);
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
do_check_eq(getShutdownReason(ID), ADDON_UNINSTALL);
|
||||
do_check_true(hasFlag(AddonManager.PENDING_UNINSTALL, a1.pendingOperations));
|
||||
do_check_false(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
["onInstalling", false],
|
||||
"onInstalled"
|
||||
]
|
||||
}, [
|
||||
"onNewInstall",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded"
|
||||
]);
|
||||
|
||||
yield promiseInstallAllFiles([do_get_addon("test_undouninstall1")]);
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
ensure_test_completed();
|
||||
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getUninstallReason(ID), ADDON_DOWNGRADE);
|
||||
do_check_eq(getInstallReason(ID), ADDON_DOWNGRADE);
|
||||
do_check_eq(getStartupReason(ID), ADDON_DOWNGRADE);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
shutdownManager();
|
||||
|
||||
do_check_eq(getShutdownReason(ID), APP_SHUTDOWN);
|
||||
|
||||
startupManager(false);
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getStartupReason(ID), APP_STARTUP);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
a1.uninstall();
|
||||
});
|
||||
|
||||
// Tests that a disabled restartless add-on can be uninstalled and goes away
|
||||
// when the uninstall is committed
|
||||
add_task(function* uninstallDisabledRestartless() {
|
||||
yield promiseInstallAllFiles([do_get_addon("test_undouninstall1")]);
|
||||
|
||||
let a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getInstallReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(getStartupReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
a1.userDisabled = true;
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
do_check_eq(getShutdownReason(ID), ADDON_DISABLE);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
a1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
do_check_true(hasFlag(AddonManager.PENDING_UNINSTALL, a1.pendingOperations));
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
|
||||
// commit the uninstall
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onUninstalled"
|
||||
]
|
||||
});
|
||||
a1.uninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_eq(a1, null);
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
BootstrapMonitor.checkAddonNotInstalled(ID);
|
||||
do_check_eq(getUninstallReason(ID), ADDON_UNINSTALL);
|
||||
});
|
||||
|
||||
//Tests that a disabled restartless add-on can be uninstalled and then cancelled
|
||||
add_task(function* cancelUninstallDisabledRestartless() {
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
["onInstalling", false],
|
||||
"onInstalled"
|
||||
]
|
||||
}, [
|
||||
"onNewInstall",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded"
|
||||
]);
|
||||
yield promiseInstallAllFiles([do_get_addon("test_undouninstall1")]);
|
||||
ensure_test_completed();
|
||||
|
||||
let a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getInstallReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(getStartupReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
["onDisabling", false],
|
||||
"onDisabled"
|
||||
]
|
||||
});
|
||||
a1.userDisabled = true;
|
||||
ensure_test_completed();
|
||||
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
do_check_eq(getShutdownReason(ID), ADDON_DISABLE);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
a1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
BootstrapMonitor.checkAddonInstalled(ID);
|
||||
do_check_true(hasFlag(AddonManager.PENDING_UNINSTALL, a1.pendingOperations));
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
});
|
||||
a1.cancelUninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
BootstrapMonitor.checkAddonInstalled(ID);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
BootstrapMonitor.checkAddonInstalled(ID);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
|
||||
a1.uninstall();
|
||||
});
|
||||
|
||||
//Tests that reinstalling a disabled restartless add-on waiting to be
|
||||
//uninstalled aborts the uninstall and leaves the add-on disabled
|
||||
add_task(function* reinstallDisabledAddonAwaitingUninstall() {
|
||||
yield promiseInstallAllFiles([do_get_addon("test_undouninstall1")]);
|
||||
|
||||
let a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getInstallReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(getStartupReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
a1.userDisabled = true;
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
do_check_eq(getShutdownReason(ID), ADDON_DISABLE);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
a1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonNotStarted(ID);
|
||||
do_check_true(hasFlag(AddonManager.PENDING_UNINSTALL, a1.pendingOperations));
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
["onInstalling", false],
|
||||
"onInstalled"
|
||||
]
|
||||
}, [
|
||||
"onNewInstall",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded"
|
||||
]);
|
||||
|
||||
yield promiseInstallAllFiles([do_get_addon("test_undouninstall1")]);
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
ensure_test_completed();
|
||||
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
BootstrapMonitor.checkAddonNotStarted(ID, "1.0");
|
||||
do_check_eq(getUninstallReason(ID), ADDON_DOWNGRADE);
|
||||
do_check_eq(getInstallReason(ID), ADDON_DOWNGRADE);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
|
||||
yield promiseRestartManager();
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonNotStarted(ID, "1.0");
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_false(a1.isActive);
|
||||
do_check_true(a1.userDisabled);
|
||||
|
||||
a1.uninstall();
|
||||
});
|
||||
|
||||
|
||||
// Test that uninstalling a temporary addon can be canceled
|
||||
add_task(function* cancelUninstallTemporary() {
|
||||
yield AddonManager.installTemporaryAddon(do_get_addon("test_undouninstall1"));
|
||||
|
||||
let a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(getInstallReason(ID), ADDON_INSTALL);
|
||||
do_check_eq(getStartupReason(ID), ADDON_ENABLE);
|
||||
do_check_eq(a1.pendingOperations, AddonManager.PENDING_NONE);
|
||||
do_check_true(a1.isActive);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
a1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
BootstrapMonitor.checkAddonNotStarted(ID, "1.0");
|
||||
do_check_true(hasFlag(AddonManager.PENDING_UNINSTALL, a1.pendingOperations));
|
||||
|
||||
prepare_test({
|
||||
"undouninstall1@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
});
|
||||
a1.cancelUninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID("undouninstall1@tests.mozilla.org");
|
||||
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonStarted(ID, "1.0");
|
||||
do_check_eq(a1.pendingOperations, 0);
|
||||
|
||||
yield promiseRestartManager();
|
||||
});
|
||||
|
||||
// Tests that cancelling the uninstall of an incompatible restartless addon
|
||||
// does not start the addon
|
||||
add_task(function* cancelUninstallIncompatibleRestartless() {
|
||||
yield promiseInstallAllFiles([do_get_addon("test_undoincompatible")]);
|
||||
|
||||
let a1 = yield promiseAddonByID(INCOMPAT_ID);
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonNotStarted(INCOMPAT_ID);
|
||||
do_check_false(a1.isActive);
|
||||
|
||||
prepare_test({
|
||||
"incompatible@tests.mozilla.org": [
|
||||
"onUninstalling"
|
||||
]
|
||||
});
|
||||
a1.uninstall(true);
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID(INCOMPAT_ID);
|
||||
do_check_neq(a1, null);
|
||||
do_check_true(hasFlag(AddonManager.PENDING_UNINSTALL, a1.pendingOperations));
|
||||
do_check_false(a1.isActive);
|
||||
|
||||
prepare_test({
|
||||
"incompatible@tests.mozilla.org": [
|
||||
"onOperationCancelled"
|
||||
]
|
||||
});
|
||||
a1.cancelUninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
a1 = yield promiseAddonByID(INCOMPAT_ID);
|
||||
do_check_neq(a1, null);
|
||||
BootstrapMonitor.checkAddonNotStarted(INCOMPAT_ID);
|
||||
do_check_eq(a1.pendingOperations, 0);
|
||||
do_check_false(a1.isActive);
|
||||
});
|
@ -201,6 +201,7 @@ function run_test_4() {
|
||||
]
|
||||
});
|
||||
a1.uninstall();
|
||||
ensure_test_completed();
|
||||
|
||||
check_test_4();
|
||||
});
|
||||
|
@ -262,6 +262,8 @@ fail-if = os == "android"
|
||||
# Bug 676992: test consistently fails on Android
|
||||
fail-if = os == "android"
|
||||
[test_types.js]
|
||||
[test_undothemeuninstall.js]
|
||||
[test_undouninstall.js]
|
||||
[test_uninstall.js]
|
||||
[test_update.js]
|
||||
# Bug 676992: test consistently hangs on Android
|
||||
|
@ -33,5 +33,4 @@ skip-if = appname != "firefox"
|
||||
[test_temporary.js]
|
||||
[test_proxy.js]
|
||||
|
||||
|
||||
[include:xpcshell-shared.ini]
|
||||
|
@ -27,6 +27,8 @@ body {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/** Categories **/
|
||||
|
||||
.category {
|
||||
cursor: pointer;
|
||||
/* Center category names */
|
||||
@ -38,6 +40,12 @@ body {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#categories hr {
|
||||
border-top-color: rgba(255,255,255,0.15);
|
||||
}
|
||||
|
||||
/** Warning container **/
|
||||
|
||||
/* XXX: a lot of this is duplicated from info-pages.css since that stylesheet
|
||||
is incompatible with this type of layout */
|
||||
.warningBackground:not([hidden]) {
|
||||
@ -84,6 +92,8 @@ body {
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
/** Content area **/
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
}
|
||||
@ -97,9 +107,10 @@ body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
hr {
|
||||
th, td, table {
|
||||
border-collapse: collapse;
|
||||
border: none;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.15);
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
th {
|
||||
@ -107,12 +118,6 @@ th {
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
th, td, table {
|
||||
border-collapse: collapse;
|
||||
border: none;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
td {
|
||||
padding-bottom: 0.25em;
|
||||
border-bottom: 1px solid var(--in-content-box-border-color);
|
||||
|
Loading…
Reference in New Issue
Block a user