Bug 595722 - Using this._enabled to make nsIUpdatePrompt not show some of the UI when the app.update.silent pref is set is confusing. r=dtownsend, a=approval2.0

This commit is contained in:
Robert Strong 2010-09-13 23:57:56 -07:00
parent b270b3d18b
commit 78559834a9
5 changed files with 266 additions and 37 deletions

View File

@ -482,24 +482,28 @@ interface nsIUpdateManager : nsISupports
interface nsIUpdatePrompt : nsISupports
{
/**
* Shows a user interface that checks for and then displays the available
* updates.
* Shows the application update checking user interface and checks if there
* is an update available.
*/
void checkForUpdates();
/**
* Show a message advising that an update is available for download and
* install.
* Shows the application update available user interface advising that an
* update is available for download and install. If the app.update.silent
* preference is true or the user interface is already displayed the call will
* be a no-op.
* @param update
* The update to be downloaded and installed
* The nsIUpdate object to be downloaded and installed
*/
void showUpdateAvailable(in nsIUpdate update);
/**
* Show a message advising that an update has now been downloaded and that
* a restart is necessary to complete the update.
* Shows the application update downloaded user interface advising that an
* update has now been downloaded and a restart is necessary to complete the
* update. If background is true (e.g. the download was not user initiated)
* and the app.update.silent preference is true the call will be a no-op.
* @param update
* The update that was downloaded
* The nsIUpdate object that was downloaded
* @param background
* Less obtrusive UI, starting with a non-modal notification alert
*/
@ -507,22 +511,29 @@ interface nsIUpdatePrompt : nsISupports
[optional] in boolean background);
/**
* Shows a message that an update was installed successfully.
* Shows the application update installed user interface advising that an
* update was installed successfully. If the app.update.silent preference is
* true, the app.update.showInstalledUI preference is false, or the user
* interface is already displayed the call will be a no-op.
*/
void showUpdateInstalled();
/**
* Shows an error message UI telling the user about some kind of update
* failure, e.g. failure to apply patch.
* Shows the application update error user interface advising that an error
* occurred while checking for or applying an update. If the app.update.silent
* preference is true the call will be a no-op.
* @param update
* The nsIUpdate object which we could not install
* An nsIUpdate object representing the update that could not be
* installed. The nsIUpdate object will not be the actual update when
* the error occurred during an update check and will instead be an
* nsIUpdate object with the error information for the update check.
*/
void showUpdateError(in nsIUpdate update);
/**
* Shows a list of all updates installed to date.
* @param parent
* A parent window to anchor this window to. Can be null.
* An nsIDOMWindow to set as the parent for this window. Can be null.
*/
void showUpdateHistory(in nsIDOMWindow parent);
};

View File

