gecko-dev/toolkit/mozapps/extensions/content/newaddon.js
Dave Townsend 5537b5c159 Bug 1237820: Track whether a user has been offered a sideloaded add-on or not. r=rhelmer
Previously we just checked every newly sideloaded add-on to decide whether to
offer it to the user for opt-in. This adds a new "seen" property (naming could
be better if you have other suggestions) which tracks whether we've ever shown
the opt-in UI for the add-on. It defaults to true for all add-ons and is only
set to false for sideloaded add-ons that default to being disabled on install.
The seen flag can be set to true through the API but cannot be reset to false
as that would allow add-ons to forcibly re-present themselves to the user when
disabled.

The opt-in UI sets the seen flag to true only when it has focus which fixes a
long-standing bug where if you accept the first add-on you see and restart the
other tabs might not show up.

The one slight downside of this approach is that it now requires loading the
full add-ons database on every startup in order to check the seen flag for all
installed add-ons. There are hacky ways we might get around this but they all
involve overloading prefs with even more object data. The good thing is that
we do the load and check asynchronously after most of startup is complete and
the UI is fully loaded so there shouldn't be any percieved impact to startup
time. I've run multiple talos runs to verify that none of the numbers appear to
regress.

--HG--
extra : commitid : AG6pELCYJDa
extra : rebase_source : b824c1626d0c5a77416fa4349ed3dd4d0e96418b
2016-01-26 14:31:33 -08:00

137 lines
4.3 KiB
JavaScript

/* 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/. */
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");
var gAddon = null;
// If the user enables the add-on through some other UI close this window
var EnableListener = {
onEnabling: function(aAddon) {
if (aAddon.id == gAddon.id)
window.close();
}
}
AddonManager.addAddonListener(EnableListener);
function initialize() {
// About URIs don't implement nsIURL so we have to find the query string
// manually
let spec = document.location.href;
let pos = spec.indexOf("?");
let query = "";
if (pos >= 0)
query = spec.substring(pos + 1);
// Just assume the query is "id=<id>"
let id = query.substring(3);
if (!id) {
window.location = "about:blank";
return;
}
let bundle = Services.strings.createBundle("chrome://mozapps/locale/extensions/newaddon.properties");
AddonManager.getAddonByID(id, function(aAddon) {
// If the add-on doesn't exist or it is already enabled or it has already
// been seen or it cannot be enabled then this UI is useless, just close it.
// This shouldn't normally happen unless session restore restores the tab.
if (!aAddon || !aAddon.userDisabled || aAddon.seen ||
!(aAddon.permissions & AddonManager.PERM_CAN_ENABLE)) {
window.close();
return;
}
gAddon = aAddon;
document.getElementById("addon-info").setAttribute("type", aAddon.type);
let icon = document.getElementById("icon");
if (aAddon.icon64URL)
icon.src = aAddon.icon64URL;
else if (aAddon.iconURL)
icon.src = aAddon.iconURL;
let name = bundle.formatStringFromName("name", [aAddon.name, aAddon.version],
2);
document.getElementById("name").value = name;
if (aAddon.creator) {
let creator = bundle.formatStringFromName("author", [aAddon.creator], 1);
document.getElementById("author").value = creator;
} else {
document.getElementById("author").hidden = true;
}
let uri = "getResourceURI" in aAddon ? aAddon.getResourceURI() : null;
let locationLabel = document.getElementById("location");
if (uri instanceof Ci.nsIFileURL) {
let location = bundle.formatStringFromName("location", [uri.file.path], 1);
locationLabel.value = location;
locationLabel.setAttribute("tooltiptext", location);
} else {
document.getElementById("location").hidden = true;
}
// Only mark the add-on as seen if the page actually gets focus
if (document.hasFocus()) {
aAddon.markAsSeen();
}
else {
document.addEventListener("focus", () => aAddon.markAsSeen(), false);
}
var event = document.createEvent("Events");
event.initEvent("AddonDisplayed", true, true);
document.dispatchEvent(event);
});
}
function unload() {
AddonManager.removeAddonListener(EnableListener);
}
function continueClicked() {
AddonManager.removeAddonListener(EnableListener);
if (document.getElementById("allow").checked) {
gAddon.userDisabled = false;
if (gAddon.pendingOperations & AddonManager.PENDING_ENABLE) {
document.getElementById("allow").disabled = true;
document.getElementById("buttonDeck").selectedPanel = document.getElementById("restartPanel");
return;
}
}
window.close();
}
function restartClicked() {
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].
createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
"restart");
if (cancelQuit.data)
return; // somebody canceled our quit request
window.close();
let appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
getService(Components.interfaces.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
}
function cancelClicked() {
gAddon.userDisabled = true;
AddonManager.addAddonListener(EnableListener);
document.getElementById("allow").disabled = false;
document.getElementById("buttonDeck").selectedPanel = document.getElementById("continuePanel");
}