Bug 934677 - Make the the various download jsm work in b2g r=paolo
authorFabrice Desré <fabrice@mozilla.com>
Tue, 12 Nov 2013 13:17:28 -0800
changeset 154644 9d504773c9df338bc629ad67ee8cd119382b6a2f
parent 154643 9e31c9c04ccfdcb432462036798d662500a83b4a
child 154645 fc568c44bcd402eb0e3ad7a71c0ac6117bfc0d09
push id25651
push userkwierso@gmail.com
push dateWed, 13 Nov 2013 00:40:26 +0000
treeherdermozilla-central@bb502bb5ed5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspaolo
bugs934677
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 934677 - Make the the various download jsm work in b2g r=paolo
toolkit/components/jsdownloads/src/DownloadCore.jsm
toolkit/components/jsdownloads/src/DownloadImport.jsm
toolkit/components/jsdownloads/src/DownloadIntegration.jsm
toolkit/components/jsdownloads/src/DownloadList.jsm
toolkit/components/jsdownloads/src/DownloadStore.jsm
toolkit/components/jsdownloads/src/DownloadUIHelper.jsm
uriloader/exthandler/gonk/nsOSHelperAppService.cpp
--- a/toolkit/components/jsdownloads/src/DownloadCore.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadCore.jsm
@@ -132,22 +132,22 @@ const kProgressUpdateIntervalMs = 400;
 ////////////////////////////////////////////////////////////////////////////////
 //// Download
 
 /**
  * Represents a single download, with associated state and actions.  This object
  * is transient, though it can be included in a DownloadList so that it can be
  * managed by the user interface and persisted across sessions.
  */
-function Download()
+this.Download = function ()
 {
   this._deferSucceeded = Promise.defer();
 }
 
