mobile/android/chrome/content/downloads.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/. */
     6 "use strict";
     8 let Cu = Components.utils;
     9 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    11 function dump(a) {
    12   Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(a);
    13 }
    15 XPCOMUtils.defineLazyModuleGetter(this, "Notifications",
    16                                   "resource://gre/modules/Notifications.jsm");
    18 const URI_GENERIC_ICON_DOWNLOAD = "drawable://alert_download";
    19 const URI_PAUSE_ICON = "drawable://pause";
    20 const URI_CANCEL_ICON = "drawable://close";
    21 const URI_RESUME_ICON = "drawable://play";
    24 XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
    26 var Downloads = {
    27   _initialized: false,
    28   _dlmgr: null,
    29   _progressAlert: null,
    30   _privateDownloads: [],
    31   _showingPrompt: false,
    32   _downloadsIdMap: {},
    34   _getLocalFile: function dl__getLocalFile(aFileURI) {
    35     // if this is a URL, get the file from that
    36     // XXX it's possible that using a null char-set here is bad
    37     const fileUrl = Services.io.newURI(aFileURI, null, null).QueryInterface(Ci.nsIFileURL);
    38     return fileUrl.file.clone().QueryInterface(Ci.nsILocalFile);
    39   },
    41   init: function dl_init() {
    42     if (this._initialized)
    43       return;
    44     this._initialized = true;
    46     // Monitor downloads and display alerts
    47     this._dlmgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
    48     this._progressAlert = new AlertDownloadProgressListener();
    49     this._dlmgr.addPrivacyAwareListener(this._progressAlert);
    50     Services.obs.addObserver(this, "last-pb-context-exited", true);
    51   },
    53   openDownload: function dl_openDownload(aDownload) {
    54     let fileUri = aDownload.target.spec;
    55     let guid = aDownload.guid;
    56     let f = this._getLocalFile(fileUri);
    57     try {
    58       f.launch();
    59     } catch (ex) {
    60       // in case we are not able to open the file (i.e. there is no app able to handle it)
    61       // we just open the browser tab showing it 
    62       BrowserApp.addTab("about:downloads?id=" + guid);
    63     }
    64   },
    66   cancelDownload: function dl_cancelDownload(aDownload) {
    67     aDownload.cancel();
    68     let fileURI = aDownload.target.spec;
    69     let f = this._getLocalFile(fileURI);
    71     OS.File.remove(f.path);
    72   },
    74   showCancelConfirmPrompt: function dl_showCancelConfirmPrompt(aDownload) {
    75     if (this._showingPrompt)
    76       return;
    77     this._showingPrompt = true;
    78     // Open a prompt that offers a choice to cancel the download
    79     let title = Strings.browser.GetStringFromName("downloadCancelPromptTitle");
    80     let message = Strings.browser.GetStringFromName("downloadCancelPromptMessage");
    81     let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_YES +
    82                 Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_NO;
    83     let choice = Services.prompt.confirmEx(null, title, message, flags,
    84                                            null, null, null, null, {});
    85     if (choice == 0)
    86       this.cancelDownload(aDownload);
    87     this._showingPrompt = false;
    88   },
    90   handleClickEvent: function dl_handleClickEvent(aDownload) {
    91     // Only open the downloaded file if the download is complete
    92     if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED)
    93       this.openDownload(aDownload);
    94     else if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING ||
    95                 aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_PAUSED)
    96       this.showCancelConfirmPrompt(aDownload);
    97   },
    99   clickCallback: function dl_clickCallback(aDownloadId) {
   100     this._dlmgr.getDownloadByGUID(aDownloadId, (function(status, download) {
   101           if (Components.isSuccessCode(status))
   102             this.handleClickEvent(download);
   103         }).bind(this));
   104   },
   106   pauseClickCallback: function dl_buttonPauseCallback(aDownloadId) {
   107     this._dlmgr.getDownloadByGUID(aDownloadId, (function(status, download) {
   108           if (Components.isSuccessCode(status))
   109             download.pause();
   110         }).bind(this));
   111   },
   113   resumeClickCallback: function dl_buttonPauseCallback(aDownloadId) {
   114     this._dlmgr.getDownloadByGUID(aDownloadId, (function(status, download) {
   115           if (Components.isSuccessCode(status))
   116             download.resume();
   117         }).bind(this));
   118   },
   120   cancelClickCallback: function dl_buttonPauseCallback(aDownloadId) {
   121     this._dlmgr.getDownloadByGUID(aDownloadId, (function(status, download) {
   122           if (Components.isSuccessCode(status))
   123             this.cancelDownload(download);
   124         }).bind(this));
   125   },
   127   notificationCanceledCallback: function dl_notifCancelCallback(aId, aDownloadId) {
   128     let notificationId = this._downloadsIdMap[aDownloadId];
   129     if (notificationId && notificationId == aId)
   130       delete this._downloadsIdMap[aDownloadId];
   131   },
   133   createNotification: function dl_createNotif(aDownload, aOptions) {
   134     let notificationId = Notifications.create(aOptions);
   135     this._downloadsIdMap[aDownload.guid] = notificationId;
   136   },
   138   updateNotification: function dl_updateNotif(aDownload, aOptions) {
   139     let notificationId = this._downloadsIdMap[aDownload.guid];
   140     if (notificationId)
   141       Notifications.update(notificationId, aOptions);
   142   },
   144   cancelNotification: function dl_cleanNotif(aDownload) {
   145     Notifications.cancel(this._downloadsIdMap[aDownload.guid]);
   146     delete this._downloadsIdMap[aDownload.guid];
   147   },
   149   // observer for last-pb-context-exited
   150   observe: function dl_observe(aSubject, aTopic, aData) {
   151     let download;
   152     while ((download = this._privateDownloads.pop())) {
   153       try {
   154         let notificationId = aDownload.guid;
   155         Notifications.clear(notificationId);
   156         Downloads.removeNotification(download);
   157       } catch (e) {
   158         dump("Error removing private download: " + e);
   159       }
   160     }
   161   },
   163   QueryInterface: function (aIID) {
   164     if (!aIID.equals(Ci.nsISupports) &&
   165         !aIID.equals(Ci.nsIObserver) &&
   166         !aIID.equals(Ci.nsISupportsWeakReference))
   167       throw Components.results.NS_ERROR_NO_INTERFACE;
   168     return this;
   169   }
   170 };
   172 const PAUSE_BUTTON = {
   173   buttonId: "pause",
   174   title : Strings.browser.GetStringFromName("alertDownloadsPause"),
   175   icon : URI_PAUSE_ICON,
   176   onClicked: function (aId, aCookie) {
   177     Downloads.pauseClickCallback(aCookie);
   178   }
   179 };
   181 const CANCEL_BUTTON = {
   182   buttonId: "cancel",
   183   title : Strings.browser.GetStringFromName("alertDownloadsCancel"),
   184   icon : URI_CANCEL_ICON,
   185   onClicked: function (aId, aCookie) {
   186     Downloads.cancelClickCallback(aCookie);
   187   }
   188 };
   190 const RESUME_BUTTON = {
   191   buttonId: "resume",
   192   title : Strings.browser.GetStringFromName("alertDownloadsResume"),
   193   icon: URI_RESUME_ICON,
   194   onClicked: function (aId, aCookie) {
   195     Downloads.resumeClickCallback(aCookie);
   196   }
   197 };
   199 function DownloadNotifOptions (aDownload, aTitle, aMessage) {
   200   this.icon = URI_GENERIC_ICON_DOWNLOAD;
   201   this.onCancel = function (aId, aCookie) {
   202     Downloads.notificationCanceledCallback(aId, aCookie);
   203   }
   204   this.onClick = function (aId, aCookie) {
   205     Downloads.clickCallback(aCookie);
   206   }
   207   this.title = aTitle;
   208   this.message = aMessage;
   209   this.buttons = null;
   210   this.cookie = aDownload.guid;
   211   this.persistent = true;
   212 }
   214 function DownloadProgressNotifOptions (aDownload, aButtons) {
   215   DownloadNotifOptions.apply(this, [aDownload, aDownload.displayName, aDownload.percentComplete + "%"]);
   216   this.ongoing = true;
   217   this.progress = aDownload.percentComplete;
   218   this.buttons = aButtons;
   219 }
   221 // AlertDownloadProgressListener is used to display progress in the alert notifications.
   222 function AlertDownloadProgressListener() { }
   224 AlertDownloadProgressListener.prototype = {
   225   //////////////////////////////////////////////////////////////////////////////
   226   //// nsIDownloadProgressListener
   227   onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress, aDownload) {
   228     let strings = Strings.browser;
   229     let availableSpace = -1;
   230     try {
   231       // diskSpaceAvailable is not implemented on all systems
   232       let availableSpace = aDownload.targetFile.diskSpaceAvailable;
   233     } catch(ex) { }
   234     let contentLength = aDownload.size;
   235     if (availableSpace > 0 && contentLength > 0 && contentLength > availableSpace) {
   236       Downloads.updateNotification(aDownload, new DownloadNotifOptions(aDownload,
   237                                                                         strings.GetStringFromName("alertDownloadsNoSpace"),
   238                                                                         strings.GetStringFromName("alertDownloadsSize")));
   239       aDownload.cancel();
   240     }
   242     if (aDownload.percentComplete == -1) {
   243       // Undetermined progress is not supported yet
   244       return;
   245     }
   247     Downloads.updateNotification(aDownload, new DownloadProgressNotifOptions(aDownload, [PAUSE_BUTTON, CANCEL_BUTTON]));
   248   },
   250   onDownloadStateChange: function(aState, aDownload) {
   251     let state = aDownload.state;
   252     switch (state) {
   253       case Ci.nsIDownloadManager.DOWNLOAD_QUEUED: {
   254         NativeWindow.toast.show(Strings.browser.GetStringFromName("alertDownloadsToast"), "long");
   255         Downloads.createNotification(aDownload, new DownloadNotifOptions(aDownload,
   256                                                                          Strings.browser.GetStringFromName("alertDownloadsStart2"),
   257                                                                          aDownload.displayName));
   258         break;
   259       }
   260       case Ci.nsIDownloadManager.DOWNLOAD_PAUSED: {
   261         Downloads.updateNotification(aDownload, new DownloadProgressNotifOptions(aDownload, [RESUME_BUTTON, CANCEL_BUTTON]));
   262         break;
   263       }
   264       case Ci.nsIDownloadManager.DOWNLOAD_FAILED:
   265       case Ci.nsIDownloadManager.DOWNLOAD_CANCELED:
   266       case Ci.nsIDownloadManager.DOWNLOAD_BLOCKED_PARENTAL:
   267       case Ci.nsIDownloadManager.DOWNLOAD_DIRTY:
   268       case Ci.nsIDownloadManager.DOWNLOAD_FINISHED: {
   269         Downloads.cancelNotification(aDownload);
   270         if (aDownload.isPrivate) {
   271           let index = Downloads._privateDownloads.indexOf(aDownload);
   272           if (index != -1) {
   273             Downloads._privateDownloads.splice(index, 1);
   274           }
   275         }
   277         if (state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED) {
   278           Downloads.createNotification(aDownload, new DownloadNotifOptions(aDownload,
   279                                                                 Strings.browser.GetStringFromName("alertDownloadsDone2"),
   280                                                                 aDownload.displayName));
   281         }
   282         break;
   283       }
   284     }
   285   },
   287   onStateChange: function(aWebProgress, aRequest, aState, aStatus, aDownload) { },
   288   onSecurityChange: function(aWebProgress, aRequest, aState, aDownload) { },
   290   //////////////////////////////////////////////////////////////////////////////
   291   //// nsISupports
   292   QueryInterface: function (aIID) {
   293     if (!aIID.equals(Ci.nsIDownloadProgressListener) &&
   294         !aIID.equals(Ci.nsISupports))
   295       throw Components.results.NS_ERROR_NO_INTERFACE;
   296     return this;
   297   }
   298 };

mercurial