Bug 740722: Wait until the user is idle before prompting to apply an update in B2G. r=fabrice

This commit is contained in:
Marshall Culpepper 2012-10-02 13:33:49 -05:00
parent 6f09be899b
commit bae89cde8e
2 changed files with 71 additions and 20 deletions

View File

@ -450,8 +450,8 @@ pref("marionette.defaultPrefs.port", 2828);
pref("shutdown.watchdog.timeoutSecs", 5);
// Timeout before the update prompt automatically installs the update
pref("b2g.update.apply-prompt-timeout", 60000); // milliseconds
// Optional timeout the user can wait before getting another update prompt
pref("b2g.update.apply-wait-timeout", 1800000); // milliseconds
// Amount of time to wait after the user is idle before prompting to apply an update
pref("b2g.update.apply-idle-timeout", 600000); // milliseconds
// Amount of time the updater waits for the process to exit cleanly before
// forcefully exiting the process
pref("b2g.update.self-destruct-timeout", 5000); // milliseconds

View File

@ -20,26 +20,33 @@ let log =
const APPLY_PROMPT_TIMEOUT =
Services.prefs.getIntPref("b2g.update.apply-prompt-timeout");
const APPLY_WAIT_TIMEOUT =
Services.prefs.getIntPref("b2g.update.apply-wait-timeout");
const APPLY_IDLE_TIMEOUT =
Services.prefs.getIntPref("b2g.update.apply-idle-timeout");
const SELF_DESTRUCT_TIMEOUT =
Services.prefs.getIntPref("b2g.update.self-destruct-timeout");
const APPLY_IDLE_TIMEOUT_SECONDS = APPLY_IDLE_TIMEOUT / 1000;
XPCOMUtils.defineLazyServiceGetter(Services, "aus",
"@mozilla.org/updates/update-service;1",
"nsIApplicationUpdateService");
XPCOMUtils.defineLazyServiceGetter(Services, "idle",
"@mozilla.org/widget/idleservice;1",
"nsIIdleService");
function UpdatePrompt() { }
UpdatePrompt.prototype = {
classID: Components.ID("{88b3eb21-d072-4e3b-886d-f89d8c49fe59}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt,
Ci.nsIRequestObserver,
Ci.nsIProgressEventSink]),
Ci.nsIProgressEventSink,
Ci.nsIObserver]),
_update: null,
_applyPromptTimer: null,
_applyWaitTimer: null,
_waitingForIdle: false,
// nsIUpdatePrompt
@ -58,16 +65,23 @@ UpdatePrompt.prototype = {
},
showUpdateDownloaded: function UP_showUpdateDownloaded(aUpdate, aBackground) {
if (!this.sendUpdateEvent("update-downloaded", aUpdate,
this.handleDownloadedResult)) {
log("Unable to prompt, forcing restart");
this.restartProcess();
// The update has been downloaded and staged. We send the update-downloaded
// event right away. After the user has been idle for a while, we send the
// update-prompt-restart event, increasing the chances that we can apply the
// update quietly without user intervention.
this.sendUpdateEvent("update-downloaded", aUpdate);
if (Services.idle.idleTime >= APPLY_IDLE_TIMEOUT) {
this.showApplyPrompt(aUpdate);
return;
}
// Schedule a fallback timeout in case the UI is unable to respond or show
// a prompt for some reason
this._applyPromptTimer = this.createTimer(APPLY_PROMPT_TIMEOUT);
// We haven't been idle long enough, so register an observer
log("Update is ready to apply, registering idle timeout of " +
APPLY_IDLE_TIMEOUT_SECONDS + " seconds before prompting.");
this._update = aUpdate;
this.waitForIdle();
},
showUpdateError: function UP_showUpdateError(aUpdate) {
@ -79,6 +93,32 @@ UpdatePrompt.prototype = {
showUpdateHistory: function UP_showUpdateHistory(aParent) { },
showUpdateInstalled: function UP_showUpdateInstalled() { },
// Custom functions
waitForIdle: function UP_waitForIdle() {
if (this._waitingForIdle) {
return;
}
this._waitingForIdle = true;
Services.idle.addIdleObserver(this, APPLY_IDLE_TIMEOUT_SECONDS);
Services.obs.addObserver(this, "quit-application", false);
},
showApplyPrompt: function UP_showApplyPrompt(aUpdate) {
if (!this.sendUpdateEvent("update-prompt-apply", aUpdate,
this.handleApplyPromptResult)) {
log("Unable to prompt, forcing restart");
this.restartProcess();
return;
}
// Schedule a fallback timeout in case the UI is unable to respond or show
// a prompt for some reason.
this._applyPromptTimer = this.createTimer(APPLY_PROMPT_TIMEOUT);
},
sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate, aCallback) {
let detail = {
displayVersion: aUpdate.displayVersion,
@ -155,7 +195,7 @@ UpdatePrompt.prototype = {
}
},
handleDownloadedResult: function UP_handleDownloadedResult(aDetail) {
handleApplyPromptResult: function UP_handleApplyPromptResult(aDetail) {
if (this._applyPromptTimer) {
this._applyPromptTimer.cancel();
this._applyPromptTimer = null;
@ -163,9 +203,8 @@ UpdatePrompt.prototype = {
switch (aDetail.result) {
case "wait":
// Wait for a fixed period of time, allowing the user to temporarily
// postpone applying an update
this._applyWaitTimer = this.createTimer(APPLY_WAIT_TIMEOUT);
// Wait until the user is idle before prompting to apply the update
this.waitForIdle();
break;
case "restart":
this.finishUpdate();
@ -236,14 +275,26 @@ UpdatePrompt.prototype = {
}
},
// nsIObserver
observe: function UP_observe(aSubject, aTopic, aData) {
switch (aTopic) {
case "idle":
this._waitingForIdle = false;
this.showApplyPrompt(this._update);
// Fall through
case "quit-application":
Services.idle.removeIdleObserver(this, APPLY_IDLE_TIMEOUT_SECONDS);
Services.obs.removeObserver(this, "quit-application");
break;
}
},
notify: function UP_notify(aTimer) {
if (aTimer == this._applyPromptTimer) {
log("Timed out waiting for result, restarting");
this._applyPromptTimer = null;
this.finishUpdate();
} else if (aTimer == this._applyWaitTimer) {
this._applyWaitTimer = null;
this.showUpdatePrompt();
}
},