unify preference handling, fix update history not to show redundant entries

This commit is contained in:
ben@bengoodger.com
2005-06-28 18:56:40 +00:00
parent 313173309c
commit 056f6ca3c1
9 changed files with 204 additions and 78 deletions

View File

@@ -71,14 +71,24 @@ pref("extensions.ignoreMTimeChanges", false);
pref("extensions.logging.enabled", false);
// App-specific update preferences
pref("app.update.enabled", false); // Whether or not app updates are enabled
// Whether or not automated background app updates are enabled.
pref("app.update.autoInstallEnabled", true);
// If automatic download is enabled, whether or not the Update system should
// automatically install the downloaded updates or just download them and prompt
// the user to install.
pref("app.update.autoInstallMode", 0);
// Whether or not app updates are enabled
pref("app.update.enabled", false);
// Defines how the Application Update Service notifies the user about updates:
//
// AUM Set to: Minor Releases: Major Releases:
// 0 download no prompt download no prompt
// 1 download no prompt download no prompt if no incompatibilities
// 2 download no prompt prompt
// 3 prompt prompt
//
// See chart in nsUpdateService.js.in for more details
//
pref("app.update.mode", 1);
// If set to true, the Update Service will present no UI for any event.
pref("app.update.silent", false);
// XXX these prefs and others like them are distribution specific and should move
// into chrome://browser

View File

@@ -459,11 +459,18 @@ function buildHelpMenu()
var um =
Components.classes["@mozilla.org/updates/update-manager;1"].
getService(Components.interfaces.nsIUpdateManager);
var activeUpdate = um.activeUpdate;
// Disable the UI if the update enabled pref has been locked by the
// administrator or if we cannot update for some other reason
var checkForUpdates = document.getElementById("checkForUpdates");
var canUpdate = updates.canUpdate;
checkForUpdates.setAttribute("disabled", !canUpdate);
if (!canUpdate)
return;
var strings = document.getElementById("bundle_browser");
var label = strings.getString("updates_checkForUpdates");
var activeUpdate = um.activeUpdate;
if (activeUpdate) {
if (updates.isDownloading) {
if (activeUpdate.name) {
@@ -483,15 +490,10 @@ function buildHelpMenu()
}
}
var checkForUpdates = document.getElementById("checkForUpdates");
checkForUpdates.label = label;
if (um.activeUpdate && updates.isDownloading)
checkForUpdates.setAttribute("loading", "true");
else
checkForUpdates.removeAttribute("loading");
// Disable the UI if the update enabled pref has been locked by the
// administrator.
checkForUpdates.disabled = gPrefService.prefIsLocked("app.update.enabled");
}

View File

