Bug 408115: Add post-restart notification of new add-on installs. r=gavin.sharp, r=robstrong, a=beltzner
This commit is contained in:
@@ -45,6 +45,8 @@ const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/distribution.js");
|
||||
|
||||
const PREF_EM_NEW_ADDONS_LIST = "extensions.newAddons";
|
||||
|
||||
// Factory object
|
||||
const BrowserGlueServiceFactory = {
|
||||
_instance: null,
|
||||
@@ -89,6 +91,9 @@ BrowserGlue.prototype = {
|
||||
case "final-ui-startup":
|
||||
this._onProfileStartup();
|
||||
break;
|
||||
case "sessionstore-windows-restored":
|
||||
this._onBrowserStartup();
|
||||
break;
|
||||
case "browser:purge-session-history":
|
||||
// reset the console service's error buffer
|
||||
const cs = Cc["@mozilla.org/consoleservice;1"].
|
||||
@@ -122,6 +127,7 @@ BrowserGlue.prototype = {
|
||||
osvr.addObserver(this, "xpcom-shutdown", false);
|
||||
osvr.addObserver(this, "prefservice:after-app-defaults", false);
|
||||
osvr.addObserver(this, "final-ui-startup", false);
|
||||
osvr.addObserver(this, "sessionstore-windows-restored", false);
|
||||
osvr.addObserver(this, "browser:purge-session-history", false);
|
||||
osvr.addObserver(this, "quit-application-requested", false);
|
||||
osvr.addObserver(this, "quit-application-granted", false);
|
||||
@@ -138,6 +144,7 @@ BrowserGlue.prototype = {
|
||||
osvr.removeObserver(this, "xpcom-shutdown");
|
||||
osvr.removeObserver(this, "prefservice:after-app-defaults");
|
||||
osvr.removeObserver(this, "final-ui-startup");
|
||||
osvr.removeObserver(this, "sessionstore-windows-restored");
|
||||
osvr.removeObserver(this, "browser:purge-session-history");
|
||||
osvr.removeObserver(this, "quit-application-requested");
|
||||
osvr.removeObserver(this, "quit-application-granted");
|
||||
@@ -202,6 +209,32 @@ BrowserGlue.prototype = {
|
||||
this.Sanitizer.onShutdown();
|
||||
},
|
||||
|
||||
// Browser startup complete. All initial windows have opened.
|
||||
_onBrowserStartup: function()
|
||||
{
|
||||
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
// If new add-ons were installed during startup open the add-ons manager.
|
||||
if (prefBranch.prefHasUserValue(PREF_EM_NEW_ADDONS_LIST)) {
|
||||
var args = Cc["@mozilla.org/supports-array;1"].
|
||||
createInstance(Ci.nsISupportsArray);
|
||||
var str = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
str.data = "";
|
||||
args.AppendElement(str);
|
||||
var str = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
str.data = prefBranch.getCharPref(PREF_EM_NEW_ADDONS_LIST);
|
||||
args.AppendElement(str);
|
||||
const EMURL = "chrome://mozapps/content/extensions/extensions.xul";
|
||||
const EMFEATURES = "chrome,menubar,extra-chrome,toolbar,dialog=no,resizable";
|
||||
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
getService(Ci.nsIWindowWatcher);
|
||||
ww.openWindow(null, EMURL, "_blank", EMFEATURES, args);
|
||||
prefBranch.clearUserPref(PREF_EM_NEW_ADDONS_LIST);
|
||||
}
|
||||
},
|
||||
|
||||
_onQuitRequest: function(aCancelQuit, aQuitType)
|
||||
{
|
||||
// If user has already dismissed quit request, then do nothing
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
# LOCALIZATION NOTE: Semi-colon list of plural forms.
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
addonsPlural=add-on;add-ons
|
||||
|
||||
aboutWindowTitle=About %S
|
||||
aboutWindowCloseButton=Close
|
||||
aboutWindowVersionString=version %S
|
||||
@@ -94,7 +98,7 @@ updateAvailableMsg=Version %S is available.
|
||||
|
||||
xpinstallDisabledMsgLocked=Software installation has been disabled by your system administrator.
|
||||
xpinstallDisabledMsg=Software installation is currently disabled. Click Enable and try again.
|
||||
newAddonsInstalledMsg=%S new add-ons have been installed.
|
||||
newAddonsNotificationMsg=%S new %S installed.
|
||||
safeModeMsg=All add-ons have been disabled by safe mode.
|
||||
disabledCompatMsg=Add-on compatibility checking is disabled. You may have incompatible add-ons.
|
||||
disabledUpdateSecurityMsg=Add-on update security checking is disabled. You may be compromised by updates.
|
||||
|
||||
@@ -74,6 +74,7 @@ var gRetrievedResults = false;
|
||||
var gRecommendedAddons = null;
|
||||
var gRDF = null;
|
||||
var gPendingInstalls = {};
|
||||
var gNewAddons = [];
|
||||
|
||||
const PREF_EM_CHECK_COMPATIBILITY = "extensions.checkCompatibility";
|
||||
const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity";
|
||||
@@ -106,6 +107,7 @@ const OP_NEEDS_UNINSTALL = "needs-uninstall";
|
||||
const OP_NEEDS_ENABLE = "needs-enable";
|
||||
const OP_NEEDS_DISABLE = "needs-disable";
|
||||
|
||||
Components.utils.import("resource://gre/modules/PluralForm.jsm");
|
||||
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -483,15 +485,8 @@ function showView(aView) {
|
||||
else
|
||||
document.getElementById("continueDialogButton").removeAttribute("default");
|
||||
|
||||
if (isThemes) {
|
||||
if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING)) {
|
||||
var item = getItemForInternalName(gCurrentTheme);
|
||||
if (item)
|
||||
setRestartMessage(item);
|
||||
}
|
||||
|
||||
if (isThemes)
|
||||
onAddonSelect();
|
||||
}
|
||||
updateGlobalCommands();
|
||||
}
|
||||
|
||||
@@ -1097,6 +1092,8 @@ function Startup()
|
||||
null, null, true, null);
|
||||
}
|
||||
|
||||
gExtensionsView.builder.addListener(TemplateBuilderListener);
|
||||
|
||||
if ("arguments" in window) {
|
||||
try {
|
||||
var params = window.arguments[0].QueryInterface(Components.interfaces.nsIDialogParamBlock);
|
||||
@@ -1119,6 +1116,36 @@ function Startup()
|
||||
null, null, true, null);
|
||||
document.title = getExtensionString("newUpdateWindowTitle", [getBrandShortName()]);
|
||||
}
|
||||
else if (window.arguments.length == 2) {
|
||||
gNewAddons = window.arguments[1].split(",");
|
||||
var addonsTerm = PluralForm.get(gNewAddons.length, getExtensionString("addonsPlural"));
|
||||
showMessage("chrome://mozapps/skin/extensions/question.png",
|
||||
getExtensionString("newAddonsNotificationMsg", [gNewAddons.length, addonsTerm]),
|
||||
null, null, true, null);
|
||||
var extensionCount = 0;
|
||||
var themeCount = 0;
|
||||
var localeCount = 0;
|
||||
for (var i = 0; i < gNewAddons.length; i++) {
|
||||
var item = gExtensionManager.getItemForID(gNewAddons[i]);
|
||||
switch (item.type) {
|
||||
case Ci.nsIUpdateItem.TYPE_EXTENSION:
|
||||
extensionCount++;
|
||||
break;
|
||||
case Ci.nsIUpdateItem.TYPE_THEME:
|
||||
themeCount++;
|
||||
break;
|
||||
case Ci.nsIUpdateItem.TYPE_LOCALE:
|
||||
localeCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (themeCount > extensionCount && themeCount > localeCount)
|
||||
showView("themes");
|
||||
else if (localeCount > extensionCount && localeCount > themeCount)
|
||||
showView("locales");
|
||||
else
|
||||
showView("extensions");
|
||||
}
|
||||
else
|
||||
showView(window.arguments[0]);
|
||||
}
|
||||
@@ -1141,6 +1168,8 @@ function Startup()
|
||||
|
||||
function Shutdown()
|
||||
{
|
||||
gExtensionsView.builder.removeListener(TemplateBuilderListener);
|
||||
|
||||
gPref.removeObserver(PREF_DSS_SKIN_TO_SELECT, gPrefObserver);
|
||||
gPref.removeObserver(PREF_GENERAL_SKINS_SELECTEDSKIN, gPrefObserver);
|
||||
if (gAddonRepository && gAddonRepository.isSearching)
|
||||
@@ -1163,6 +1192,38 @@ function Shutdown()
|
||||
window.removeEventListener("select", noUpdatesDismiss, true);
|
||||
}
|
||||
|
||||
var TemplateBuilderListener = {
|
||||
willRebuild: function(aBuilder) {
|
||||
},
|
||||
|
||||
didRebuild: function(aBuilder) {
|
||||
// Display has been rebuilt, update necessary attributes
|
||||
if (gView == "extensions" || gView == "themes" || gView == "locales") {
|
||||
for (var i = 0; i < gNewAddons.length; i++) {
|
||||
var item = document.getElementById(PREFIX_ITEM_URI + gNewAddons[i]);
|
||||
if (item)
|
||||
item.setAttribute("newAddon", "true");
|
||||
}
|
||||
}
|
||||
|
||||
if (gView == "themes") {
|
||||
if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING)) {
|
||||
var item = getItemForInternalName(gCurrentTheme);
|
||||
if (item)
|
||||
setRestartMessage(item);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: function (aIID)
|
||||
{
|
||||
if (!aIID.equals(Components.interfaces.nsIXULBuilderListener) &&
|
||||
!aIID.equals(Components.interfaces.nsISupports))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// XPInstall
|
||||
|
||||
@@ -60,6 +60,7 @@ const PREF_EM_LAST_APP_VERSION = "extensions.lastAppVersion";
|
||||
const PREF_EM_ENABLED_ITEMS = "extensions.enabledItems";
|
||||
const PREF_UPDATE_COUNT = "extensions.update.count";
|
||||
const PREF_UPDATE_DEFAULT_URL = "extensions.update.url";
|
||||
const PREF_EM_NEW_ADDONS_LIST = "extensions.newAddons";
|
||||
const PREF_EM_IGNOREMTIMECHANGES = "extensions.ignoreMTimeChanges";
|
||||
const PREF_EM_DISABLEDOBSOLETE = "extensions.disabledObsolete";
|
||||
const PREF_EM_EXTENSION_FORMAT = "extensions.%UUID%.";
|
||||
@@ -173,6 +174,7 @@ var gLoggingEnabled = null;
|
||||
var gCheckCompatibility = true;
|
||||
var gCheckUpdateSecurity = true;
|
||||
var gLocale = "en-US";
|
||||
var gFirstRun = false;
|
||||
|
||||
/**
|
||||
* Valid GUIDs fit this pattern.
|
||||
@@ -1716,7 +1718,7 @@ Installer.prototype = {
|
||||
// contents.rdf file at the location specified, malformed contents.rdf,
|
||||
// etc. Set the pending op to be OP_NEEDS_UNINSTALL so that the
|
||||
// extension is uninstalled properly during the subsequent uninstall
|
||||
// pass in |ExtensionManager::_finalizeOperations|
|
||||
// pass in |ExtensionManager::_finishOperations|
|
||||
ERROR("upgradeThemeChrome: failed for theme " + this._id + " - why " +
|
||||
"not convert to the new chrome.manifest format while you're at it? " +
|
||||
"Failure exception: " + e);
|
||||
@@ -1806,7 +1808,7 @@ Installer.prototype = {
|
||||
// contents.rdf file at the location specified, malformed contents.rdf,
|
||||
// etc. Set the pending op to be OP_NEEDS_UNINSTALL so that the
|
||||
// extension is uninstalled properly during the subsequent uninstall
|
||||
// pass in |ExtensionManager::_finalizeOperations|
|
||||
// pass in |ExtensionManager::_finishOperations|
|
||||
ERROR("upgradeExtensionChrome: failed for extension " + this._id + " - why " +
|
||||
"not convert to the new chrome.manifest format while you're at it? " +
|
||||
"Failure exception: " + e);
|
||||
@@ -2281,6 +2283,7 @@ var StartupCache = {
|
||||
// There is no change manifest for some reason, either we're in an initial
|
||||
// state or something went wrong with one of the other files and the
|
||||
// change manifest was removed. Return an empty dataset and rebuild.
|
||||
gFirstRun = true;
|
||||
return;
|
||||
}
|
||||
var fis = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
@@ -3365,6 +3368,11 @@ ExtensionManager.prototype = {
|
||||
var updatedTargetAppInfos = [];
|
||||
|
||||
var needsRestart = false;
|
||||
var upgrades = [];
|
||||
var newAddons = [];
|
||||
var addons = getPref("getCharPref", PREF_EM_NEW_ADDONS_LIST, "");
|
||||
if (addons != "")
|
||||
newAddons = addons.split(",");
|
||||
do {
|
||||
// Enable and disable during startup so items that are changed in the
|
||||
// ui can be reset to a no-op.
|
||||
@@ -3402,6 +3410,7 @@ ExtensionManager.prototype = {
|
||||
if (newTargetAppInfo)
|
||||
updatedTargetAppInfos.push(newTargetAppInfo);
|
||||
this._finalizeUpgrade(id, newLocation);
|
||||
upgrades.push(id);
|
||||
}
|
||||
PendingOperations.clearItems(OP_NEEDS_UPGRADE);
|
||||
|
||||
@@ -3415,6 +3424,8 @@ ExtensionManager.prototype = {
|
||||
if (newTargetAppInfo)
|
||||
updatedTargetAppInfos.push(newTargetAppInfo);
|
||||
this._finalizeInstall(id, null);
|
||||
if (upgrades.indexOf(id) < 0 && newAddons.indexOf(id) < 0)
|
||||
newAddons.push(id);
|
||||
}
|
||||
PendingOperations.clearItems(OP_NEEDS_INSTALL);
|
||||
|
||||
@@ -3427,6 +3438,9 @@ ExtensionManager.prototype = {
|
||||
this._finalizeUninstall(id);
|
||||
this._checkForUncoveredItem(id);
|
||||
needsRestart = true;
|
||||
var pos = newAddons.indexOf(id);
|
||||
if (pos >= 0)
|
||||
newAddons.splice(pos, 1);
|
||||
}
|
||||
PendingOperations.clearItems(OP_NEEDS_UNINSTALL);
|
||||
|
||||
@@ -3479,6 +3493,10 @@ ExtensionManager.prototype = {
|
||||
// not to do any extra startup checking next time round.
|
||||
this._updateManifests(needsRestart);
|
||||
|
||||
// Remember the list of add-ons that were installed this time around
|
||||
// unless this was a new profile.
|
||||
if (!gFirstRun && newAddons.length > 0)
|
||||
gPref.setCharPref(PREF_EM_NEW_ADDONS_LIST, newAddons.join(","));
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("ExtensionManager:_finishOperations - failure, catching exception - lineno: " +
|
||||
|
||||
@@ -52,6 +52,10 @@ richlistitem[isDisabled="true"] {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
richlistitem[newAddon="true"] {
|
||||
background-color: InfoBackground;
|
||||
}
|
||||
|
||||
richlistitem[selected="true"] {
|
||||
background-color: -moz-cellhighlight;
|
||||
color: -moz-cellhighlighttext;
|
||||
|
||||
@@ -57,6 +57,10 @@ richlistitem[isDisabled="true"] {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
richlistitem[newAddon="true"] {
|
||||
background-color: #fdf2ab;
|
||||
}
|
||||
|
||||
richlistitem[selected="true"] {
|
||||
background-color: Highlight;
|
||||
color: HighlightText;
|
||||
|
||||
@@ -51,6 +51,10 @@ richlistitem[isDisabled="true"] {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
richlistitem[newAddon="true"] {
|
||||
background-color: InfoBackground;
|
||||
}
|
||||
|
||||
richlistitem[selected="true"] {
|
||||
background-color: -moz-cellhighlight;
|
||||
color: -moz-cellhighlighttext;
|
||||
|
||||
Reference in New Issue
Block a user