@ -2584,7 +2584,7 @@ Downloader.prototype = {
if (this._verifyDownload()) {
state = STATE_PENDING;
// We only need to explicitly show the prompt if this is a backround
// We only need to explicitly show the prompt if this is a background
// download, since otherwise some kind of UI is already visible and
// that UI will notify.
if (this.background)
@ -2751,7 +2751,8 @@ UpdatePrompt.prototype = {
* See nsIUpdateService.idl
*/
showUpdateAvailable: function UP_showUpdateAvailable(update) {
if (!this._enabled || this._getUpdateWindow())
if (getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false) ||
this._getUpdateWindow())
return;
var stringsPrefix = "updateAvailable_" + update.type + ".";
@ -2769,7 +2770,7 @@ UpdatePrompt.prototype = {
*/
showUpdateDownloaded: function UP_showUpdateDownloaded(update, background) {
if (background) {
if (!this._enabled)
if (getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false))
return;
var stringsPrefix = "updateDownloaded_" + update.type + ".";
@ -2790,8 +2791,9 @@ UpdatePrompt.prototype = {
* See nsIUpdateService.idl
*/
showUpdateInstalled: function UP_showUpdateInstalled() {
if (!this._enabled || this._getUpdateWindow() ||
!getPref("getBoolPref", PREF_APP_UPDATE_SHOW_INSTALLED_UI, false))
if (getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false) ||
!getPref("getBoolPref", PREF_APP_UPDATE_SHOW_INSTALLED_UI, false) ||
this._getUpdateWindow())
return;
var page = "installed";
@ -2814,17 +2816,9 @@ UpdatePrompt.prototype = {
* See nsIUpdateService.idl
*/
showUpdateError: function UP_showUpdateError(update) {
if (!this._enabled)
if (getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false))
return;
if (update.errorCode &&
(update.errorCode == CERT_ATTR_CHECK_FAILED_NO_UPDATE ||
update.errorCode == CERT_ATTR_CHECK_FAILED_HAS_UPDATE)) {
this._showUIWhenIdle(null, URI_UPDATE_PROMPT_DIALOG, null,
UPDATE_WINDOW_NAME, null, update);
return;
}
// In some cases, we want to just show a simple alert dialog:
if (update.state == STATE_FAILED && update.errorCode == WRITE_ERROR) {
var title = gUpdateBundle.GetStringFromName("updaterIOErrorTitle");
@ -2832,10 +2826,18 @@ UpdatePrompt.prototype = {
[Services.appinfo.name,
Services.appinfo.name], 2);
Services.ww.getNewPrompter(null).alert(title, text);
} else {
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, null, UPDATE_WINDOW_NAME,
"errors", update);
return;
}
if (update.errorCode == CERT_ATTR_CHECK_FAILED_NO_UPDATE ||
update.errorCode == CERT_ATTR_CHECK_FAILED_HAS_UPDATE) {
this._showUIWhenIdle(null, URI_UPDATE_PROMPT_DIALOG, null,
UPDATE_WINDOW_NAME, null, update);
return;
}
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, null, UPDATE_WINDOW_NAME,
"errors", update);
},
/**
@ -2846,13 +2848,6 @@ UpdatePrompt.prototype = {
"Update:History", null, null);
},
/**
* Whether or not we are enabled (i.e. not in Silent mode)
*/
get _enabled() {
return !getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false);
},
/**
* Returns the update window if present.
*/

View File

@ -56,6 +56,7 @@ const PREF_APP_UPDATE_LOG = "app.update.log";
const PREF_APP_UPDATE_NEVER_BRANCH = "app.update.never.";
const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime";
const PREF_APP_UPDATE_SHOW_INSTALLED_UI = "app.update.showInstalledUI";
const PREF_APP_UPDATE_SILENT = "app.update.silent";
const PREF_APP_UPDATE_URL = "app.update.url";
const PREF_APP_UPDATE_URL_DETAILS = "app.update.url.details";
const PREF_APP_UPDATE_URL_OVERRIDE = "app.update.url.override";
@ -111,6 +112,7 @@ const PERMS_FILE = 0644;
const PERMS_DIRECTORY = 0755;
AUS_Cu.import("resource://gre/modules/Services.jsm");
AUS_Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.properties";
const gUpdateBundle = Services.strings.createBundle(URI_UPDATES_PROPERTIES);

View File

@ -0,0 +1,105 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Test that nsIUpdatePrompt doesn't display UI for showUpdateInstalled,
* showUpdateAvailable, and showUpdateError when the app.update.silent
* preference is true.
*/
var gCheckFunc;
function run_test() {
dump("Testing: nsIUpdatePrompt notifications should not be seen when the " +
PREF_APP_UPDATE_SILENT + " preference is true\n");
removeUpdateDirsAndFiles();
setUpdateChannel();
Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
"Fake Window Watcher",
"@mozilla.org/embedcomp/window-watcher;1",
WindowWatcherFactory);
standardInit();
dump("showUpdateInstalled should not call openWindow\n");
Services.prefs.setBoolPref(PREF_APP_UPDATE_SHOW_INSTALLED_UI, true);
gCheckFunc = check_showUpdateInstalled;
gUP.showUpdateInstalled();
// Report a successful check after the call to showUpdateInstalled since it
// didn't throw and otherwise it would report no tests run.
do_check_true(true);
dump("showUpdateAvailable should not call openWindow\n");
writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
let patches = getLocalPatchString(null, null, null, null, null, null,
STATE_FAILED);
let updates = getLocalUpdateString(patches);
writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
writeStatusFile(STATE_FAILED);
reloadUpdateManagerData();
gCheckFunc = check_showUpdateAvailable;
let update = gUpdateManager.activeUpdate;
gUP.showUpdateAvailable(update);
// Report a successful check after the call to showUpdateAvailable since it
// didn't throw and otherwise it would report no tests run.
do_check_true(true);
dump("showUpdateError should not call getNewPrompter\n");
gCheckFunc = check_showUpdateError;
update.errorCode = WRITE_ERROR;
gUP.showUpdateError(update);
// Report a successful check after the call to showUpdateError since it
// didn't throw and otherwise it would report no tests run.
do_check_true(true);
let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
WindowWatcherFactory);
cleanUp();
}
function check_showUpdateInstalled() {
do_throw("showUpdateInstalled should not have called openWindow!");
}
function check_showUpdateAvailable() {
do_throw("showUpdateAvailable should not have called openWindow!");
}
function check_showUpdateError() {
do_throw("showUpdateError should not have seen getNewPrompter!");
}
var WindowWatcher = {
openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) {
gCheckFunc();
},
getNewPrompter: function(aParent) {
gCheckFunc();
},
QueryInterface: function(aIID) {
if (aIID.equals(AUS_Ci.nsIWindowWatcher) ||
aIID.equals(AUS_Ci.nsISupports))
return this;
throw AUS_Cr.NS_ERROR_NO_INTERFACE;
}
}
var WindowWatcherFactory = {
createInstance: function createInstance(aOuter, aIID) {
if (aOuter != null)
throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
return WindowWatcher.QueryInterface(aIID);
}
};