-Download.prototype = {
+this.Download.prototype = {
   /**
    * DownloadSource object associated with this download.
    */
   source: null,
 
   /**
    * DownloadTarget object associated with this download.
    */
@@ -993,19 +993,19 @@ Download.fromSerializable = function (aS
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadSource
 
 /**
  * Represents the source of a download, for example a document or an URI.
  */
-function DownloadSource() { }
+this.DownloadSource = function () {}
 
-DownloadSource.prototype = {
+this.DownloadSource.prototype = {
   /**
    * String containing the URI for the download source.
    */
   url: null,
 
   /**
    * Indicates whether the download originated from a private window.  This
    * determines the context of the network request that is made to retrieve the
@@ -1057,17 +1057,17 @@ DownloadSource.prototype = {
  *                     window.  If omitted, the download is public.
  *          referrer: String containing the referrer URI of the download source.
  *                    Can be omitted or null if no referrer should be sent or
  *                    the download source is not HTTP.
  *        }
  *
  * @return The newly created DownloadSource object.
  */
-DownloadSource.fromSerializable = function (aSerializable) {
+this.DownloadSource.fromSerializable = function (aSerializable) {
   let source = new DownloadSource();
   if (isString(aSerializable)) {
     // Convert String objects to primitive strings at this point.
     source.url = aSerializable.toString();
   } else if (aSerializable instanceof Ci.nsIURI) {
     source.url = aSerializable.spec;
   } else {
     // Convert String objects to primitive strings at this point.
@@ -1088,19 +1088,19 @@ DownloadSource.fromSerializable = functi
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadTarget
 
 /**
  * Represents the target of a download, for example a file in the global
  * downloads directory, or a file in the system temporary directory.
  */
-function DownloadTarget() { }
+this.DownloadTarget = function () {}
 
-DownloadTarget.prototype = {
+this.DownloadTarget.prototype = {
   /**
    * String containing the path of the target file.
    */
   path: null,
 
   /**
    * String containing the path of the ".part" file containing the data
    * downloaded so far, or null to disable the use of a ".part" file to keep
@@ -1136,17 +1136,17 @@ DownloadTarget.prototype = {
  *        object with the following properties:
  *        {
  *          path: String containing the path of the target file.
  *          partFilePath: optional string containing the part file path.
  *        }
  *
  * @return The newly created DownloadTarget object.
  */
-DownloadTarget.fromSerializable = function (aSerializable) {
+this.DownloadTarget.fromSerializable = function (aSerializable) {
   let target = new DownloadTarget();
   if (isString(aSerializable)) {
     // Convert String objects to primitive strings at this point.
     target.path = aSerializable.toString();
   } else if (aSerializable instanceof Ci.nsIFile) {
     // Read the "path" property of nsIFile after checking the object type.
     target.path = aSerializable.path;
   } else {
@@ -1179,17 +1179,17 @@ DownloadTarget.fromSerializable = functi
  *                        download is a network failure or a local file failure,
  *                        based on a set of known values of the result code.
  *                        This is useful when the error is received by a
  *                        component that handles both aspects of the download.
  *          }
  *        The properties object may also contain any of the DownloadError's
  *        because properties, which will be set accordingly in the error object.
  */
-function DownloadError(aProperties)
+this.DownloadError = function (aProperties)
 {
   const NS_ERROR_MODULE_BASE_OFFSET = 0x45;
   const NS_ERROR_MODULE_NETWORK = 6;
   const NS_ERROR_MODULE_FILES = 13;
 
   // Set the error name used by the Error object prototype first.
   this.name = "DownloadError";
   this.result = aProperties.result || Cr.NS_ERROR_FAILURE;
@@ -1226,17 +1226,17 @@ function DownloadError(aProperties)
     this.becauseBlockedByReputationCheck = true;
   } else if (aProperties.becauseBlocked) {
     this.becauseBlocked = true;
   }
 
   this.stack = new Error().stack;
 }
 
-DownloadError.prototype = {
+this.DownloadError.prototype = {
   __proto__: Error.prototype,
 
   /**
    * The result code associated with this error.
    */
   result: false,
 
   /**
@@ -1269,19 +1269,19 @@ DownloadError.prototype = {
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadSaver
 
 /**
  * Template for an object that actually transfers the data for the download.
  */
-function DownloadSaver() { }
+this.DownloadSaver = function () {}
 
-DownloadSaver.prototype = {
+this.DownloadSaver.prototype = {
   /**
    * Download object for raising notifications and reading properties.
    *
    * If the tryToKeepPartialData property of the download object is false, the
    * saver should never try to keep partially downloaded data if the download
    * fails.
    */
   download: null,
@@ -1409,17 +1409,17 @@ DownloadSaver.prototype = {
  *
  * @param aSerializable
  *        Serializable representation of a DownloadSaver object.  If no initial
  *        state information for the saver object is needed, can be a string
  *        representing the class of the download operation, for example "copy".
  *
  * @return The newly created DownloadSaver object.
  */
-DownloadSaver.fromSerializable = function (aSerializable) {
+this.DownloadSaver.fromSerializable = function (aSerializable) {
   let serializable = isString(aSerializable) ? { type: aSerializable }
                                              : aSerializable;
   let saver;
   switch (serializable.type) {
     case "copy":
       saver = DownloadCopySaver.fromSerializable(serializable);
       break;
     case "legacy":
@@ -1432,19 +1432,19 @@ DownloadSaver.fromSerializable = functio
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadCopySaver
 
 /**
  * Saver object that simply copies the entire source file to the target.
  */
-function DownloadCopySaver() { }
+this.DownloadCopySaver = function () {}
 
-DownloadCopySaver.prototype = {
+this.DownloadCopySaver.prototype = {
   __proto__: DownloadSaver.prototype,
 
   /**
    * BackgroundFileSaver object currently handling the download.
    */
   _backgroundFileSaver: null,
 
   /**
@@ -1777,17 +1777,17 @@ DownloadCopySaver.prototype = {
  * Creates a new DownloadCopySaver object, with its initial state derived from
  * its serializable representation.
  *
  * @param aSerializable
  *        Serializable representation of a DownloadCopySaver object.
  *
  * @return The newly created DownloadCopySaver object.
  */
-DownloadCopySaver.fromSerializable = function (aSerializable) {
+this.DownloadCopySaver.fromSerializable = function (aSerializable) {
   let saver = new DownloadCopySaver();
   if ("entityID" in aSerializable) {
     saver.entityID = aSerializable.entityID;
   }
 
   deserializeUnknownProperties(saver, aSerializable, property =>
     property != "entityID" && property != "type");
 
@@ -1797,23 +1797,23 @@ DownloadCopySaver.fromSerializable = fun
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadLegacySaver
 
 /**
  * Saver object that integrates with the legacy nsITransfer interface.
  *
  * For more background on the process, see the DownloadLegacyTransfer object.
  */
-function DownloadLegacySaver()
+this.DownloadLegacySaver = function()
 {
   this.deferExecuted = Promise.defer();
   this.deferCanceled = Promise.defer();
 }
 
-DownloadLegacySaver.prototype = {
+this.DownloadLegacySaver.prototype = {
   __proto__: DownloadSaver.prototype,
 
   /**
    * Save the SHA-256 hash in raw bytes of the downloaded file. This may be
    * null when nsExternalHelperAppService (and thus BackgroundFileSaver) is not
    * invoked.
    */
   _sha256Hash: null,
@@ -2090,11 +2090,11 @@ DownloadLegacySaver.prototype = {
   },
 };
 
 /**
  * Returns a new DownloadLegacySaver object.  This saver type has a
  * deserializable form only when creating a new object in memory, because it
  * cannot be serialized to disk.
  */
-DownloadLegacySaver.fromSerializable = function () {
+this.DownloadLegacySaver.fromSerializable = function () {
   return new DownloadLegacySaver();
 };
--- a/toolkit/components/jsdownloads/src/DownloadImport.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadImport.jsm
@@ -48,17 +48,18 @@ const DOWNLOAD_QUEUED = 5;
 /**
  * Provides an object that has a method to import downloads
  * from the previous SQLite storage format.
  *
  * @param aList   A DownloadList where each successfully
  *                imported download will be added.
  * @param aPath   The path to the database file.
  */
-this.DownloadImport = function(aList, aPath) {
+this.DownloadImport = function (aList, aPath)
+{
   this.list = aList;
   this.path = aPath;
 }
 
 this.DownloadImport.prototype = {
   /**
    * Imports unfinished downloads from the previous SQLite storage
    * format (supporting schemas 7 and up), to the new Download object
--- a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
@@ -34,18 +34,20 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper",
                                   "resource://gre/modules/DownloadUIHelper.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
+#ifdef MOZ_PLACES
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
+#endif
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/commonjs/sdk/core/promise.js");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
@@ -1002,33 +1004,34 @@ this.DownloadObserver = {
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference])
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadHistoryObserver
 
+#ifdef MOZ_PLACES
 /**
  * Registers a Places observer so that operations on download history are
  * reflected on the provided list of downloads.
  *
  * You do not need to keep a reference to this object in order to keep it alive,
  * because the history service already keeps a strong reference to it.
  *
  * @param aList
  *        DownloadList object linked to this observer.
  */
-function DownloadHistoryObserver(aList)
+this.DownloadHistoryObserver = function (aList)
 {
   this._list = aList;
   PlacesUtils.history.addObserver(this, false);
 }
 
-DownloadHistoryObserver.prototype = {
+this.DownloadHistoryObserver.prototype = {
   /**
    * DownloadList object linked to this observer.
    */
   _list: null,
 
   ////////////////////////////////////////////////////////////////////////////
   //// nsISupports
 
@@ -1048,16 +1051,22 @@ DownloadHistoryObserver.prototype = {
 
   onTitleChanged: function () {},
   onBeginUpdateBatch: function () {},
   onEndUpdateBatch: function () {},
   onVisit: function () {},
   onPageChanged: function () {},
   onDeleteVisits: function () {},
 };
+#else
+/**
+ * Empty implementation when we have no Places support, for example on B2G.
+ */
+this.DownloadHistoryObserver = function (aList) {}
+#endif
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadAutoSaveView
 
 /**
  * This view can be added to a DownloadList object to trigger a save operation
  * in the given DownloadStore object when a relevant change occurs.  You should
  * call the "initialize" method in order to register the view and load the
@@ -1066,23 +1075,24 @@ DownloadHistoryObserver.prototype = {
  * You do not need to keep a reference to this object in order to keep it alive,
  * because the DownloadList object already keeps a strong reference to it.
  *
  * @param aList
  *        The DownloadList object on which the view should be registered.
  * @param aStore
  *        The DownloadStore object used for saving.
  */
-function DownloadAutoSaveView(aList, aStore) {
+this.DownloadAutoSaveView = function (aList, aStore)
+{
   this._list = aList;
   this._store = aStore;
   this._downloadsMap = new Map();
 }
 
-DownloadAutoSaveView.prototype = {
+this.DownloadAutoSaveView.prototype = {
   /**
    * DownloadList object linked to this view.
    */
   _list: null,
 
   /**
    * The DownloadStore object used for saving.
    */
--- a/toolkit/components/jsdownloads/src/DownloadList.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadList.jsm
@@ -43,22 +43,23 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadList
 
 /**
  * Represents a collection of Download objects that can be viewed and managed by
  * the user interface, and persisted across sessions.
  */
-function DownloadList() {
+this.DownloadList = function ()
+{
   this._downloads = [];
   this._views = new Set();
 }
 
-DownloadList.prototype = {
+this.DownloadList.prototype = {
   /**
    * Array of Download objects currently in the list.
    */
   _downloads: null,
 
   /**
    * Retrieves a snapshot of the downloads that are currently in the list.  The
    * returned array does not change when downloads are added or removed, though
@@ -264,26 +265,26 @@ DownloadList.prototype = {
  * underlying lists, based on their "source.isPrivate" property.  Views on this
  * list will receive notifications for both public and private downloads.
  *
  * @param aPublicList
  *        Underlying DownloadList containing public downloads.
  * @param aPrivateList
  *        Underlying DownloadList containing private downloads.
  */
-function DownloadCombinedList(aPublicList, aPrivateList)
+this.DownloadCombinedList = function (aPublicList, aPrivateList)
 {
   DownloadList.call(this);
   this._publicList = aPublicList;
   this._privateList = aPrivateList;
   aPublicList.addView(this).then(null, Cu.reportError);
   aPrivateList.addView(this).then(null, Cu.reportError);
 }
 
-DownloadCombinedList.prototype = {
+this.DownloadCombinedList.prototype = {
   __proto__: DownloadList.prototype,
 
   /**
    * Underlying DownloadList containing public downloads.
    */
   _publicList: null,
 
   /**
@@ -366,22 +367,23 @@ DownloadCombinedList.prototype = {
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadSummary
 
 /**
  * Provides an aggregated view on the contents of a DownloadList.
  */
-function DownloadSummary() {
+this.DownloadSummary = function ()
+{
   this._downloads = [];
   this._views = new Set();
 }
 
-DownloadSummary.prototype = {
+this.DownloadSummary.prototype = {
   /**
    * Array of Download objects that are currently part of the summary.
    */
   _downloads: null,
 
   /**
    * Underlying DownloadList whose contents should be summarized.
    */
--- a/toolkit/components/jsdownloads/src/DownloadStore.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadStore.jsm
@@ -66,23 +66,23 @@ XPCOMUtils.defineLazyGetter(this, "gText
  * Handles serialization of Download objects and persistence into a file, so
  * that the state of downloads can be restored across sessions.
  *
  * @param aList
  *        DownloadList object to be populated or serialized.
  * @param aPath
  *        String containing the file path where data should be saved.
  */
-function DownloadStore(aList, aPath)
+this.DownloadStore = function (aList, aPath)
 {
   this.list = aList;
   this.path = aPath;
 }
 
-DownloadStore.prototype = {
+this.DownloadStore.prototype = {
   /**
    * DownloadList object to be populated or serialized.
    */
   list: null,
 
   /**
    * String containing the file path where data should be saved.
    */
--- a/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm
@@ -101,22 +101,27 @@ XPCOMUtils.defineLazyGetter(DownloadUIHe
 
 /**
  * Allows displaying prompts related to downloads.
  *
  * @param aParent
  *        The nsIDOMWindow to which prompts should be attached, or null to
  *        attach prompts to the most recently active window.
  */
-function DownloadPrompter(aParent)
+this.DownloadPrompter = function (aParent)
 {
+#ifdef MOZ_WIDGET_GONK
+  // On B2G there is no prompter implementation.
+  this._prompter = null;
+#else
   this._prompter = Services.ww.getNewPrompter(aParent);
+#endif
 }
 
-DownloadPrompter.prototype = {
+this.DownloadPrompter.prototype = {
   /**
    * Constants with the different type of prompts.
    */
   ON_QUIT: "prompt-on-quit",
   ON_OFFLINE: "prompt-on-offline",
   ON_LEAVE_PRIVATE_BROWSING: "prompt-on-leave-private-browsing",
 
   /**
@@ -136,16 +141,21 @@ DownloadPrompter.prototype = {
    * @resolves Boolean indicating whether the launch operation can continue.
    * @rejects JavaScript exception.
    */
   confirmLaunchExecutable: function (aPath)
   {
     const kPrefAlertOnEXEOpen = "browser.download.manager.alertOnEXEOpen";
 
     try {
+      // Always launch in case we have no prompter implementation.
+      if (!this._prompter) {
+        return Promise.resolve(true);
+      }
+
       try {
         if (!Services.prefs.getBoolPref(kPrefAlertOnEXEOpen)) {
           return Promise.resolve(true);
         }
       } catch (ex) {
         // If the preference does not exist, continue with the prompt.
       }
 
@@ -173,24 +183,25 @@ DownloadPrompter.prototype = {
    * Displays a warning message box that informs that there are active
    * downloads, and asks whether the user wants to cancel them or not.
    *
    * @param aDownloadsCount
    *        The current downloads count.
    * @param aPromptType
    *        The type of prompt notification depending on the observer.
    *
-   * @return True to cancel the downloads and continue, false to abort the
+   * @return False to cancel the downloads and continue, true to abort the
    *         operation.
    */
   confirmCancelDownloads: function DP_confirmCancelDownload(aDownloadsCount,
                                                             aPromptType)
   {
-    // If there are no active downloads, then do nothing.
-    if (aDownloadsCount <= 0) {
+    // Always continue in case we have no prompter implementation, or if there
+    // are no active downloads.
+    if (!this._prompter || aDownloadsCount <= 0) {
       return false;
     }
 
     let s = DownloadUIHelper.strings;
     let buttonFlags = (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
                       (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1);
     let okButton = aDownloadsCount > 1 ? s.cancelDownloadsOKTextMultiple(aDownloadsCount)
                                        : s.cancelDownloadsOKText;
--- a/uriloader/exthandler/gonk/nsOSHelperAppService.cpp
+++ b/uriloader/exthandler/gonk/nsOSHelperAppService.cpp
@@ -12,19 +12,20 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "nsOSHelperAppService.h"
 #include "nsMIMEInfoImpl.h"
 
-// Simplest nsIMIMEInfo implementation possible.
-// We don't need it to actually do anything.
 class nsGonkMIMEInfo : public nsMIMEInfoImpl {
+public:
+    nsGonkMIMEInfo(const nsACString& aMIMEType) : nsMIMEInfoImpl(aMIMEType) { }
+
 protected:
     virtual NS_HIDDEN_(nsresult) LoadUriInternal(nsIURI *aURI) {
         return NS_ERROR_NOT_IMPLEMENTED;
     }
 };
 
 nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService()
 {
@@ -35,19 +36,19 @@ nsOSHelperAppService::~nsOSHelperAppServ
 }
 
 already_AddRefed<nsIMIMEInfo>
 nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
                                         const nsACString& aFileExt,
                                         bool* aFound)
 {
     *aFound = false;
-    // Even if we return false for aFound, we need to return a non-null
-    // nsIMIMEInfo implementation to prevent a crash in the caller.
-    nsRefPtr<nsGonkMIMEInfo> mimeInfo = new nsGonkMIMEInfo();
+    // Even if we return false for aFound, we need to return a working
+    // nsIMIMEInfo implementation that will be used by the caller.
+    nsRefPtr<nsGonkMIMEInfo> mimeInfo = new nsGonkMIMEInfo(aMIMEType);
     return mimeInfo.forget();
 }
 
 nsresult
 nsOSHelperAppService::OSProtocolHandlerExists(const char* aScheme,
                                               bool* aExists)
 {
     *aExists = false;