browser/metro/base/content/flyoutpanels/AboutFlyoutPanel.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 'use strict';
     7 Cu.import("resource://gre/modules/Services.jsm");
     8 let gAppUpdater;
    10 let AboutFlyoutPanel = {
    11   init: function() {
    12     if (this._isInitialized) {
    13       Cu.reportError("Attempted to initialize AboutFlyoutPanel more than once");
    14     }
    16     this._isInitialized = true;
    18     let self = this;
    19     this._elements = {};
    20     [
    21       ['versionLabel', 'about-version-label'],
    22       ['AboutFlyoutPanel',  'about-flyoutpanel'],
    23     ].forEach(function(aElement) {
    24       let [name, id] = aElement;
    25       XPCOMUtils.defineLazyGetter(self._elements, name, function() {
    26         return document.getElementById(id);
    27       });
    28     });
    30     this._topmostElement = this._elements.AboutFlyoutPanel;
    32     // Include the build ID if this is an "a#" (nightly or aurora) build
    33     let version = Services.appinfo.version;
    34     if (/a\d+$/.test(version)) {
    35       let buildID = Services.appinfo.appBuildID;
    36       let buildDate = buildID.slice(0,4) + "-" + buildID.slice(4,6) +
    37                       "-" + buildID.slice(6,8);
    38       this._elements.versionLabel.textContent +=" (" + buildDate + ")";
    39     }
    41     window.addEventListener('MozFlyoutPanelShowing', this, false);
    42     window.addEventListener('MozFlyoutPanelHiding', this, false);
    44 #if MOZ_UPDATE_CHANNEL != release
    45     let defaults = Services.prefs.getDefaultBranch("");
    46     let channelLabel = document.getElementById("currentChannel");
    47     channelLabel.value = defaults.getCharPref("app.update.channel");
    48 #endif
    49   },
    51   onPolicyClick: function(aEvent) {
    52     if (aEvent.button != 0) {
    53       return;
    54     }
    55     let url = Services.urlFormatter.formatURLPref("app.privacyURL");
    56     BrowserUI.addAndShowTab(url, Browser.selectedTab);
    57   },
    59   handleEvent: function(aEvent) {
    60     switch (aEvent.type) {
    61       case 'MozFlyoutPanelShowing':
    62 #ifdef MOZ_UPDATER
    63         this.appUpdater = new appUpdater();
    64         gAppUpdater = this.appUpdater;
    65 #endif
    66         break;
    67       case 'MozFlyoutPanelHiding':
    68 #ifdef MOZ_UPDATER
    69         onUnload();
    70 #endif
    71         break;
    72     }
    73   }
    74 };
    76 #ifdef MOZ_UPDATER
    77 function onUnload(aEvent) {
    78   if (!gAppUpdater) {
    79     return;
    80   }
    82   if (gAppUpdater.isChecking)
    83     gAppUpdater.checker.stopChecking(Components.interfaces.nsIUpdateChecker.CURRENT_CHECK);
    84   // Safe to call even when there isn't a download in progress.
    85   gAppUpdater.removeDownloadListener();
    86   gAppUpdater = null;
    87   AboutFlyoutPanel.appUpdater = null;
    88 }
    90 function appUpdater()
    91 {
    92   this.updateDeck = document.getElementById("updateDeck");
    94   XPCOMUtils.defineLazyServiceGetter(this, "aus",
    95                                      "@mozilla.org/updates/update-service;1",
    96                                      "nsIApplicationUpdateService");
    97   XPCOMUtils.defineLazyServiceGetter(this, "checker",
    98                                      "@mozilla.org/updates/update-checker;1",
    99                                      "nsIUpdateChecker");
   100   XPCOMUtils.defineLazyServiceGetter(this, "um",
   101                                      "@mozilla.org/updates/update-manager;1",
   102                                      "nsIUpdateManager");
   104   this.bundle = Services.strings.
   105                 createBundle("chrome://browser/locale/browser.properties");
   107   this.updateBtn = document.getElementById("updateButton");
   109   // The button label value must be set so its height is correct.
   110   this.setupUpdateButton("update.checkInsideButton");
   112   let manualURL = Services.urlFormatter.formatURLPref("app.update.url.manual");
   113   let manualLink = document.getElementById("manualLink");
   114   manualLink.value = manualURL;
   115   manualLink.href = manualURL;
   116   document.getElementById("failedLink").href = manualURL;
   118   if (this.updateDisabledAndLocked) {
   119     this.selectPanel("adminDisabled");
   120     return;
   121   }
   123   if (this.isPending || this.isApplied) {
   124     this.setupUpdateButton("update.restart." +
   125                            (this.isMajor ? "upgradeButton" : "updateButton"));
   126     return;
   127   }
   129   if (this.aus.isOtherInstanceHandlingUpdates) {
   130     this.selectPanel("otherInstanceHandlingUpdates");
   131     return;
   132   }
   134   if (this.isDownloading) {
   135     this.startDownload();
   136     return;
   137   }
   139   if (this.updateEnabled && this.updateAuto) {
   140     this.selectPanel("checkingForUpdates");
   141     this.isChecking = true;
   142     this.checker.checkForUpdates(this.updateCheckListener, true);
   143     return;
   144   }
   145 }
   147 appUpdater.prototype =
   148 {
   149   // true when there is an update check in progress.
   150   isChecking: false,
   152   // true when there is an update already staged / ready to be applied.
   153   get isPending() {
   154     if (this.update) {
   155       return this.update.state == "pending" ||
   156              this.update.state == "pending-service";
   157     }
   158     return this.um.activeUpdate &&
   159            (this.um.activeUpdate.state == "pending" ||
   160             this.um.activeUpdate.state == "pending-service");
   161   },
   163   // true when there is an update already installed in the background.
   164   get isApplied() {
   165     if (this.update)
   166       return this.update.state == "applied" ||
   167              this.update.state == "applied-service";
   168     return this.um.activeUpdate &&
   169            (this.um.activeUpdate.state == "applied" ||
   170             this.um.activeUpdate.state == "applied-service");
   171   },
   173   // true when there is an update download in progress.
   174   get isDownloading() {
   175     if (this.update)
   176       return this.update.state == "downloading";
   177     return this.um.activeUpdate &&
   178            this.um.activeUpdate.state == "downloading";
   179   },
   181   // true when the update type is major.
   182   get isMajor() {
   183     if (this.update)
   184       return this.update.type == "major";
   185     return this.um.activeUpdate.type == "major";
   186   },
   188   // true when updating is disabled by an administrator.
   189   get updateDisabledAndLocked() {
   190     return !this.updateEnabled &&
   191            Services.prefs.prefIsLocked("app.update.enabled");
   192   },
   194   // true when updating is enabled.
   195   get updateEnabled() {
   196     let updatesEnabled = true;
   197     try {
   198       updatesEnabled = Services.prefs.getBoolPref("app.update.metro.enabled");
   199     }
   200     catch (e) { }
   201     if (!updatesEnabled) {
   202       return false;
   203     }
   205     try {
   206       updatesEnabled = Services.prefs.getBoolPref("app.update.enabled")
   207     }
   208     catch (e) { }
   210     return updatesEnabled;
   211   },
   213   // true when updating in background is enabled.
   214   get backgroundUpdateEnabled() {
   215     return this.updateEnabled &&
   216            gAppUpdater.aus.canStageUpdates;
   217   },
   219   // true when updating is automatic.
   220   get updateAuto() {
   221     try {
   222       return Services.prefs.getBoolPref("app.update.auto");
   223     }
   224     catch (e) { }
   225     return true; // Firefox default is true
   226   },
   228   /**
   229    * Sets the deck's selected panel.
   230    *
   231    * @param  aChildID
   232    *         The id of the deck's child to select.
   233    */
   234   selectPanel: function(aChildID) {
   235     this.updateDeck.selectedPanel = document.getElementById(aChildID);
   236     this.updateBtn.disabled = (aChildID != "updateButtonBox");
   237   },
   239   /**
   240    * Sets the update button's label and accesskey.
   241    *
   242    * @param  aKeyPrefix
   243    *         The prefix for the properties file entry to use for setting the
   244    *         label and accesskey.
   245    */
   246   setupUpdateButton: function(aKeyPrefix) {
   247     this.updateBtn.label = this.bundle.GetStringFromName(aKeyPrefix + ".label");
   248     this.updateBtn.accessKey = this.bundle.GetStringFromName(aKeyPrefix + ".accesskey");
   249     if (!document.commandDispatcher.focusedElement ||
   250         document.commandDispatcher.focusedElement == this.updateBtn)
   251       this.updateBtn.focus();
   252   },
   254   /**
   255    * Handles oncommand for the update button.
   256    */
   257   buttonOnCommand: function() {
   258     if (this.isPending || this.isApplied) {
   259       // Notify all windows that an application quit has been requested.
   260       let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
   261                        createInstance(Components.interfaces.nsISupportsPRBool);
   262       Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
   264       // Something aborted the quit process.
   265       if (cancelQuit.data)
   266         return;
   268       let appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
   269                        getService(Components.interfaces.nsIAppStartup);
   271       // If already in safe mode restart in safe mode (bug 327119)
   272       if (Services.appinfo.inSafeMode) {
   273         appStartup.restartInSafeMode(Components.interfaces.nsIAppStartup.eAttemptQuit);
   274         return;
   275       }
   277       Services.metro.updatePending = true;
   278       appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit |
   279                       Components.interfaces.nsIAppStartup.eRestartTouchEnvironment);
   280       return;
   281     }
   283     // XXX We can't create dialogs in metro, and we currently don't support addons, so
   284     // commenting this out for now.
   285     /* const URI_UPDATE_PROMPT_DIALOG = "chrome://mozapps/content/update/updates.xul";
   286     // Firefox no longer displays a license for updates and the licenseURL check
   287     // is just in case a distibution does.
   288     if (this.update && (this.update.billboardURL || this.update.licenseURL ||
   289         this.addons.length != 0)) {
   290       var ary = null;
   291       ary = Components.classes["@mozilla.org/supports-array;1"].
   292             createInstance(Components.interfaces.nsISupportsArray);
   293       ary.AppendElement(this.update);
   294       var openFeatures = "chrome,centerscreen,dialog=no,resizable=no,titlebar,toolbar=no";
   295       Services.ww.openWindow(null, URI_UPDATE_PROMPT_DIALOG, "", openFeatures, ary);
   296       window.close();
   297       return;
   298     }*/
   300     this.selectPanel("checkingForUpdates");
   301     this.isChecking = true;
   302     this.checker.checkForUpdates(this.updateCheckListener, true);
   303   },
   305   /**
   306    * Implements nsIUpdateCheckListener. The methods implemented by
   307    * nsIUpdateCheckListener are in a different scope from nsIIncrementalDownload
   308    * to make it clear which are used by each interface.
   309    */
   310   updateCheckListener: {
   311     /**
   312      * See nsIUpdateService.idl
   313      */
   314     onCheckComplete: function(aRequest, aUpdates, aUpdateCount) {
   315       gAppUpdater.isChecking = false;
   316       gAppUpdater.update = gAppUpdater.aus.
   317                            selectUpdate(aUpdates, aUpdates.length);
   318       if (!gAppUpdater.update) {
   319         gAppUpdater.selectPanel("noUpdatesFound");
   320         return;
   321       }
   323       if (!gAppUpdater.aus.canApplyUpdates) {
   324         gAppUpdater.selectPanel("manualUpdate");
   325         return;
   326       }
   328       // Firefox no longer displays a license for updates and the licenseURL
   329       // check is just in case a distibution does.
   330       if (gAppUpdater.update.billboardURL || gAppUpdater.update.licenseURL) {
   331         gAppUpdater.selectPanel("updateButtonBox");
   332         gAppUpdater.setupUpdateButton("update.openUpdateUI." +
   333                                       (this.isMajor ? "upgradeButton"
   334                                                     : "applyButton"));
   335         return;
   336       }
   338       if (!gAppUpdater.update.appVersion ||
   339           Services.vc.compare(gAppUpdater.update.appVersion,
   340                               Services.appinfo.version) == 0) {
   341         gAppUpdater.startDownload();
   342         return;
   343       }
   345       gAppUpdater.checkAddonCompatibility();
   346     },
   348     /**
   349      * See nsIUpdateService.idl
   350      */
   351     onError: function(aRequest, aUpdate) {
   352       // Errors in the update check are treated as no updates found. If the
   353       // update check fails repeatedly without a success the user will be
   354       // notified with the normal app update user interface so this is safe.
   355       gAppUpdater.isChecking = false;
   356       gAppUpdater.selectPanel("noUpdatesFound");
   357     },
   359     /**
   360      * See nsISupports.idl
   361      */
   362     QueryInterface: function(aIID) {
   363       if (!aIID.equals(Components.interfaces.nsIUpdateCheckListener) &&
   364           !aIID.equals(Components.interfaces.nsISupports))
   365         throw Components.results.NS_ERROR_NO_INTERFACE;
   366       return this;
   367     }
   368   },
   370   /**
   371    * Checks the compatibility of add-ons for the application update.
   372    */
   373   checkAddonCompatibility: function() {
   374     try {
   375       var hotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID);
   376     }
   377     catch (e) { }
   379     var self = this;
   380     AddonManager.getAllAddons(function(aAddons) {
   381       self.addons = [];
   382       self.addonsCheckedCount = 0;
   383       aAddons.forEach(function(aAddon) {
   384         // Protect against code that overrides the add-ons manager and doesn't
   385         // implement the isCompatibleWith or the findUpdates method.
   386         if (!("isCompatibleWith" in aAddon) || !("findUpdates" in aAddon)) {
   387           let errMsg = "Add-on doesn't implement either the isCompatibleWith " +
   388                        "or the findUpdates method!";
   389           if (aAddon.id)
   390             errMsg += " Add-on ID: " + aAddon.id;
   391           Components.utils.reportError(errMsg);
   392           return;
   393         }
   395         // If an add-on isn't appDisabled and isn't userDisabled then it is
   396         // either active now or the user expects it to be active after the
   397         // restart. If that is the case and the add-on is not installed by the
   398         // application and is not compatible with the new application version
   399         // then the user should be warned that the add-on will become
   400         // incompatible. If an addon's type equals plugin it is skipped since
   401         // checking plugins compatibility information isn't supported and
   402         // getting the scope property of a plugin breaks in some environments
   403         // (see bug 566787). The hotfix add-on is also ignored as it shouldn't
   404         // block the user from upgrading.
   405         try {
   406           if (aAddon.type != "plugin" && aAddon.id != hotfixID &&
   407               !aAddon.appDisabled && !aAddon.userDisabled &&
   408               aAddon.scope != AddonManager.SCOPE_APPLICATION &&
   409               aAddon.isCompatible &&
   410               !aAddon.isCompatibleWith(self.update.appVersion,
   411                                        self.update.platformVersion))
   412             self.addons.push(aAddon);
   413         }
   414         catch (e) {
   415           Components.utils.reportError(e);
   416         }
   417       });
   418       self.addonsTotalCount = self.addons.length;
   419       if (self.addonsTotalCount == 0) {
   420         self.startDownload();
   421         return;
   422       }
   424       self.checkAddonsForUpdates();
   425     });
   426   },
   428   /**
   429    * Checks if there are updates for add-ons that are incompatible with the
   430    * application update.
   431    */
   432   checkAddonsForUpdates: function() {
   433     this.addons.forEach(function(aAddon) {
   434       aAddon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_DETECTED,
   435                          this.update.appVersion,
   436                          this.update.platformVersion);
   437     }, this);
   438   },
   440   /**
   441    * See XPIProvider.jsm
   442    */
   443   onCompatibilityUpdateAvailable: function(aAddon) {
   444     for (var i = 0; i < this.addons.length; ++i) {
   445       if (this.addons[i].id == aAddon.id) {
   446         this.addons.splice(i, 1);
   447         break;
   448       }
   449     }
   450   },
   452   /**
   453    * See XPIProvider.jsm
   454    */
   455   onUpdateAvailable: function(aAddon, aInstall) {
   456     if (!Services.blocklist.isAddonBlocklisted(aAddon,
   457                                                this.update.appVersion,
   458                                                this.update.platformVersion)) {
   459       // Compatibility or new version updates mean the same thing here.
   460       this.onCompatibilityUpdateAvailable(aAddon);
   461     }
   462   },
   464   /**
   465    * See XPIProvider.jsm
   466    */
   467   onUpdateFinished: function(aAddon) {
   468     ++this.addonsCheckedCount;
   470     if (this.addonsCheckedCount < this.addonsTotalCount)
   471       return;
   473     if (this.addons.length == 0) {
   474       // Compatibility updates or new version updates were found for all add-ons
   475       this.startDownload();
   476       return;
   477     }
   479     this.selectPanel("updateButtonBox");
   480     this.setupUpdateButton("update.openUpdateUI." +
   481                            (this.isMajor ? "upgradeButton" : "applyButton"));
   482   },
   484   /**
   485    * Starts the download of an update mar.
   486    */
   487   startDownload: function() {
   488     if (!this.update)
   489       this.update = this.um.activeUpdate;
   490     this.update.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
   491     this.update.setProperty("foregroundDownload", "true");
   493     this.aus.pauseDownload();
   494     let state = this.aus.downloadUpdate(this.update, false);
   495     if (state == "failed") {
   496       this.selectPanel("downloadFailed");
   497       return;
   498     }
   500     this.setupDownloadingUI();
   501   },
   503   /**
   504    * Switches to the UI responsible for tracking the download.
   505    */
   506   setupDownloadingUI: function() {
   507     this.downloadStatus = document.getElementById("downloadStatus");
   508     this.downloadStatus.textContent =
   509       DownloadUtils.getTransferTotal(0, this.update.selectedPatch.size);
   510     this.selectPanel("downloading");
   511     this.aus.addDownloadListener(this);
   512   },
   514   removeDownloadListener: function() {
   515     if (this.aus) {
   516       this.aus.removeDownloadListener(this);
   517     }
   518   },
   520   /**
   521    * See nsIRequestObserver.idl
   522    */
   523   onStartRequest: function(aRequest, aContext) {
   524   },
   526   /**
   527    * See nsIRequestObserver.idl
   528    */
   529   onStopRequest: function(aRequest, aContext, aStatusCode) {
   530     switch (aStatusCode) {
   531     case Components.results.NS_ERROR_UNEXPECTED:
   532       if (this.update.selectedPatch.state == "download-failed" &&
   533           (this.update.isCompleteUpdate || this.update.patchCount != 2)) {
   534         // Verification error of complete patch, informational text is held in
   535         // the update object.
   536         this.removeDownloadListener();
   537         this.selectPanel("downloadFailed");
   538         break;
   539       }
   540       // Verification failed for a partial patch, complete patch is now
   541       // downloading so return early and do NOT remove the download listener!
   542       break;
   543     case Components.results.NS_BINDING_ABORTED:
   544       // Do not remove UI listener since the user may resume downloading again.
   545       break;
   546     case Components.results.NS_OK:
   547       this.removeDownloadListener();
   548       if (this.backgroundUpdateEnabled) {
   549         this.selectPanel("applying");
   550         let update = this.um.activeUpdate;
   551         let self = this;
   552         Services.obs.addObserver(function updateStaged(aSubject, aTopic, aData) {
   553           // Update the UI when the background updater is finished
   554           let status = aData;
   555           if (status == "applied" || status == "applied-service" ||
   556               status == "pending" || status == "pending-service") {
   557             // If the update is successfully applied, or if the updater has
   558             // fallen back to non-staged updates, show the Restart to Update
   559             // button.
   560             self.selectPanel("updateButtonBox");
   561             self.setupUpdateButton("update.restart." +
   562                                    (self.isMajor ? "upgradeButton" : "updateButton"));
   563           } else if (status == "failed") {
   564             // Background update has failed, let's show the UI responsible for
   565             // prompting the user to update manually.
   566             self.selectPanel("downloadFailed");
   567           } else if (status == "downloading") {
   568             // We've fallen back to downloading the full update because the
   569             // partial update failed to get staged in the background.
   570             // Therefore we need to keep our observer.
   571             self.setupDownloadingUI();
   572             return;
   573           }
   574           Services.obs.removeObserver(updateStaged, "update-staged");
   575         }, "update-staged", false);
   576       } else {
   577         this.selectPanel("updateButtonBox");
   578         this.setupUpdateButton("update.restart." +
   579                                (this.isMajor ? "upgradeButton" : "updateButton"));
   580       }
   581       break;
   582     default:
   583       this.removeDownloadListener();
   584       this.selectPanel("downloadFailed");
   585       break;
   586     }
   588   },
   590   /**
   591    * See nsIProgressEventSink.idl
   592    */
   593   onStatus: function(aRequest, aContext, aStatus, aStatusArg) {
   594   },
   596   /**
   597    * See nsIProgressEventSink.idl
   598    */
   599   onProgress: function(aRequest, aContext, aProgress, aProgressMax) {
   600     this.downloadStatus.textContent =
   601       DownloadUtils.getTransferTotal(aProgress, aProgressMax);
   602   },
   604   /**
   605    * See nsISupports.idl
   606    */
   607   QueryInterface: function(aIID) {
   608     if (!aIID.equals(Components.interfaces.nsIProgressEventSink) &&
   609         !aIID.equals(Components.interfaces.nsIRequestObserver) &&
   610         !aIID.equals(Components.interfaces.nsISupports))
   611       throw Components.results.NS_ERROR_NO_INTERFACE;
   612     return this;
   613   }
   614 };
   615 #endif

mercurial