1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
/* 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/. */
module.metadata = {
"stability": "experimental"
};
const { Cc, Ci, Cu } = require("chrome");
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm");
const { defer } = require("../core/promise");
const { setTimeout } = require("../timers");
/**
* `install` method error codes:
*
* https://developer.mozilla.org/en/Addons/Add-on_Manager/AddonManager#AddonInstall_errors
*/
exports.ERROR_NETWORK_FAILURE = AddonManager.ERROR_NETWORK_FAILURE;
exports.ERROR_INCORRECT_HASH = AddonManager.ERROR_INCORRECT_HASH;
exports.ERROR_CORRUPT_FILE = AddonManager.ERROR_CORRUPT_FILE;
exports.ERROR_FILE_ACCESS = AddonManager.ERROR_FILE_ACCESS;
/**
* Immediatly install an addon.
*
* @param {String} xpiPath
* file path to an xpi file to install
* @return {Promise}
* A promise resolved when the addon is finally installed.
* Resolved with addon id as value or rejected with an error code.
*/
exports.install = function install(xpiPath) {
let { promise, resolve, reject } = defer();
// Create nsIFile for the xpi file
let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile);
try {
file.initWithPath(xpiPath);
}
catch(e) {
reject(exports.ERROR_FILE_ACCESS);
return promise;
}
// Listen for installation end
let listener = {
onInstallEnded: function(aInstall, aAddon) {
aInstall.removeListener(listener);
// Bug 749745: on FF14+, onInstallEnded is called just before `startup()`
// is called, but we expect to resolve the promise only after it.
// As startup is called synchronously just after onInstallEnded,
// a simple setTimeout(0) is enough
setTimeout(resolve, 0, aAddon.id);
},
onInstallFailed: function (aInstall) {
aInstall.removeListener(listener);
reject(aInstall.error);
},
onDownloadFailed: function(aInstall) {
this.onInstallFailed(aInstall);
}
};
// Order AddonManager to install the addon
AddonManager.getInstallForFile(file, function(install) {
if (install.error == 0) {
install.addListener(listener);
install.install();
} else {
reject(install.error);
}
});
return promise;
};
exports.uninstall = function uninstall(addonId) {
let { promise, resolve, reject } = defer();
// Listen for uninstallation end
let listener = {
onUninstalled: function onUninstalled(aAddon) {
if (aAddon.id != addonId)
return;
AddonManager.removeAddonListener(listener);
resolve();
}
};
AddonManager.addAddonListener(listener);
// Order Addonmanager to uninstall the addon
getAddon(addonId).then(addon => addon.uninstall(), reject);
return promise;
};
exports.disable = function disable(addonId) {
return getAddon(addonId).then(addon => {
addon.userDisabled = true;
return addonId;
});
};
exports.enable = function enabled(addonId) {
return getAddon(addonId).then(addon => {
addon.userDisabled = false;
return addonId;
});
};
exports.isActive = function isActive(addonId) {
return getAddon(addonId).then(addon => addon.isActive && !addon.appDisabled);
};
const getAddon = function getAddon (id) {
let { promise, resolve, reject } = defer();
AddonManager.getAddonByID(id, addon => addon ? resolve(addon) : reject());
return promise;
}
exports.getAddon = getAddon;
|