|
1 # This Source Code Form is subject to the terms of the Mozilla Public |
|
2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 |
|
5 // Services = object with smart getters for common XPCOM services |
|
6 Components.utils.import("resource://gre/modules/Services.jsm"); |
|
7 |
|
8 const PREF_EM_HOTFIX_ID = "extensions.hotfix.id"; |
|
9 |
|
10 #ifdef TOR_BROWSER_VERSION |
|
11 # Add double-quotes back on (stripped by JarMaker.py). |
|
12 #expand const TOR_BROWSER_VERSION = "__TOR_BROWSER_VERSION__"; |
|
13 #endif |
|
14 |
|
15 function init(aEvent) |
|
16 { |
|
17 if (aEvent.target != document) |
|
18 return; |
|
19 |
|
20 try { |
|
21 var distroId = Services.prefs.getCharPref("distribution.id"); |
|
22 if (distroId) { |
|
23 var distroVersion = Services.prefs.getCharPref("distribution.version"); |
|
24 |
|
25 var distroIdField = document.getElementById("distributionId"); |
|
26 distroIdField.value = distroId + " - " + distroVersion; |
|
27 distroIdField.style.display = "block"; |
|
28 |
|
29 try { |
|
30 // This is in its own try catch due to bug 895473 and bug 900925. |
|
31 var distroAbout = Services.prefs.getComplexValue("distribution.about", |
|
32 Components.interfaces.nsISupportsString); |
|
33 var distroField = document.getElementById("distribution"); |
|
34 distroField.value = distroAbout; |
|
35 distroField.style.display = "block"; |
|
36 } |
|
37 catch (ex) { |
|
38 // Pref is unset |
|
39 Components.utils.reportError(ex); |
|
40 } |
|
41 } |
|
42 } |
|
43 catch (e) { |
|
44 // Pref is unset |
|
45 } |
|
46 |
|
47 // Include the build ID and display warning if this is an "a#" (nightly or aurora) build |
|
48 let version = Services.appinfo.version; |
|
49 if (/a\d+$/.test(version)) { |
|
50 document.getElementById("experimental").hidden = false; |
|
51 document.getElementById("communityDesc").hidden = true; |
|
52 } |
|
53 |
|
54 #ifdef TOR_BROWSER_VERSION |
|
55 let versionElem = document.getElementById("version"); |
|
56 if (versionElem) |
|
57 versionElem.textContent += " (Tor Browser " + TOR_BROWSER_VERSION + ")"; |
|
58 #endif |
|
59 |
|
60 #ifdef MOZ_UPDATER |
|
61 gAppUpdater = new appUpdater(); |
|
62 |
|
63 #if MOZ_UPDATE_CHANNEL != release |
|
64 let defaults = Services.prefs.getDefaultBranch(""); |
|
65 let channelLabel = document.getElementById("currentChannel"); |
|
66 channelLabel.value = defaults.getCharPref("app.update.channel"); |
|
67 #endif |
|
68 #endif |
|
69 |
|
70 #ifdef XP_MACOSX |
|
71 // it may not be sized at this point, and we need its width to calculate its position |
|
72 window.sizeToContent(); |
|
73 window.moveTo((screen.availWidth / 2) - (window.outerWidth / 2), screen.availHeight / 5); |
|
74 #endif |
|
75 } |
|
76 |
|
77 #ifdef MOZ_UPDATER |
|
78 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
79 Components.utils.import("resource://gre/modules/DownloadUtils.jsm"); |
|
80 Components.utils.import("resource://gre/modules/AddonManager.jsm"); |
|
81 |
|
82 var gAppUpdater; |
|
83 |
|
84 function onUnload(aEvent) { |
|
85 if (gAppUpdater.isChecking) |
|
86 gAppUpdater.checker.stopChecking(Components.interfaces.nsIUpdateChecker.CURRENT_CHECK); |
|
87 // Safe to call even when there isn't a download in progress. |
|
88 gAppUpdater.removeDownloadListener(); |
|
89 gAppUpdater = null; |
|
90 } |
|
91 |
|
92 |
|
93 function appUpdater() |
|
94 { |
|
95 this.updateDeck = document.getElementById("updateDeck"); |
|
96 |
|
97 // Hide the update deck when there is already an update window open to avoid |
|
98 // syncing issues between them. |
|
99 if (Services.wm.getMostRecentWindow("Update:Wizard")) { |
|
100 this.updateDeck.hidden = true; |
|
101 return; |
|
102 } |
|
103 |
|
104 XPCOMUtils.defineLazyServiceGetter(this, "aus", |
|
105 "@mozilla.org/updates/update-service;1", |
|
106 "nsIApplicationUpdateService"); |
|
107 XPCOMUtils.defineLazyServiceGetter(this, "checker", |
|
108 "@mozilla.org/updates/update-checker;1", |
|
109 "nsIUpdateChecker"); |
|
110 XPCOMUtils.defineLazyServiceGetter(this, "um", |
|
111 "@mozilla.org/updates/update-manager;1", |
|
112 "nsIUpdateManager"); |
|
113 |
|
114 this.bundle = Services.strings. |
|
115 createBundle("chrome://browser/locale/browser.properties"); |
|
116 |
|
117 let manualURL = Services.urlFormatter.formatURLPref("app.update.url.manual"); |
|
118 let manualLink = document.getElementById("manualLink"); |
|
119 manualLink.value = manualURL; |
|
120 manualLink.href = manualURL; |
|
121 document.getElementById("failedLink").href = manualURL; |
|
122 |
|
123 if (this.updateDisabledAndLocked) { |
|
124 this.selectPanel("adminDisabled"); |
|
125 return; |
|
126 } |
|
127 |
|
128 if (this.isPending || this.isApplied) { |
|
129 this.selectPanel("apply"); |
|
130 return; |
|
131 } |
|
132 |
|
133 if (this.aus.isOtherInstanceHandlingUpdates) { |
|
134 this.selectPanel("otherInstanceHandlingUpdates"); |
|
135 return; |
|
136 } |
|
137 |
|
138 if (this.isDownloading) { |
|
139 this.startDownload(); |
|
140 // selectPanel("downloading") is called from setupDownloadingUI(). |
|
141 return; |
|
142 } |
|
143 |
|
144 // Honor the "Never check for updates" option by not only disabling background |
|
145 // update checks, but also in the About dialog, by presenting a |
|
146 // "Check for updates" button. |
|
147 // If updates are found, the user is then asked if he wants to "Update to <version>". |
|
148 if (!this.updateEnabled) { |
|
149 this.selectPanel("checkForUpdates"); |
|
150 return; |
|
151 } |
|
152 |
|
153 // That leaves the options |
|
154 // "Check for updates, but let me choose whether to install them", and |
|
155 // "Automatically install updates". |
|
156 // In both cases, we check for updates without asking. |
|
157 // In the "let me choose" case, we ask before downloading though, in onCheckComplete. |
|
158 this.checkForUpdates(); |
|
159 } |
|
160 |
|
161 appUpdater.prototype = |
|
162 { |
|
163 // true when there is an update check in progress. |
|
164 isChecking: false, |
|
165 |
|
166 // true when there is an update already staged / ready to be applied. |
|
167 get isPending() { |
|
168 if (this.update) { |
|
169 return this.update.state == "pending" || |
|
170 this.update.state == "pending-service"; |
|
171 } |
|
172 return this.um.activeUpdate && |
|
173 (this.um.activeUpdate.state == "pending" || |
|
174 this.um.activeUpdate.state == "pending-service"); |
|
175 }, |
|
176 |
|
177 // true when there is an update already installed in the background. |
|
178 get isApplied() { |
|
179 if (this.update) |
|
180 return this.update.state == "applied" || |
|
181 this.update.state == "applied-service"; |
|
182 return this.um.activeUpdate && |
|
183 (this.um.activeUpdate.state == "applied" || |
|
184 this.um.activeUpdate.state == "applied-service"); |
|
185 }, |
|
186 |
|
187 // true when there is an update download in progress. |
|
188 get isDownloading() { |
|
189 if (this.update) |
|
190 return this.update.state == "downloading"; |
|
191 return this.um.activeUpdate && |
|
192 this.um.activeUpdate.state == "downloading"; |
|
193 }, |
|
194 |
|
195 // true when updating is disabled by an administrator. |
|
196 get updateDisabledAndLocked() { |
|
197 return !this.updateEnabled && |
|
198 Services.prefs.prefIsLocked("app.update.enabled"); |
|
199 }, |
|
200 |
|
201 // true when updating is enabled. |
|
202 get updateEnabled() { |
|
203 try { |
|
204 return Services.prefs.getBoolPref("app.update.enabled"); |
|
205 } |
|
206 catch (e) { } |
|
207 return true; // Firefox default is true |
|
208 }, |
|
209 |
|
210 // true when updating in background is enabled. |
|
211 get backgroundUpdateEnabled() { |
|
212 return this.updateEnabled && |
|
213 gAppUpdater.aus.canStageUpdates; |
|
214 }, |
|
215 |
|
216 // true when updating is automatic. |
|
217 get updateAuto() { |
|
218 try { |
|
219 return Services.prefs.getBoolPref("app.update.auto"); |
|
220 } |
|
221 catch (e) { } |
|
222 return true; // Firefox default is true |
|
223 }, |
|
224 |
|
225 /** |
|
226 * Sets the panel of the updateDeck. |
|
227 * |
|
228 * @param aChildID |
|
229 * The id of the deck's child to select, e.g. "apply". |
|
230 */ |
|
231 selectPanel: function(aChildID) { |
|
232 let panel = document.getElementById(aChildID); |
|
233 |
|
234 let button = panel.querySelector("button"); |
|
235 if (button) { |
|
236 if (aChildID == "downloadAndInstall") { |
|
237 let updateVersion = gAppUpdater.update.displayVersion; |
|
238 button.label = this.bundle.formatStringFromName("update.downloadAndInstallButton.label", [updateVersion], 1); |
|
239 button.accessKey = this.bundle.GetStringFromName("update.downloadAndInstallButton.accesskey"); |
|
240 } |
|
241 this.updateDeck.selectedPanel = panel; |
|
242 if (!document.commandDispatcher.focusedElement || // don't steal the focus |
|
243 document.commandDispatcher.focusedElement.localName == "button") // except from the other buttons |
|
244 button.focus(); |
|
245 |
|
246 } else { |
|
247 this.updateDeck.selectedPanel = panel; |
|
248 } |
|
249 }, |
|
250 |
|
251 /** |
|
252 * Check for updates |
|
253 */ |
|
254 checkForUpdates: function() { |
|
255 this.selectPanel("checkingForUpdates"); |
|
256 this.isChecking = true; |
|
257 this.checker.checkForUpdates(this.updateCheckListener, true); |
|
258 // after checking, onCheckComplete() is called |
|
259 }, |
|
260 |
|
261 /** |
|
262 * Check for addon compat, or start the download right away |
|
263 */ |
|
264 doUpdate: function() { |
|
265 // skip the compatibility check if the update doesn't provide appVersion, |
|
266 // or the appVersion is unchanged, e.g. nightly update |
|
267 #ifdef TOR_BROWSER_UPDATE |
|
268 let pkgVersion = TOR_BROWSER_VERSION; |
|
269 #else |
|
270 let pkgVersion = Services.appinfo.version; |
|
271 #endif |
|
272 if (!this.update.appVersion || |
|
273 Services.vc.compare(gAppUpdater.update.appVersion, pkgVersion) == 0) { |
|
274 this.startDownload(); |
|
275 } else { |
|
276 this.checkAddonCompatibility(); |
|
277 } |
|
278 }, |
|
279 |
|
280 /** |
|
281 * Handles oncommand for the "Restart to Update" button |
|
282 * which is presented after the download has been downloaded. |
|
283 */ |
|
284 buttonRestartAfterDownload: function() { |
|
285 if (!this.isPending && !this.isApplied) |
|
286 return; |
|
287 |
|
288 // Notify all windows that an application quit has been requested. |
|
289 let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]. |
|
290 createInstance(Components.interfaces.nsISupportsPRBool); |
|
291 Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart"); |
|
292 |
|
293 // Something aborted the quit process. |
|
294 if (cancelQuit.data) |
|
295 return; |
|
296 |
|
297 let appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]. |
|
298 getService(Components.interfaces.nsIAppStartup); |
|
299 |
|
300 // If already in safe mode restart in safe mode (bug 327119) |
|
301 if (Services.appinfo.inSafeMode) { |
|
302 appStartup.restartInSafeMode(Components.interfaces.nsIAppStartup.eAttemptQuit); |
|
303 return; |
|
304 } |
|
305 |
|
306 appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit | |
|
307 Components.interfaces.nsIAppStartup.eRestart); |
|
308 }, |
|
309 |
|
310 /** |
|
311 * Handles oncommand for the "Apply Update…" button |
|
312 * which is presented if we need to show the billboard or license. |
|
313 */ |
|
314 buttonApplyBillboard: function() { |
|
315 const URI_UPDATE_PROMPT_DIALOG = "chrome://mozapps/content/update/updates.xul"; |
|
316 var ary = null; |
|
317 ary = Components.classes["@mozilla.org/supports-array;1"]. |
|
318 createInstance(Components.interfaces.nsISupportsArray); |
|
319 ary.AppendElement(this.update); |
|
320 var openFeatures = "chrome,centerscreen,dialog=no,resizable=no,titlebar,toolbar=no"; |
|
321 Services.ww.openWindow(null, URI_UPDATE_PROMPT_DIALOG, "", openFeatures, ary); |
|
322 window.close(); // close the "About" window; updates.xul takes over. |
|
323 }, |
|
324 |
|
325 /** |
|
326 * Implements nsIUpdateCheckListener. The methods implemented by |
|
327 * nsIUpdateCheckListener are in a different scope from nsIIncrementalDownload |
|
328 * to make it clear which are used by each interface. |
|
329 */ |
|
330 updateCheckListener: { |
|
331 /** |
|
332 * See nsIUpdateService.idl |
|
333 */ |
|
334 onCheckComplete: function(aRequest, aUpdates, aUpdateCount) { |
|
335 gAppUpdater.isChecking = false; |
|
336 gAppUpdater.update = gAppUpdater.aus. |
|
337 selectUpdate(aUpdates, aUpdates.length); |
|
338 if (!gAppUpdater.update) { |
|
339 gAppUpdater.selectPanel("noUpdatesFound"); |
|
340 return; |
|
341 } |
|
342 |
|
343 if (gAppUpdater.update.unsupported) { |
|
344 if (gAppUpdater.update.detailsURL) { |
|
345 let unsupportedLink = document.getElementById("unsupportedLink"); |
|
346 unsupportedLink.href = gAppUpdater.update.detailsURL; |
|
347 } |
|
348 gAppUpdater.selectPanel("unsupportedSystem"); |
|
349 return; |
|
350 } |
|
351 |
|
352 if (!gAppUpdater.aus.canApplyUpdates) { |
|
353 gAppUpdater.selectPanel("manualUpdate"); |
|
354 return; |
|
355 } |
|
356 |
|
357 // Firefox no longer displays a license for updates and the licenseURL |
|
358 // check is just in case a distibution does. |
|
359 if (gAppUpdater.update.billboardURL || gAppUpdater.update.licenseURL) { |
|
360 gAppUpdater.selectPanel("applyBillboard"); |
|
361 return; |
|
362 } |
|
363 |
|
364 if (gAppUpdater.updateAuto) // automatically download and install |
|
365 gAppUpdater.doUpdate(); |
|
366 else // ask |
|
367 gAppUpdater.selectPanel("downloadAndInstall"); |
|
368 }, |
|
369 |
|
370 /** |
|
371 * See nsIUpdateService.idl |
|
372 */ |
|
373 onError: function(aRequest, aUpdate) { |
|
374 // Errors in the update check are treated as no updates found. If the |
|
375 // update check fails repeatedly without a success the user will be |
|
376 // notified with the normal app update user interface so this is safe. |
|
377 gAppUpdater.isChecking = false; |
|
378 gAppUpdater.selectPanel("noUpdatesFound"); |
|
379 }, |
|
380 |
|
381 /** |
|
382 * See nsISupports.idl |
|
383 */ |
|
384 QueryInterface: function(aIID) { |
|
385 if (!aIID.equals(Components.interfaces.nsIUpdateCheckListener) && |
|
386 !aIID.equals(Components.interfaces.nsISupports)) |
|
387 throw Components.results.NS_ERROR_NO_INTERFACE; |
|
388 return this; |
|
389 } |
|
390 }, |
|
391 |
|
392 /** |
|
393 * Checks the compatibility of add-ons for the application update. |
|
394 */ |
|
395 checkAddonCompatibility: function() { |
|
396 try { |
|
397 var hotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID); |
|
398 } |
|
399 catch (e) { } |
|
400 |
|
401 var self = this; |
|
402 AddonManager.getAllAddons(function(aAddons) { |
|
403 self.addons = []; |
|
404 self.addonsCheckedCount = 0; |
|
405 aAddons.forEach(function(aAddon) { |
|
406 // Protect against code that overrides the add-ons manager and doesn't |
|
407 // implement the isCompatibleWith or the findUpdates method. |
|
408 if (!("isCompatibleWith" in aAddon) || !("findUpdates" in aAddon)) { |
|
409 let errMsg = "Add-on doesn't implement either the isCompatibleWith " + |
|
410 "or the findUpdates method!"; |
|
411 if (aAddon.id) |
|
412 errMsg += " Add-on ID: " + aAddon.id; |
|
413 Components.utils.reportError(errMsg); |
|
414 return; |
|
415 } |
|
416 |
|
417 // If an add-on isn't appDisabled and isn't userDisabled then it is |
|
418 // either active now or the user expects it to be active after the |
|
419 // restart. If that is the case and the add-on is not installed by the |
|
420 // application and is not compatible with the new application version |
|
421 // then the user should be warned that the add-on will become |
|
422 // incompatible. If an addon's type equals plugin it is skipped since |
|
423 // checking plugins compatibility information isn't supported and |
|
424 // getting the scope property of a plugin breaks in some environments |
|
425 // (see bug 566787). The hotfix add-on is also ignored as it shouldn't |
|
426 // block the user from upgrading. |
|
427 try { |
|
428 #ifdef TOR_BROWSER_UPDATE |
|
429 let compatVersion = self.update.platformVersion; |
|
430 #else |
|
431 let compatVersion = self.update.appVersion; |
|
432 #endif |
|
433 if (aAddon.type != "plugin" && aAddon.id != hotfixID && |
|
434 !aAddon.appDisabled && !aAddon.userDisabled && |
|
435 aAddon.scope != AddonManager.SCOPE_APPLICATION && |
|
436 aAddon.isCompatible && |
|
437 !aAddon.isCompatibleWith(compatVersion, |
|
438 self.update.platformVersion)) |
|
439 self.addons.push(aAddon); |
|
440 } |
|
441 catch (e) { |
|
442 Components.utils.reportError(e); |
|
443 } |
|
444 }); |
|
445 self.addonsTotalCount = self.addons.length; |
|
446 if (self.addonsTotalCount == 0) { |
|
447 self.startDownload(); |
|
448 return; |
|
449 } |
|
450 |
|
451 self.checkAddonsForUpdates(); |
|
452 }); |
|
453 }, |
|
454 |
|
455 /** |
|
456 * Checks if there are updates for add-ons that are incompatible with the |
|
457 * application update. |
|
458 */ |
|
459 checkAddonsForUpdates: function() { |
|
460 this.addons.forEach(function(aAddon) { |
|
461 #ifdef TOR_BROWSER_UPDATE |
|
462 let compatVersion = this.update.platformVersion; |
|
463 #else |
|
464 let compatVersion = this.update.appVersion; |
|
465 #endif |
|
466 aAddon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_DETECTED, |
|
467 compatVersion, |
|
468 this.update.platformVersion); |
|
469 }, this); |
|
470 }, |
|
471 |
|
472 /** |
|
473 * See XPIProvider.jsm |
|
474 */ |
|
475 onCompatibilityUpdateAvailable: function(aAddon) { |
|
476 for (var i = 0; i < this.addons.length; ++i) { |
|
477 if (this.addons[i].id == aAddon.id) { |
|
478 this.addons.splice(i, 1); |
|
479 break; |
|
480 } |
|
481 } |
|
482 }, |
|
483 |
|
484 /** |
|
485 * See XPIProvider.jsm |
|
486 */ |
|
487 onUpdateAvailable: function(aAddon, aInstall) { |
|
488 #ifdef TOR_BROWSER_UPDATE |
|
489 let compatVersion = this.update.platformVersion; |
|
490 #else |
|
491 let compatVersion = this.update.appVersion; |
|
492 #endif |
|
493 if (!Services.blocklist.isAddonBlocklisted(aAddon, |
|
494 compatVersion, |
|
495 this.update.platformVersion)) { |
|
496 // Compatibility or new version updates mean the same thing here. |
|
497 this.onCompatibilityUpdateAvailable(aAddon); |
|
498 } |
|
499 }, |
|
500 |
|
501 /** |
|
502 * See XPIProvider.jsm |
|
503 */ |
|
504 onUpdateFinished: function(aAddon) { |
|
505 ++this.addonsCheckedCount; |
|
506 |
|
507 if (this.addonsCheckedCount < this.addonsTotalCount) |
|
508 return; |
|
509 |
|
510 if (this.addons.length == 0) { |
|
511 // Compatibility updates or new version updates were found for all add-ons |
|
512 this.startDownload(); |
|
513 return; |
|
514 } |
|
515 |
|
516 this.selectPanel("apply"); |
|
517 }, |
|
518 |
|
519 /** |
|
520 * Starts the download of an update mar. |
|
521 */ |
|
522 startDownload: function() { |
|
523 if (!this.update) |
|
524 this.update = this.um.activeUpdate; |
|
525 this.update.QueryInterface(Components.interfaces.nsIWritablePropertyBag); |
|
526 this.update.setProperty("foregroundDownload", "true"); |
|
527 |
|
528 this.aus.pauseDownload(); |
|
529 let state = this.aus.downloadUpdate(this.update, false); |
|
530 if (state == "failed") { |
|
531 this.selectPanel("downloadFailed"); |
|
532 return; |
|
533 } |
|
534 |
|
535 this.setupDownloadingUI(); |
|
536 }, |
|
537 |
|
538 /** |
|
539 * Switches to the UI responsible for tracking the download. |
|
540 */ |
|
541 setupDownloadingUI: function() { |
|
542 this.downloadStatus = document.getElementById("downloadStatus"); |
|
543 this.downloadStatus.value = |
|
544 DownloadUtils.getTransferTotal(0, this.update.selectedPatch.size); |
|
545 this.selectPanel("downloading"); |
|
546 this.aus.addDownloadListener(this); |
|
547 }, |
|
548 |
|
549 removeDownloadListener: function() { |
|
550 if (this.aus) { |
|
551 this.aus.removeDownloadListener(this); |
|
552 } |
|
553 }, |
|
554 |
|
555 /** |
|
556 * See nsIRequestObserver.idl |
|
557 */ |
|
558 onStartRequest: function(aRequest, aContext) { |
|
559 }, |
|
560 |
|
561 /** |
|
562 * See nsIRequestObserver.idl |
|
563 */ |
|
564 onStopRequest: function(aRequest, aContext, aStatusCode) { |
|
565 switch (aStatusCode) { |
|
566 case Components.results.NS_ERROR_UNEXPECTED: |
|
567 if (this.update.selectedPatch.state == "download-failed" && |
|
568 (this.update.isCompleteUpdate || this.update.patchCount != 2)) { |
|
569 // Verification error of complete patch, informational text is held in |
|
570 // the update object. |
|
571 this.removeDownloadListener(); |
|
572 this.selectPanel("downloadFailed"); |
|
573 break; |
|
574 } |
|
575 // Verification failed for a partial patch, complete patch is now |
|
576 // downloading so return early and do NOT remove the download listener! |
|
577 break; |
|
578 case Components.results.NS_BINDING_ABORTED: |
|
579 // Do not remove UI listener since the user may resume downloading again. |
|
580 break; |
|
581 case Components.results.NS_OK: |
|
582 this.removeDownloadListener(); |
|
583 if (this.backgroundUpdateEnabled) { |
|
584 this.selectPanel("applying"); |
|
585 let update = this.um.activeUpdate; |
|
586 let self = this; |
|
587 Services.obs.addObserver(function (aSubject, aTopic, aData) { |
|
588 // Update the UI when the background updater is finished |
|
589 let status = aData; |
|
590 if (status == "applied" || status == "applied-service" || |
|
591 status == "pending" || status == "pending-service") { |
|
592 // If the update is successfully applied, or if the updater has |
|
593 // fallen back to non-staged updates, show the "Restart to Update" |
|
594 // button. |
|
595 self.selectPanel("apply"); |
|
596 } else if (status == "failed") { |
|
597 // Background update has failed, let's show the UI responsible for |
|
598 // prompting the user to update manually. |
|
599 self.selectPanel("downloadFailed"); |
|
600 } else if (status == "downloading") { |
|
601 // We've fallen back to downloading the full update because the |
|
602 // partial update failed to get staged in the background. |
|
603 // Therefore we need to keep our observer. |
|
604 self.setupDownloadingUI(); |
|
605 return; |
|
606 } |
|
607 Services.obs.removeObserver(arguments.callee, "update-staged"); |
|
608 }, "update-staged", false); |
|
609 } else { |
|
610 this.selectPanel("apply"); |
|
611 } |
|
612 break; |
|
613 default: |
|
614 this.removeDownloadListener(); |
|
615 this.selectPanel("downloadFailed"); |
|
616 break; |
|
617 } |
|
618 }, |
|
619 |
|
620 /** |
|
621 * See nsIProgressEventSink.idl |
|
622 */ |
|
623 onStatus: function(aRequest, aContext, aStatus, aStatusArg) { |
|
624 }, |
|
625 |
|
626 /** |
|
627 * See nsIProgressEventSink.idl |
|
628 */ |
|
629 onProgress: function(aRequest, aContext, aProgress, aProgressMax) { |
|
630 this.downloadStatus.value = |
|
631 DownloadUtils.getTransferTotal(aProgress, aProgressMax); |
|
632 }, |
|
633 |
|
634 /** |
|
635 * See nsISupports.idl |
|
636 */ |
|
637 QueryInterface: function(aIID) { |
|
638 if (!aIID.equals(Components.interfaces.nsIProgressEventSink) && |
|
639 !aIID.equals(Components.interfaces.nsIRequestObserver) && |
|
640 !aIID.equals(Components.interfaces.nsISupports)) |
|
641 throw Components.results.NS_ERROR_NO_INTERFACE; |
|
642 return this; |
|
643 } |
|
644 }; |
|
645 #endif |