@@ -95,6 +95,13 @@ var gAdvancedPane = {
{
var preference = document.getElementById("app.update.enabled");
document.getElementById("enableAutoInstall").disabled = !preference.value;
var aus =
Components.classes["@mozilla.org/updates/update-service;1"].
getService(Components.interfaces.nsIApplicationUpdateService);
var checkNowButton = document.getElementById("checkNowButton");
checkNowButton.disabled = !aus.canUpdate;
this.updateAutoInstallUI();
return undefined;
},
@@ -129,8 +136,9 @@ var gAdvancedPane = {
var features = "chrome,centerscreen,dialog,titlebar";
const URI_EXTENSION_UPDATE_DIALOG =
"chrome://mozapps/content/extensions/update.xul";
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
var ww =
Components.classes["@mozilla.org/embedcomp/window-watcher;1"].
getService(Components.interfaces.nsIWindowWatcher);
ww.openWindow(window, URI_EXTENSION_UPDATE_DIALOG, "", features, ary);
},

View File

@@ -59,7 +59,7 @@
<preference id="general.smoothScroll" name="general.smoothScroll" type="bool"/>
<preference id="app.update.enabled" name="app.update.enabled" type="bool"/>
<preference id="app.update.autoInstallEnabled" name="app.update.autoInstallEnabled" type="bool"/>
<preference id="app.update.autoInstallMode" name="app.update.autoInstallMode" type="int"/>
<preference id="app.update.mode" name="app.update.mode" type="int"/>
<preference id="extensions.update.autoUpdateEnabled"
name="extensions.update.autoUpdateEnabled"
type="bool"/>
@@ -142,7 +142,7 @@
accesskey="&enableAutoInstall.accesskey;"
preference="app.update.autoInstallEnabled"
onpreferenceread="return gAdvancedPane.updateAutoInstallUI();"/>
<radiogroup id="autoInstallMode" preference="app.update.autoInstallMode">
<radiogroup id="autoInstallMode" preference="app.update.mode">
<grid class="indent">
<columns>
<column/>
@@ -161,7 +161,8 @@
</radiogroup>
<separator class="thin"/>
<hbox>
<button label="&checkNow.label;" accesskey="&appCheckNow.accesskey;"
<button id="checkNowButton"
label="&checkNow.label;" accesskey="&appCheckNow.accesskey;"
oncommand="gAdvancedPane.checkForUpdates();"
preference="app.update.enabled"/>
<button label="&showUpdates.label;" accesskey="&showUpdates.accesskey;"

View File

@@ -61,6 +61,8 @@ var gUpdateHistory = {
var element = document.createElementNS(NS_XUL, "update");
this._view.appendChild(element);
if (!update.name)
continue;
element.name = update.name;
element.type = bundle.getString("updateType_" + update.type);
element.installDate = this._formatDate(update.installDate);

View File

@@ -133,7 +133,7 @@ var gUpdates = {
* the function call to the selected page.
*/
onWizardFinish: function() {
var pageid = gUpdates.wiz.currentPage.pageid;
var pageid = document.documentElement.currentPage.pageid;
if ("onWizardFinish" in this._pages[pageid])
this._pages[pageid].onWizardFinish();
},
@@ -143,11 +143,24 @@ var gUpdates = {
* the function call to the selected page.
*/
onWizardCancel: function() {
var pageid = gUpdates.wiz.currentPage.pageid;
var pageid = document.documentElement.currentPage.pageid;
if ("onWizardCancel" in this._pages[pageid])
this._pages[pageid].onWizardCancel();
},
/**
* Called when the user presses the "Next" button on the wizard, dispatches
* the function call to the selected page.
*/
onWizardNext: function() {
var cp = document.documentElement.currentPage;
if (!cp)
return;
var pageid = cp.pageid;
if ("onWizardNext" in this._pages[pageid])
this._pages[pageid].onWizardNext();
},
/**
* The checking process that spawned this update UI. There are two types:
* SRCEVT_FOREGROUND:
@@ -276,9 +289,6 @@ var gUpdates = {
setUpdate: function(update) {
this.update = update;
this.update.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
var p = this.update.selectedPatch;
if (p)
p.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
},
/**
@@ -493,8 +503,16 @@ var gUpdatesAvailablePage = {
// If we were invoked from a background update check, automatically show
// the additional details the user may need to make this decision since
// they did not consciously make the decision to check.
if (gUpdates.sourceEvent == SRCEVT_BACKGROUND)
this.onShowMoreDetails();
// if (gUpdates.sourceEvent == SRCEVT_BACKGROUND)
// This is ridiculous... always show the additional info.
this.onShowMoreDetails();
try {
gUpdates.update.getProperty("licenseAccepted");
}
catch (e) {
gUpdates.update.setProperty("licenseAccepted", "false");
}
var downloadNow = document.getElementById("downloadNow");
downloadNow.focus();
@@ -601,6 +619,10 @@ var gLicensePage = {
*/
onWizardNext: function() {
gUpdates.update.setProperty("licenseAccepted", "true");
var um =
Components.classes["@mozilla.org/updates/update-manager;1"].
getService(Components.interfaces.nsIUpdateManager);
um.saveUpdates();
},
/**
@@ -885,10 +907,8 @@ var gDownloadingPage = {
Components.classes["@mozilla.org/updates/update-manager;1"].
getService(Components.interfaces.nsIUpdateManager);
var activeUpdate = um.activeUpdate;
if (activeUpdate) {
if (activeUpdate)
gUpdates.setUpdate(activeUpdate);
this._togglePausedState(!updates.isDownloading);
}
if (!gUpdates.update) {
LOG("UI:DownloadingPage.Progress", "no valid update to download?!");
@@ -911,6 +931,9 @@ var gDownloadingPage = {
updates.addDownloadListener(this);
}
if (activeUpdate)
this._setUIState(!updates.isDownloading);
gUpdates.wiz.getButton("back").disabled = true;
var cancelButton = gUpdates.wiz.getButton("cancel");
cancelButton.label = gUpdates.strings.getString("closeButtonLabel");
@@ -954,24 +977,28 @@ var gDownloadingPage = {
* @param paused
* Whether or not the download is paused
*/
_togglePausedState: function(paused) {
_setUIState: function(paused) {
var u = gUpdates.update;
var p = u.selectedPatch.QueryInterface(Components.interfaces.nsIPropertyBag);
var status = p.getProperty("status");
if (paused) {
this._oldStatus = this._downloadStatus.textContent;
this._oldMode = this._downloadProgress.mode;
this._oldProgress = parseInt(this._downloadProgress.progress);
this._downloadName.value = gUpdates.strings.getFormattedString(
"pausedName", [u.name]);
this._setStatus(p.getProperty("status"));
if (status)
this._setStatus(status);
this._downloadProgress.mode = "normal";
this._pauseButton.label = gUpdates.strings.getString("pauseButtonResume");
}
else {
this._downloadName.value = gUpdates.strings.getFormattedString(
"downloadingPrefix", [u.name]);
this._setStatus(this._oldStatus || p.getProperty("status"));
if (this._oldStatus)
this._setStatus(this._oldStatus);
else if (status)
this._setStatus(status);
this._downloadProgress.value =
this._oldProgress || parseInt(p.getProperty("progress"));
this._downloadProgress.mode = this._oldMode || "normal";
@@ -990,6 +1017,7 @@ var gDownloadingPage = {
updates.downloadUpdate(gUpdates.update, false);
else {
var patch = gUpdates.update.selectedPatch;
patch.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
patch.setProperty("status",
gUpdates.strings.getFormattedString("pausedStatus",
[this.statusFormatter.progress]));
@@ -998,7 +1026,7 @@ var gDownloadingPage = {
this._paused = !this._paused;
// Update the UI
this._togglePausedState(this._paused);
this._setUIState(this._paused);
},
/**
@@ -1072,6 +1100,7 @@ var gDownloadingPage = {
"/" + maxProgress);
var p = gUpdates.update.selectedPatch;
p.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
p.setProperty("progress", Math.round(100 * (progress/maxProgress)));
p.setProperty("status",
this.statusFormatter.formatStatus(progress, maxProgress));
@@ -1081,7 +1110,9 @@ var gDownloadingPage = {
this._pauseButton.disabled = false;
var name = gUpdates.strings.getFormattedString("downloadingPrefix", [gUpdates.update.name]);
this._downloadName.value = name;
this._setStatus(p.getProperty("status"));
var status = p.getProperty("status");
if (status)
this._setStatus(status);
},
/**

View File

@@ -54,6 +54,7 @@
windowtype="Update:Wizard" style="width: 36em;"
onwizardfinish="gUpdates.onWizardFinish();"
onwizardcancel="gUpdates.onWizardCancel();"
onwizardnext="gUpdates.onWizardNext();"
onload="gUpdates.onLoad();">
<script type="application/x-javascript" src="chrome://mozapps/content/update/updates.js"/>
@@ -125,8 +126,7 @@
<wizardpage id="license" pageid="license" next="downloading"
object="gLicensePage" label="&license.title;"
onpageshow="gLicensePage.onPageShow();"
onwizardnext="gLicensePage.onWizardNext();">
onpageshow="gLicensePage.onPageShow();">
<label>&license.intro;</label>
<separator class="thin"/>
<license id="licenseContent" flex="1"/>

View File

@@ -306,11 +306,6 @@ interface nsIUpdateChecker : nsISupports
* A value representing the set of checks to stop doing.
*/
void stopChecking(in unsigned short duration);
/**
* Whether or not this Checker can perform update checking.
*/
readonly attribute boolean enabled;
};
[scriptable, uuid(9849c4bf-5197-4d22-baa8-e3b44a1703d2)]
@@ -364,6 +359,13 @@ interface nsIApplicationUpdateService : nsISupports
* Whether or not there is an download happening at the moment.
*/
readonly attribute boolean isDownloading;
/**
* Whether or not the Update Service can download and install updates.
* This is a function of whether or not the current user has access
* privileges to the install directory.
*/
readonly attribute boolean canUpdate;
};
[scriptable, uuid(fede66a9-9f96-4507-a22a-775ee885577e)]

View File

@@ -37,22 +37,13 @@
* ***** END LICENSE BLOCK ***** */
const PREF_APP_UPDATE_ENABLED = "app.update.enabled";
const PREF_APP_UPDATE_AUTOINSTALL_ENABLED = "app.update.autoInstallEnabled";
// Defines the notification behavior when updates are encountered
//
// 0 = download and install all updates (including major versions, provided
// no addons are made incompatible)
// 1 = download and install minor (security) updates
// 2 = ask before doing anything
//
const PREF_APP_UPDATE_AUTOINSTALL_MODE = "app.update.autoInstallMode";
const PREF_APP_UPDATE_MODE = "app.update.mode";
const PREF_APP_UPDATE_SILENT = "app.update.silent";
const PREF_APP_UPDATE_INTERVAL = "app.update.interval";
const PREF_APP_UPDATE_TIMER = "app.update.timer";
const PREF_APP_UPDATE_LOG_BRANCH = "app.update.log.";
const PREF_APP_UPDATE_URL = "app.update.url";
const PREF_APP_UPDATE_URL_OVERRIDE = "app.update.url.override";
const PREF_UPDATE_LASTUPDATETIME_FMT = "app.update.lastUpdateTime.%ID%";
const PREF_APP_EXTENSIONS_VERSION = "app.extensions.version";
@@ -70,6 +61,7 @@ const FILE_UPDATE_ARCHIVE = "update.mar";
const FILE_UPDATE_INFO = "update.info";
const FILE_UPDATES_DB = "updates.xml";
const FILE_UPDATE_ACTIVE = "active-update.xml";
const FILE_PERMS_TEST = "update.test";
const MODE_RDONLY = 0x01;
const MODE_WRONLY = 0x02;
@@ -425,28 +417,40 @@ UpdatePrompt.prototype = {
* See nsIUpdateService.idl
*/
showUpdateAvailable: function(parent, update) {
this._showUI(parent, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard", update);
if (this._enabled) {
this._showUI(parent, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard",
update);
}
},
/**
* See nsIUpdateService.idl
*/
showUpdateDownloaded: function(parent, update) {
this._showUI(parent, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard", update);
if (this._enabled) {
this._showUI(parent, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard",
update);
}
},
/**
* See nsIUpdateService.idl
*/
showUpdateInstalled: function(update) {
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, "modal", "Update:Wizard", update);
if (this._enabled) {
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, "modal", "Update:Wizard",
update);
}
},
/**
* See nsIUpdateService.idl
*/
showUpdateError: function(update) {
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, "modal", "Update:Wizard", update);
if (this._enabled) {
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, "modal", "Update:Wizard",
update);
}
},
/**
@@ -456,6 +460,13 @@ UpdatePrompt.prototype = {
this._showUI(parent, URI_UPDATE_HISTORY_DIALOG, "modal", "Update:History", null);
},
/**
* Whether or not we are enabled (i.e. not in Silent mode)
*/
get _enabled() {
return !getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false);
},
/**
* Show the Update Checking UI
* @param parent
@@ -689,15 +700,17 @@ UpdateService.prototype = {
// The outcome we follow is determined as follows:
//
// Update Type Mode Incompatible Outcome
// Major 0 No Auto Install
// Major 0 Yes Notify and Confirm
// Major 1 Yes or No Notify and Confirm
// Major 0 Yes or No Auto Install
// Major 1 No Auto Install
// Major 1 Yes Notify and Confirm
// Major 2 Yes or No Notify and Confirm
// Minor 0 No Auto Install
// Minor 0 Yes Notify and Confirm
// Major 3 Yes or No Notify and Confirm
// Minor 0 Yes or No Auto Install
// Minor 1 No Auto Install
// Minor 1 Yes Notify and Confirm
// Minor 2 Yes or No Notify and Confirm
// Minor 2 No Auto Install
// Minor 2 Yes Notify and Confirm
// Minor 3 Yes or No Notify and Confirm
//
// In addition, if there is a license associated with an update, regardless
// of type it must be agreed to.
@@ -705,18 +718,30 @@ UpdateService.prototype = {
// If app.update.enabled is set to false, an update check is not performed
// at all, and so none of the decision making above is entered into.
//
if (update.licenseURL)
update.QueryInterface(Components.interfaces.nsIPropertyBag);
var licenseAccepted = update.getProperty("licenseAccepted") == "true";
if (update.licenseURL && !licenseAccepted)
return true;
var updateEnabled = getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true);
if (!updateEnabled)
return false;
var mode = getPref("getIntPref", PREF_APP_UPDATE_AUTOINSTALL_MODE, 0);
var compatible = isCompatible(update);
if ((update.type == "major" && (mode == 0)) ||
(update.type == "minor" && (mode == 0 || mode == 1)))
return !compatible;
switch (getPref("getIntPref", PREF_APP_UPDATE_MODE, 1)) {
case 0:
// Mode 0 is do not prompt regardless of incompatibilities
return false;
case 1:
// Mode 1 is do not prompt only if there are no incompatibilities
// releases
return !isCompatible(update);
case 2:
// Mode 2 is do not prompt only if there are no incompatibilities for
// minor updates only
if (update.type == "minor")
return !isCompatible(update);
}
// Mode 3 is prompt, regardless.
return true;
},
@@ -784,6 +809,24 @@ UpdateService.prototype = {
return this._backgroundChecker;
},
/**
* See nsIUpdateService.idl
*/
get canUpdate() {
try {
var file = getFile(KEY_APPDIR, [FILE_PERMS_TEST]);
if (!file.exists()) {
file.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
file.remove(false);
}
}
catch (e) {
// No write privileges to install directory
return false;
}
return true;
},
/**
* See nsIUpdateService.idl
*/
@@ -921,18 +964,15 @@ UpdateManager.prototype = {
this._ensureActiveUpdate();
},
_loadedActiveUpdate: false,
/**
* Ensure that the Active Update file is loaded.
*/
_ensureActiveUpdate: function() {
if (!this._loadedActiveUpdate) {
if (!this._activeUpdate) {
var updates = this._loadXMLFileIntoArray(getFile(KEY_APPDIR,
[FILE_UPDATE_ACTIVE]));
if (updates.length > 0)
this._activeUpdate = updates[0];
this._loadedActiveUpdate = true;
}
},
@@ -962,7 +1002,7 @@ UpdateManager.prototype = {
set activeUpdate(activeUpdate) {
this._ensureActiveUpdate();
if (!activeUpdate)
this._updates = [this._activeUpdate].concat(this._updates);
this._addUpdate(this._activeUpdate);
this._activeUpdate = activeUpdate;
if (!activeUpdate) {
// If |activeUpdate| is null, we have updated both lists - the active list
@@ -984,7 +1024,32 @@ UpdateManager.prototype = {
},
/**
*
* Add an update to the Updates list. If the item already exists in the list,
* replace the existing value with the new value.
* @param update
* The nsIUpdate object to add.
*/
_addUpdate: function(update) {
if (this._updates) {
for (var i = 0; i < this._updates.length; ++i) {
if (this._updates[i].version == update.version) {
// Replace the existing entry with the new value, updating
// all metadata.
this._updates[i] = update;
return;
}
}
}
// Otherwise add it to the front of the list.
this._updates = [this._activeUpdate].concat(this._updates);
},
/**
* Serializes an array of updates to an XML file
* @param updates
* An array of nsIUpdate objects
* @param file
* The nsIFile object to serialize to
*/
_writeUpdatesToXMLFile: function(updates, file) {
var fos = Components.classes["@mozilla.org/network/safe-file-output-stream;1"]
@@ -1256,7 +1321,7 @@ Update.prototype = {
for (var p in this._properties) {
if (this._properties[p].present)
patch.setAttribute(p, this._properties[p].data);
update.setAttribute(p, this._properties[p].data);
}
for (var i = 0; i < this.patchCount; ++i)
@@ -1502,8 +1567,11 @@ Checker.prototype = {
* See nsIUpdateService.idl
*/
get enabled() {
var aus =
Components.classes["@mozilla.org/updates/update-service;1"].
getService(Components.interfaces.nsIApplicationUpdateService);
var enabled = getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true) &&
this._enabled;
aus.canUpdate && this._enabled;
return enabled;
},
@@ -1867,6 +1935,7 @@ Downloader.prototype = {
var shouldShowPrompt = false;
var deleteActiveUpdate = false;
const NS_BINDING_ABORTED = 0x804b0002;
const NS_ERROR_ABORT = 0x80004004;
if (Components.isSuccessCode(status)) {
if (this._verifyDownload()) {
state = STATE_PENDING;
@@ -1908,7 +1977,8 @@ Downloader.prototype = {
cleanUpUpdatesDir();
}
}
else if (status != NS_BINDING_ABORTED) {
else if (status != NS_BINDING_ABORTED &&
status != NS_ERROR_ABORT) {
LOG("Downloader", "onStopRequest: Non-verification failure");
// Some sort of other failure, log this in the |statusText| property
state = STATE_FAILED;