mobile/android/chrome/content/downloads.js

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

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

mercurial