View File

@ -0,0 +1,116 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Test that nsIUpdatePrompt doesn't display UI for showUpdateInstalled and
* showUpdateAvailable when there is already an application update window open.
*/
var gCheckFunc;
function run_test() {
dump("Testing: nsIUpdatePrompt notifications should not be seen when there " +
"is already an application update window open\n");
removeUpdateDirsAndFiles();
setUpdateChannel();
Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false);
let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
"Fake Window Watcher",
"@mozilla.org/embedcomp/window-watcher;1",
WindowWatcherFactory);
registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af56}"),
"Fake Window Mediator",
"@mozilla.org/appshell/window-mediator;1",
WindowMediatorFactory);
standardInit();
dump("showUpdateInstalled should not call openWindow\n");
Services.prefs.setBoolPref(PREF_APP_UPDATE_SHOW_INSTALLED_UI, true);
gCheckFunc = check_showUpdateInstalled;
gUP.showUpdateInstalled();
// Report a successful check after the call to showUpdateInstalled since it
// didn't throw and otherwise it would report no tests run.
do_check_true(true);
dump("showUpdateAvailable should not call openWindow\n");
writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
let patches = getLocalPatchString(null, null, null, null, null, null,
STATE_FAILED);
let updates = getLocalUpdateString(patches);
writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
writeStatusFile(STATE_FAILED);
reloadUpdateManagerData();
gCheckFunc = check_showUpdateAvailable;
let update = gUpdateManager.activeUpdate;
gUP.showUpdateAvailable(update);
// Report a successful check after the call to showUpdateAvailable since it
// didn't throw and otherwise it would report no tests run.
do_check_true(true);
let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
WindowWatcherFactory);
registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af56}"),
WindowMediatorFactory);
cleanUp();
}
function check_showUpdateInstalled() {
do_throw("showUpdateInstalled should not have called openWindow!");
}
function check_showUpdateAvailable() {
do_throw("showUpdateAvailable should not have called openWindow!");
}
var WindowWatcher = {
openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) {
gCheckFunc();
},
QueryInterface: function(aIID) {
if (aIID.equals(AUS_Ci.nsIWindowWatcher) ||
aIID.equals(AUS_Ci.nsISupports))
return this;
throw AUS_Cr.NS_ERROR_NO_INTERFACE;
}
}
var WindowWatcherFactory = {
createInstance: function createInstance(aOuter, aIID) {
if (aOuter != null)
throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
return WindowWatcher.QueryInterface(aIID);
}
};
var WindowMediator = {
getMostRecentWindow: function(aWindowType) {
return { getInterface: XPCOMUtils.generateQI([AUS_Ci.nsIDOMWindowInternal]) };
},
QueryInterface: function(aIID) {
if (aIID.equals(AUS_Ci.nsIWindowMediator) ||
aIID.equals(AUS_Ci.nsISupports))
return this;
throw AUS_Cr.NS_ERROR_NO_INTERFACE;
}
}
var WindowMediatorFactory = {
createInstance: function createInstance(aOuter, aIID) {
if (aOuter != null)
throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
return WindowMediator.QueryInterface(aIID);
}
};