Bug 1334975 - Get rid of nsIFilePicker.show() use in gecko, r=ochameau draft
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 31 Jan 2017 11:33:42 +0100
changeset 468397 3e9ede1e615020699949edfa21dab310e2d66cfc
parent 468392 9c06e744b1befb3a2e2fdac7414ce18220774a1d
child 543937 dc996158fbbc888e068f9510797aaf0508f3b093
push id43453
push useramarchesini@mozilla.com
push dateTue, 31 Jan 2017 10:34:17 +0000
reviewersochameau
bugs1334975
milestone54.0a1
Bug 1334975 - Get rid of nsIFilePicker.show() use in gecko, r=ochameau MozReview-Commit-ID: 9JYILThpPho
devtools/client/aboutdebugging/components/addons/controls.js
devtools/client/aboutdebugging/test/head.js
devtools/client/canvasdebugger/snapshotslist.js
devtools/client/jsonview/main.js
devtools/client/jsonview/utils.js
devtools/client/netmonitor/har/har-exporter.js
devtools/client/netmonitor/har/har-utils.js
devtools/client/performance/performance-view.js
devtools/client/webide/content/newapp.js
devtools/client/webide/content/simulator.js
devtools/client/webide/modules/project-list.js
devtools/client/webide/modules/utils.js
layout/tools/layout-debug/ui/content/layoutdebug.js
security/manager/pki/resources/content/certManager.js
testing/specialpowers/content/MockFilePicker.jsm
toolkit/components/apppicker/content/appPicker.js
toolkit/components/printing/content/printdialog.js
toolkit/mozapps/downloads/nsHelperAppDlg.js
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/content/setting.xml
toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js
toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js
toolkit/mozapps/handling/content/dialog.js
widget/nsIFilePicker.idl
--- a/devtools/client/aboutdebugging/components/addons/controls.js
+++ b/devtools/client/aboutdebugging/components/addons/controls.js
@@ -42,32 +42,33 @@ module.exports = createClass({
   },
 
   loadAddonFromFile() {
     this.setState({ installError: null });
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     fp.init(window,
       Strings.GetStringFromName("selectAddonFromFile2"),
       Ci.nsIFilePicker.modeOpen);
-    let res = fp.show();
-    if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {
-      return;
-    }
-    let file = fp.file;
-    // AddonManager.installTemporaryAddon accepts either
-    // addon directory or final xpi file.
-    if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) {
-      file = file.parent;
-    }
+    fp.open(res => {
+      if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {
+        return;
+      }
+      let file = fp.file;
+      // AddonManager.installTemporaryAddon accepts either
+      // addon directory or final xpi file.
+      if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) {
+        file = file.parent;
+      }
 
-    AddonManager.installTemporaryAddon(file)
-      .catch(e => {
-        console.error(e);
-        this.setState({ installError: e.message });
-      });
+      AddonManager.installTemporaryAddon(file)
+        .catch(e => {
+          console.error(e);
+          this.setState({ installError: e.message });
+        });
+    });
   },
 
   render() {
     let { debugDisabled } = this.props;
 
     return dom.div({ className: "addons-top" },
       dom.div({ className: "addons-controls" },
         dom.div({ className: "addons-options toggle-container-with-text" },
--- a/devtools/client/aboutdebugging/test/head.js
+++ b/devtools/client/aboutdebugging/test/head.js
@@ -108,17 +108,17 @@ function getServiceWorkerList(document) 
 function getTabList(document) {
   return document.querySelector("#tabs .target-list") ||
     document.querySelector("#tabs.targets");
 }
 
 function* installAddon({document, path, name, isWebExtension}) {
   // Mock the file picker to select a test addon
   let MockFilePicker = SpecialPowers.MockFilePicker;
-  MockFilePicker.init(null);
+  MockFilePicker.init(window);
   let file = getSupportsFile(path);
   MockFilePicker.returnFiles = [file.file];
 
   let addonList = getAddonList(document);
   let addonListMutation = waitForMutation(addonList, { childList: true });
 
   let onAddonInstalled;
 
--- a/devtools/client/canvasdebugger/snapshotslist.js
+++ b/devtools/client/canvasdebugger/snapshotslist.js
@@ -352,48 +352,50 @@ var SnapshotsListView = Heritage.extend(
    * The click listener for the "import" button in this container.
    */
   _onImportButtonClick: function () {
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     fp.init(window, L10N.getStr("snapshotsList.saveDialogTitle"), Ci.nsIFilePicker.modeOpen);
     fp.appendFilter(L10N.getStr("snapshotsList.saveDialogJSONFilter"), "*.json");
     fp.appendFilter(L10N.getStr("snapshotsList.saveDialogAllFilter"), "*.*");
 
-    if (fp.show() != Ci.nsIFilePicker.returnOK) {
-      return;
-    }
-
-    let channel = NetUtil.newChannel({
-      uri: NetUtil.newURI(fp.file), loadUsingSystemPrincipal: true});
-    channel.contentType = "text/plain";
-
-    NetUtil.asyncFetch(channel, (inputStream, status) => {
-      if (!Components.isSuccessCode(status)) {
-        console.error("Could not import recorded animation frame snapshot file.");
-        return;
-      }
-      try {
-        let string = NetUtil.readInputStreamToString(inputStream, inputStream.available());
-        var data = JSON.parse(string);
-      } catch (e) {
-        console.error("Could not read animation frame snapshot file.");
-        return;
-      }
-      if (data.fileType != CALLS_LIST_SERIALIZER_IDENTIFIER) {
-        console.error("Unrecognized animation frame snapshot file.");
+    fp.open(rv => {
+      if (rv != Ci.nsIFilePicker.returnOK) {
         return;
       }
 
-      // Add a `isLoadedFromDisk` flag on everything to avoid sending invalid
-      // requests to the backend, since we're not dealing with actors anymore.
-      let snapshotItem = this.addSnapshot();
-      snapshotItem.isLoadedFromDisk = true;
-      data.calls.forEach(e => e.isLoadedFromDisk = true);
+      let channel = NetUtil.newChannel({
+        uri: NetUtil.newURI(fp.file), loadUsingSystemPrincipal: true});
+      channel.contentType = "text/plain";
 
-      this.customizeSnapshot(snapshotItem, data.calls, data);
+      NetUtil.asyncFetch(channel, (inputStream, status) => {
+        if (!Components.isSuccessCode(status)) {
+          console.error("Could not import recorded animation frame snapshot file.");
+          return;
+        }
+        try {
+          let string = NetUtil.readInputStreamToString(inputStream, inputStream.available());
+          var data = JSON.parse(string);
+        } catch (e) {
+          console.error("Could not read animation frame snapshot file.");
+          return;
+        }
+        if (data.fileType != CALLS_LIST_SERIALIZER_IDENTIFIER) {
+          console.error("Unrecognized animation frame snapshot file.");
+          return;
+        }
+
+        // Add a `isLoadedFromDisk` flag on everything to avoid sending invalid
+        // requests to the backend, since we're not dealing with actors anymore.
+        let snapshotItem = this.addSnapshot();
+        snapshotItem.isLoadedFromDisk = true;
+        data.calls.forEach(e => e.isLoadedFromDisk = true);
+
+        this.customizeSnapshot(snapshotItem, data.calls, data);
+      });
     });
   },
 
   /**
    * The click listener for the "save" button of each item in this container.
    */
   _onSaveButtonClick: function (e) {
     let snapshotItem = this.getItemForElement(e.target);
--- a/devtools/client/jsonview/main.js
+++ b/devtools/client/jsonview/main.js
@@ -45,18 +45,18 @@ var JsonView = {
 
   // Message handlers for events from child processes
 
   /**
    * Save JSON to a file needs to be implemented here
    * in the parent process.
    */
   onSave: function (message) {
-    let value = message.data;
-    let file = JsonViewUtils.getTargetFile();
-    if (file) {
-      JsonViewUtils.saveToFile(file, value);
-    }
+    JsonViewUtils.getTargetFile(file => {
+      if (file) {
+        JsonViewUtils.saveToFile(file, message.data);
+      }
+    });
   }
 };
 
 // Exports from this module
 module.exports.JsonView = JsonView;
--- a/devtools/client/jsonview/utils.js
+++ b/devtools/client/jsonview/utils.js
@@ -18,31 +18,34 @@ const OPEN_FLAGS = {
   TRUNCATE: parseInt("0x20", 16),
   EXCL: parseInt("0x80", 16)
 };
 
 /**
  * Open File Save As dialog and let the user to pick proper file location.
  */
 exports.getTargetFile = function () {
-  let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+  return new Promise(resolve => {
+    let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
 
-  let win = getMostRecentBrowserWindow();
-  fp.init(win, null, Ci.nsIFilePicker.modeSave);
-  fp.appendFilter("JSON Files", "*.json; *.jsonp;");
-  fp.appendFilters(Ci.nsIFilePicker.filterText);
-  fp.appendFilters(Ci.nsIFilePicker.filterAll);
-  fp.filterIndex = 0;
+    let win = getMostRecentBrowserWindow();
+    fp.init(win, null, Ci.nsIFilePicker.modeSave);
+    fp.appendFilter("JSON Files", "*.json; *.jsonp;");
+    fp.appendFilters(Ci.nsIFilePicker.filterText);
+    fp.appendFilters(Ci.nsIFilePicker.filterAll);
+    fp.filterIndex = 0;
 
-  let rv = fp.show();
-  if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
-    return fp.file;
-  }
-
-  return null;
+    fp.open(rv => {
+      if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
+        resolve(fp.file);
+      } else {
+        resolve(null);
+      }
+    });
+  });
 };
 
 /**
  * Save JSON to a file
  */
 exports.saveToFile = function (file, jsonString) {
   let foStream = Cc["@mozilla.org/network/file-output-stream;1"]
     .createInstance(Ci.nsIFileOutputStream);
--- a/devtools/client/netmonitor/har/har-exporter.js
+++ b/devtools/client/netmonitor/har/har-exporter.js
@@ -75,32 +75,32 @@ const HarExporter = {
     // Set default options related to save operation.
     options.defaultFileName = Services.prefs.getCharPref(
       "devtools.netmonitor.har.defaultFileName");
     options.compress = Services.prefs.getBoolPref(
       "devtools.netmonitor.har.compress");
 
     // Get target file for exported data. Bail out, if the user
     // presses cancel.
-    let file = HarUtils.getTargetFile(options.defaultFileName,
-      options.jsonp, options.compress);
+    return HarUtils.getTargetFile(options.defaultFileName, options.jsonp,
+      options.compress).then(file => {
+        if (!file) {
+          return resolve();
+        }
 
-    if (!file) {
-      return resolve();
-    }
+        trace.log("HarExporter.save; " + options.defaultFileName, options);
 
-    trace.log("HarExporter.save; " + options.defaultFileName, options);
-
-    return this.fetchHarData(options).then(jsonString => {
-      if (!HarUtils.saveToFile(file, jsonString, options.compress)) {
-        let msg = "Failed to save HAR file at: " + options.defaultFileName;
-        console.error(msg);
-      }
-      return jsonString;
-    });
+        return this.fetchHarData(options).then(jsonString => {
+          if (!HarUtils.saveToFile(file, jsonString, options.compress)) {
+            let msg = "Failed to save HAR file at: " + options.defaultFileName;
+            console.error(msg);
+          }
+          return jsonString;
+        });
+      });
   },
 
   /**
    * Copy HAR string into the clipboard.
    *
    * @param Object options
    *        Configuration object, see save() for detailed description.
    */
--- a/devtools/client/netmonitor/har/har-utils.js
+++ b/devtools/client/netmonitor/har/har-utils.js
@@ -51,34 +51,35 @@ function formatDate(date) {
 /**
  * Helper API for HAR export features.
  */
 var HarUtils = {
   /**
    * Open File Save As dialog and let the user pick the proper file
    * location for generated HAR log.
    */
-  getTargetFile: function (fileName, jsonp, compress) {
+  getTargetFile: function (fileName, jsonp, compress, cb) {
     let browser = getMostRecentBrowserWindow();
 
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
     fp.init(browser, null, nsIFilePicker.modeSave);
     fp.appendFilter(
       "HTTP Archive Files", "*.har; *.harp; *.json; *.jsonp; *.zip");
     fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText);
     fp.filterIndex = 1;
 
     fp.defaultString = this.getHarFileName(fileName, jsonp, compress);
 
-    let rv = fp.show();
-    if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
-      return fp.file;
-    }
-
-    return null;
+    fp.open(rv => {
+      if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
+        cb(fp.file);
+      } else {
+        cb(null);
+      }
+    });
   },
 
   getHarFileName: function (defaultFileName, jsonp, compress) {
     let extension = jsonp ? ".harp" : ".har";
 
     let now = new Date();
     let name = defaultFileName.replace(/%date/g, formatDate(now));
     name = name.replace(/\:/gm, "-", "");
--- a/devtools/client/performance/performance-view.js
+++ b/devtools/client/performance/performance-view.js
@@ -354,19 +354,21 @@ var PerformanceView = {
    */
   _onImportButtonClick: function (e) {
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     fp.init(window, L10N.getStr("recordingsList.importDialogTitle"),
             Ci.nsIFilePicker.modeOpen);
     fp.appendFilter(L10N.getStr("recordingsList.saveDialogJSONFilter"), "*.json");
     fp.appendFilter(L10N.getStr("recordingsList.saveDialogAllFilter"), "*.*");
 
-    if (fp.show() == Ci.nsIFilePicker.returnOK) {
-      this.emit(EVENTS.UI_IMPORT_RECORDING, fp.file);
-    }
+    fp.open(rv => {
+      if (rv == Ci.nsIFilePicker.returnOK) {
+        this.emit(EVENTS.UI_IMPORT_RECORDING, fp.file);
+      }
+    });
   },
 
   /**
    * Fired when a recording is selected. Used to toggle the profiler view state.
    */
   _onRecordingSelected: function (_, recording) {
     if (!recording) {
       this.setState("empty");
--- a/devtools/client/webide/content/newapp.js
+++ b/devtools/client/webide/content/newapp.js
@@ -105,70 +105,73 @@ function doOK() {
   }
 
   let templatelistNode = document.querySelector("#templatelist");
   if (templatelistNode.selectedIndex < 0) {
     console.error("No template selected");
     return false;
   }
 
-  let folder;
-
   /* Chrome mochitest support */
-  let testOptions = window.arguments[0].testOptions;
-  if (testOptions) {
-    folder = testOptions.folder;
-  } else {
-    let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
-    fp.init(window, "Select directory where to create app directory", Ci.nsIFilePicker.modeGetFolder);
-    let res = fp.show();
-    if (res == Ci.nsIFilePicker.returnCancel) {
-      console.error("No directory selected");
-      return false;
+  let promise = new Promise((resolve, reject) => {
+    let testOptions = window.arguments[0].testOptions;
+    if (testOptions) {
+      resolve(testOptions.folder);
+    } else {
+      let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+      fp.init(window, "Select directory where to create app directory", Ci.nsIFilePicker.modeGetFolder);
+      fp.open(res => {
+        if (res == Ci.nsIFilePicker.returnCancel) {
+          console.error("No directory selected");
+          reject(null);
+        } else {
+          resolve(fp.file);
+        }
+      });
     }
-    folder = fp.file;
-  }
-
-  // Create subfolder with fs-friendly name of project
-  let subfolder = projectName.replace(/[\\/:*?"<>|]/g, "").toLowerCase();
-  let win = Services.wm.getMostRecentWindow("devtools:webide");
-  folder.append(subfolder);
-
-  try {
-    folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
-  } catch (e) {
-    win.UI.reportError("error_folderCreationFailed");
-    window.close();
-    return false;
-  }
-
-  // Download boilerplate zip
-  let template = gTemplateList[templatelistNode.selectedIndex];
-  let source = template.file;
-  let target = folder.clone();
-  target.append(subfolder + ".zip");
+  });
 
   let bail = (e) => {
     console.error(e);
     window.close();
   };
 
-  Downloads.fetch(source, target).then(() => {
-    ZipUtils.extractFiles(target, folder);
-    target.remove(false);
-    AppProjects.addPackaged(folder).then((project) => {
-      window.arguments[0].location = project.location;
-      AppManager.validateAndUpdateProject(project).then(() => {
-        if (project.manifest) {
-          project.manifest.name = projectName;
-          AppManager.writeManifest(project).then(() => {
-            AppManager.validateAndUpdateProject(project).then(
-              () => {window.close();}, bail);
-          }, bail);
-        } else {
-          bail("Manifest not found");
-        }
+  promise.then(folder => {
+    // Create subfolder with fs-friendly name of project
+    let subfolder = projectName.replace(/[\\/:*?"<>|]/g, "").toLowerCase();
+    let win = Services.wm.getMostRecentWindow("devtools:webide");
+    folder.append(subfolder);
+
+    try {
+      folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
+    } catch (e) {
+      win.UI.reportError("error_folderCreationFailed");
+      window.close();
+      return;
+    }
+
+    // Download boilerplate zip
+    let template = gTemplateList[templatelistNode.selectedIndex];
+    let source = template.file;
+    let target = folder.clone();
+    target.append(subfolder + ".zip");
+    Downloads.fetch(source, target).then(() => {
+      ZipUtils.extractFiles(target, folder);
+      target.remove(false);
+      AppProjects.addPackaged(folder).then((project) => {
+        window.arguments[0].location = project.location;
+        AppManager.validateAndUpdateProject(project).then(() => {
+          if (project.manifest) {
+            project.manifest.name = projectName;
+            AppManager.writeManifest(project).then(() => {
+              AppManager.validateAndUpdateProject(project).then(
+                () => {window.close();}, bail);
+            }, bail);
+          } else {
+            bail("Manifest not found");
+          }
+        }, bail);
       }, bail);
     }, bail);
   }, bail);
 
   return false;
 }
--- a/devtools/client/webide/content/simulator.js
+++ b/devtools/client/webide/content/simulator.js
@@ -284,39 +284,41 @@ var SimulatorEditor = {
     let input = event.target;
     switch (input.name) {
       case "name":
         simulator.options.name = input.value;
         break;
       case "version":
         switch (input.value) {
           case "pick":
-            let file = utils.getCustomBinary(window);
-            if (file) {
-              this.version = file.path;
-            }
-            // Whatever happens, don't stay on the "pick" option.
-            this.updateVersionSelector();
+            utils.getCustomBinary(window).then(file => {
+              if (file) {
+                this.version = file.path;
+              }
+              // Whatever happens, don't stay on the "pick" option.
+              this.updateVersionSelector();
+            });
             break;
           case "custom":
             this.version = input[input.selectedIndex].textContent;
             break;
           default:
             this.version = input.value;
         }
         break;
       case "profile":
         switch (input.value) {
           case "pick":
-            let directory = utils.getCustomProfile(window);
-            if (directory) {
-              this.profile = directory.path;
-            }
-            // Whatever happens, don't stay on the "pick" option.
-            this.updateProfileSelector();
+            utils.getCustomProfile(window).then(directory => {
+              if (directory) {
+                this.profile = directory.path;
+              }
+              // Whatever happens, don't stay on the "pick" option.
+              this.updateProfileSelector();
+            });
             break;
           case "custom":
             this.profile = input[input.selectedIndex].textContent;
             break;
           default:
             this.profile = input.value;
         }
         break;
--- a/devtools/client/webide/modules/project-list.js
+++ b/devtools/client/webide/modules/project-list.js
@@ -87,17 +87,17 @@ ProjectList.prototype = {
       self._telemetry.actionOccurred("webideNewProject");
     }), "creating new app");
   },
 
   importPackagedApp: function (location) {
     let parentWindow = this._parentWindow;
     let UI = this._UI;
     return UI.busyUntil(Task.spawn(function* () {
-      let directory = utils.getPackagedDirectory(parentWindow, location);
+      let directory = yield utils.getPackagedDirectory(parentWindow, location);
 
       if (!directory) {
         // User cancelled directory selection
         return;
       }
 
       yield UI.importAndSelectApp(directory);
     }), "importing packaged app");
--- a/devtools/client/webide/modules/utils.js
+++ b/devtools/client/webide/modules/utils.js
@@ -10,25 +10,30 @@ const Strings = Services.strings.createB
 function doesFileExist(location) {
   let file = new FileUtils.File(location);
   return file.exists();
 }
 exports.doesFileExist = doesFileExist;
 
 function _getFile(location, ...pickerParams) {
   if (location) {
-    return new FileUtils.File(location);
+    return Promise.resolve(new FileUtils.File(location));
   }
   let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
   fp.init(...pickerParams);
-  let res = fp.show();
-  if (res == Ci.nsIFilePicker.returnCancel) {
-    return null;
-  }
-  return fp.file;
+
+  return new Promise(resolve => {
+    fp.open(res => {
+      if (res == Ci.nsIFilePicker.returnCancel) {
+        resolve(null);
+      } else {
+        resolve(fp.file);
+      }
+    });
+  });
 }
 
 function getCustomBinary(window, location) {
   return _getFile(location, window, Strings.GetStringFromName("selectCustomBinary_title"), Ci.nsIFilePicker.modeOpen);
 }
 exports.getCustomBinary = getCustomBinary;
 
 function getCustomProfile(window, location) {
--- a/layout/tools/layout-debug/ui/content/layoutdebug.js
+++ b/layout/tools/layout-debug/ui/content/layoutdebug.js
@@ -162,20 +162,22 @@ function toggle(menuitem)
 
 function openFile()
 {
   var nsIFilePicker = Components.interfaces.nsIFilePicker;
   var fp = Components.classes["@mozilla.org/filepicker;1"]
         .createInstance(nsIFilePicker);
   fp.init(window, "Select a File", nsIFilePicker.modeOpen);
   fp.appendFilters(nsIFilePicker.filterHTML | nsIFilePicker.filterAll);
-  if (fp.show() == nsIFilePicker.returnOK && fp.fileURL.spec &&
-                fp.fileURL.spec.length > 0) {
-    gBrowser.loadURI(fp.fileURL.spec);
-  }
+  fp.open(rv => {
+    if (rv == nsIFilePicker.returnOK && fp.fileURL.spec &&
+        fp.fileURL.spec.length > 0) {
+      gBrowser.loadURI(fp.fileURL.spec);
+    }
+  });
 }
 const LDB_RDFNS = "http://mozilla.org/newlayout/LDB-rdf#";
 const NC_RDFNS = "http://home.netscape.com/NC-rdf#";
 
 function RTestIndexList() {
   this.init();
 }
 
@@ -259,27 +261,29 @@ RTestIndexList.prototype = {
 
       var fp = Components.classes[NS_FILEPICKER_CONTRACTID].
                    createInstance(nsIFilePicker);
 
       // XXX l10n (but this is just for 5 developers, so no problem)
       fp.init(window, "New Regression Test List", nsIFilePicker.modeOpen);
       fp.appendFilters(nsIFilePicker.filterAll);
       fp.defaultString = "rtest.lst";
-      if (fp.show() != nsIFilePicker.returnOK)
-        return;
+      fp.open(rv => {
+        if (rv != nsIFilePicker.returnOK) {
+          return;
+        }
 
-      var file = fp.file.persistentDescriptor;
-      var resource = this.mRDFService.GetResource(file);
-      var literal = this.mRDFService.GetLiteral(file);
-      this.mDataSource.Assert(this.mLDB_Root, this.mNC_Child, resource, true);
-      this.mDataSource.Assert(resource, this.mNC_Name, literal, true);
+        var file = fp.file.persistentDescriptor;
+        var resource = this.mRDFService.GetResource(file);
+        var literal = this.mRDFService.GetLiteral(file);
+        this.mDataSource.Assert(this.mLDB_Root, this.mNC_Child, resource, true);
+        this.mDataSource.Assert(resource, this.mNC_Name, literal, true);
 
-      this.save();
-
+        this.save();
+      });
     },
 
   remove : function(file)
     {
       var resource = this.mRDFService.GetResource(file);
       var literal = this.mRDFService.GetLiteral(file);
       this.mDataSource.Unassert(this.mLDB_Root, this.mNC_Child, resource);
       this.mDataSource.Unassert(resource, this.mNC_Name, literal);
--- a/security/manager/pki/resources/content/certManager.js
+++ b/security/manager/pki/resources/content/certManager.js
@@ -327,21 +327,22 @@ function backupCerts()
   var bundle = document.getElementById("pippki_bundle");
   var fp = Components.classes[nsFilePicker].createInstance(nsIFilePicker);
   fp.init(window,
           bundle.getString("chooseP12BackupFileDialog"),
           nsIFilePicker.modeSave);
   fp.appendFilter(bundle.getString("file_browse_PKCS12_spec"),
                   "*.p12");
   fp.appendFilters(nsIFilePicker.filterAll);
-  var rv = fp.show();
-  if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
-    certdb.exportPKCS12File(null, fp.file, selected_certs.length,
-                            selected_certs);
-  }
+  fp.open(rv => {
+    if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
+      certdb.exportPKCS12File(null, fp.file, selected_certs.length,
+                              selected_certs);
+    }
+  });
 }
 
 function backupAllCerts()
 {
   // Select all rows, then call doBackup()
   var items = userTreeView.selection.selectAll();
   backupCerts();
 }
@@ -363,17 +364,21 @@ function restoreCerts()
   fp.init(window,
           bundle.getString("chooseP12RestoreFileDialog2"),
           nsIFilePicker.modeOpen);
   fp.appendFilter(bundle.getString("file_browse_PKCS12_spec"),
                   "*.p12; *.pfx");
   fp.appendFilter(bundle.getString("file_browse_Certificate_spec"),
                   gCertFileTypes);
   fp.appendFilters(nsIFilePicker.filterAll);
-  if (fp.show() == nsIFilePicker.returnOK) {
+  fp.open(rv => {
+    if (rv != nsIFilePicker.returnOK) {
+      return;
+    }
+
     // If this is an X509 user certificate, import it as one.
 
     var isX509FileType = false;
     var fileTypesList = gCertFileTypes.slice(1).split("; *");
     for (var type of fileTypesList) {
       if (fp.file.path.endsWith(type)) {
         isX509FileType = true;
         break;
@@ -403,17 +408,17 @@ function restoreCerts()
     }
 
     var certcache = certdb.getCerts();
     userTreeView.loadCertsFromCache(certcache, nsIX509Cert.USER_CERT);
     userTreeView.selection.clearSelection();
     caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT);
     caTreeView.selection.clearSelection();
     enableBackupAllButton();
-  }
+  });
 }
 
 function exportCerts()
 {
   getSelectedCerts();
 
   for (let cert of selected_certs) {
     exportToFile(window, cert);
@@ -481,21 +486,23 @@ function addCACerts()
   var bundle = document.getElementById("pippki_bundle");
   var fp = Components.classes[nsFilePicker].createInstance(nsIFilePicker);
   fp.init(window,
           bundle.getString("importCACertsPrompt"),
           nsIFilePicker.modeOpen);
   fp.appendFilter(bundle.getString("file_browse_Certificate_spec"),
                   gCertFileTypes);
   fp.appendFilters(nsIFilePicker.filterAll);
-  if (fp.show() == nsIFilePicker.returnOK) {
-    certdb.importCertsFromFile(fp.file, nsIX509Cert.CA_CERT);
-    caTreeView.loadCerts(nsIX509Cert.CA_CERT);
-    caTreeView.selection.clearSelection();
-  }
+  fp.open(rv => {
+    if (rv == nsIFilePicker.returnOK) {
+      certdb.importCertsFromFile(fp.file, nsIX509Cert.CA_CERT);
+      caTreeView.loadCerts(nsIX509Cert.CA_CERT);
+      caTreeView.selection.clearSelection();
+    }
+  });
 }
 
 function onSmartCardChange()
 {
   var certcache = certdb.getCerts();
   // We've change the state of the smart cards inserted or removed
   // that means the available certs may have changed. Update the display
   userTreeView.loadCertsFromCache(certcache, nsIX509Cert.USER_CERT);
@@ -515,24 +522,26 @@ function addEmailCert()
   var bundle = document.getElementById("pippki_bundle");
   var fp = Components.classes[nsFilePicker].createInstance(nsIFilePicker);
   fp.init(window,
           bundle.getString("importEmailCertPrompt"),
           nsIFilePicker.modeOpen);
   fp.appendFilter(bundle.getString("file_browse_Certificate_spec"),
                   gCertFileTypes);
   fp.appendFilters(nsIFilePicker.filterAll);
-  if (fp.show() == nsIFilePicker.returnOK) {
-    certdb.importCertsFromFile(fp.file, nsIX509Cert.EMAIL_CERT);
-    var certcache = certdb.getCerts();
-    emailTreeView.loadCertsFromCache(certcache, nsIX509Cert.EMAIL_CERT);
-    emailTreeView.selection.clearSelection();
-    caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT);
-    caTreeView.selection.clearSelection();
-  }
+  fp.open(rv => {
+    if (rv == nsIFilePicker.returnOK) {
+      certdb.importCertsFromFile(fp.file, nsIX509Cert.EMAIL_CERT);
+      var certcache = certdb.getCerts();
+      emailTreeView.loadCertsFromCache(certcache, nsIX509Cert.EMAIL_CERT);
+      emailTreeView.selection.clearSelection();
+      caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT);
+      caTreeView.selection.clearSelection();
+    }
+  });
 }
 
 function addException()
 {
   window.openDialog("chrome://pippki/content/exceptionDialog.xul", "",
                     "chrome,centerscreen,modal");
   var certcache = certdb.getCerts();
   serverTreeView.loadCertsFromCache(certcache, nsIX509Cert.SERVER_CERT);
--- a/testing/specialpowers/content/MockFilePicker.jsm
+++ b/testing/specialpowers/content/MockFilePicker.jsm
@@ -71,16 +71,17 @@ this.MockFilePicker = {
     this.appendFilterCallback = null;
     this.appendFiltersCallback = null;
     this.displayDirectory = null;
     this.filterIndex = 0;
     this.mode = null;
     this.returnFiles = [];
     this.returnValue = null;
     this.showCallback = null;
+    this.afterOpenCallback = null;
     this.shown = false;
     this.showing = false;
   },
 
   cleanup: function() {
     var previousFactory = this.factory;
     this.reset();
     this.factory = null;
@@ -205,31 +206,39 @@ MockFilePickerInstance.prototype = {
         if (!MockFilePicker.isNsIFile(MockFilePicker.returnFiles[this.index])) {
           return MockFilePicker.returnFiles[this.index++];
         }
         return utils.wrapDOMFile(MockFilePicker.returnFiles[this.index++]);
       }
     };
   },
   show: function() {
+    throw "This is not implemented";
+  },
+  _openInternal: function() {
     MockFilePicker.displayDirectory = this.displayDirectory;
     MockFilePicker.shown = true;
     if (typeof MockFilePicker.showCallback == "function") {
       var returnValue = MockFilePicker.showCallback(this);
       if (typeof returnValue != "undefined")
         return returnValue;
     }
     return MockFilePicker.returnValue;
   },
   open: function(aFilePickerShownCallback) {
     MockFilePicker.showing = true;
     this.window.setTimeout(function() {
       let result = Components.interfaces.nsIFilePicker.returnCancel;
       try {
-        result = this.show();
+        result = this._openInternal();
       } catch(ex) {
       }
       if (aFilePickerShownCallback) {
         aFilePickerShownCallback.done(result);
       }
+      if (typeof MockFilePicker.afterOpenCallback == "function") {
+        this.window.setTimeout(() => {
+          MockFilePicker.afterOpenCallback(this);
+        }, 0);
+      }
     }.bind(this), 0);
   }
 };
--- a/toolkit/components/apppicker/content/appPicker.js
+++ b/toolkit/components/apppicker/content/appPicker.js
@@ -188,23 +188,25 @@ AppPicker.prototype =
       } else if (AppConstants.platform == "macosx") {
         startLocation = "LocApp"; // Local Applications
       } else {
         startLocation = "Home";
       }
       fp.displayDirectory =
         fileLoc.get(startLocation, Components.interfaces.nsILocalFile);
 
-      if (fp.show() == nsIFilePicker.returnOK && fp.file) {
-          var localHandlerApp =
-            Components.classes["@mozilla.org/uriloader/local-handler-app;1"].
-            createInstance(Components.interfaces.nsILocalHandlerApp);
-          localHandlerApp.executable = fp.file;
+      fp.open(rv => {
+          if (rv == nsIFilePicker.returnOK && fp.file) {
+              var localHandlerApp =
+                Components.classes["@mozilla.org/uriloader/local-handler-app;1"].
+                createInstance(Components.interfaces.nsILocalHandlerApp);
+              localHandlerApp.executable = fp.file;
 
-          this._incomingParams.handlerApp = localHandlerApp;
-          window.close();
-      }
+              this._incomingParams.handlerApp = localHandlerApp;
+              window.close();
+          }
+      });
       return true;
     }
 }
 
 // Global object
 var g_dialog = new AppPicker();
--- a/toolkit/components/printing/content/printdialog.js
+++ b/toolkit/components/printing/content/printdialog.js
@@ -297,84 +297,97 @@ function onLoad() {
   // default return value is "cancel"
   paramBlock.SetInt(0, 0);
 
   loadDialog();
 }
 
 // ---------------------------------------------------
 function onAccept() {
-  if (gPrintSettings != null) {
+  let promise;
+
+  if (gPrintSettings == null) {
+    promise = Promise.resolve();
+  } else {
     var print_howToEnableUI = gPrintSetInterface.kFrameEnableNone;
 
     // save these out so they can be picked up by the device spec
     gPrintSettings.printerName = dialog.printerList.value;
     print_howToEnableUI        = gPrintSettings.howToEnableFrameUI;
     gPrintSettings.printToFile = dialog.fileCheck.checked;
 
-    if (gPrintSettings.printToFile && !chooseFile())
-      return false;
+    if (gPrintSettings.printToFile) {
+      promise = chooseFile();
+    } else {
+      promise = Promise.resolve();
+    }
 
-    if (dialog.allpagesRadio.selected) {
-      gPrintSettings.printRange = gPrintSetInterface.kRangeAllPages;
-    } else if (dialog.rangeRadio.selected) {
-      gPrintSettings.printRange = gPrintSetInterface.kRangeSpecifiedPageRange;
-    } else if (dialog.selectionRadio.selected) {
-      gPrintSettings.printRange = gPrintSetInterface.kRangeSelection;
-    }
-    gPrintSettings.startPageRange = dialog.frompageInput.value;
-    gPrintSettings.endPageRange   = dialog.topageInput.value;
-    gPrintSettings.numCopies      = dialog.numCopiesInput.value;
+    promise = promise.then(() => {
+      if (dialog.allpagesRadio.selected) {
+        gPrintSettings.printRange = gPrintSetInterface.kRangeAllPages;
+      } else if (dialog.rangeRadio.selected) {
+        gPrintSettings.printRange = gPrintSetInterface.kRangeSpecifiedPageRange;
+      } else if (dialog.selectionRadio.selected) {
+        gPrintSettings.printRange = gPrintSetInterface.kRangeSelection;
+      }
+      gPrintSettings.startPageRange = dialog.frompageInput.value;
+      gPrintSettings.endPageRange   = dialog.topageInput.value;
+      gPrintSettings.numCopies      = dialog.numCopiesInput.value;
 
-    var frametype = gPrintSetInterface.kNoFrames;
-    if (print_howToEnableUI != gPrintSetInterface.kFrameEnableNone) {
-      if (dialog.aslaidoutRadio.selected) {
-        frametype = gPrintSetInterface.kFramesAsIs;
-      } else if (dialog.selectedframeRadio.selected) {
-        frametype = gPrintSetInterface.kSelectedFrame;
-      } else if (dialog.eachframesepRadio.selected) {
-        frametype = gPrintSetInterface.kEachFrameSep;
-      } else {
-        frametype = gPrintSetInterface.kSelectedFrame;
+      var frametype = gPrintSetInterface.kNoFrames;
+      if (print_howToEnableUI != gPrintSetInterface.kFrameEnableNone) {
+        if (dialog.aslaidoutRadio.selected) {
+          frametype = gPrintSetInterface.kFramesAsIs;
+        } else if (dialog.selectedframeRadio.selected) {
+          frametype = gPrintSetInterface.kSelectedFrame;
+        } else if (dialog.eachframesepRadio.selected) {
+          frametype = gPrintSetInterface.kEachFrameSep;
+        } else {
+          frametype = gPrintSetInterface.kSelectedFrame;
+        }
       }
-    }
-    gPrintSettings.printFrameType = frametype;
-    if (doDebug) {
-      dump("onAccept*********************************************\n");
-      dump("frametype      " + frametype + "\n");
-      dump("numCopies      " + gPrintSettings.numCopies + "\n");
-      dump("printRange     " + gPrintSettings.printRange + "\n");
-      dump("printerName    " + gPrintSettings.printerName + "\n");
-      dump("startPageRange " + gPrintSettings.startPageRange + "\n");
-      dump("endPageRange   " + gPrintSettings.endPageRange + "\n");
-      dump("printToFile    " + gPrintSettings.printToFile + "\n");
-    }
+      gPrintSettings.printFrameType = frametype;
+      if (doDebug) {
+        dump("onAccept*********************************************\n");
+        dump("frametype      " + frametype + "\n");
+        dump("numCopies      " + gPrintSettings.numCopies + "\n");
+        dump("printRange     " + gPrintSettings.printRange + "\n");
+        dump("printerName    " + gPrintSettings.printerName + "\n");
+        dump("startPageRange " + gPrintSettings.startPageRange + "\n");
+        dump("endPageRange   " + gPrintSettings.endPageRange + "\n");
+        dump("printToFile    " + gPrintSettings.printToFile + "\n");
+      }
+    });
   }
 
-  var saveToPrefs = false;
+  promise.then(() => {
+    var saveToPrefs = false;
 
-  saveToPrefs = gPrefs.getBoolPref("print.save_print_settings");
+    saveToPrefs = gPrefs.getBoolPref("print.save_print_settings");
 
-  if (saveToPrefs && printService != null) {
-    var flags = gPrintSetInterface.kInitSavePaperSize |
-                gPrintSetInterface.kInitSaveEdges |
-                gPrintSetInterface.kInitSaveInColor |
-                gPrintSetInterface.kInitSaveShrinkToFit |
-                gPrintSetInterface.kInitSaveScaling;
-    printService.savePrintSettingsToPrefs(gPrintSettings, true, flags);
-  }
+    if (saveToPrefs && printService != null) {
+      var flags = gPrintSetInterface.kInitSavePaperSize |
+                  gPrintSetInterface.kInitSaveEdges |
+                  gPrintSetInterface.kInitSaveInColor |
+                  gPrintSetInterface.kInitSaveShrinkToFit |
+                  gPrintSetInterface.kInitSaveScaling;
+      printService.savePrintSettingsToPrefs(gPrintSettings, true, flags);
+    }
 
-  // set return value to "print"
-  if (paramBlock) {
-    paramBlock.SetInt(0, 1);
-  } else {
-    dump("*** FATAL ERROR: No paramBlock\n");
-  }
+    // set return value to "print"
+    if (paramBlock) {
+      paramBlock.SetInt(0, 1);
+    } else {
+      dump("*** FATAL ERROR: No paramBlock\n");
+    }
 
-  return true;
+    window.close();
+  });
+
+  return false;
 }
 
 // ---------------------------------------------------
 function onCancel() {
   // set return value to "cancel"
   if (paramBlock) {
     paramBlock.SetInt(0, 0);
   } else {
@@ -382,24 +395,22 @@ function onCancel() {
   }
 
   return true;
 }
 
 // ---------------------------------------------------
 const nsIFilePicker = Components.interfaces.nsIFilePicker;
 function chooseFile() {
-  try {
+  return new Promise(resolve => {
     var fp = Components.classes["@mozilla.org/filepicker;1"]
                        .createInstance(nsIFilePicker);
     fp.init(window, dialog.fpDialog.getAttribute("label"), nsIFilePicker.modeSave);
     fp.appendFilters(nsIFilePicker.filterAll);
-    if (fp.show() != Components.interfaces.nsIFilePicker.returnCancel &&
-        fp.file && fp.file.path) {
-      gPrintSettings.toFileName = fp.file.path;
-      return true;
-    }
-  } catch (ex) {
-    dump(ex);
-  }
-
-  return false;
+    fp.open(rv => {
+      if (rv != Components.interfaces.nsIFilePicker.returnCancel &&
+          fp.file && fp.file.path) {
+        gPrintSettings.toFileName = fp.file.path;
+        resolve(null);
+      }
+    });
+  });
 }
--- a/toolkit/mozapps/downloads/nsHelperAppDlg.js
+++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js
@@ -311,63 +311,65 @@ nsUnknownContentTypeDialog.prototype = {
       // return a valid directory path, so we can safely default to it.
       let preferredDir = yield Downloads.getPreferredDownloadsDirectory();
       picker.displayDirectory = new FileUtils.File(preferredDir);
 
       gDownloadLastDir.getFileAsync(aLauncher.source, function LastDirCallback(lastDir) {
         if (lastDir && isUsableDirectory(lastDir))
           picker.displayDirectory = lastDir;
 
-        if (picker.show() == nsIFilePicker.returnCancel) {
-          // null result means user cancelled.
-          aLauncher.saveDestinationAvailable(null);
-          return;
-        }
-
-        // Be sure to save the directory the user chose through the Save As...
-        // dialog  as the new browser.download.dir since the old one
-        // didn't exist.
-        result = picker.file;
-
-        if (result) {
-          try {
-            // Remove the file so that it's not there when we ensure non-existence later;
-            // this is safe because for the file to exist, the user would have had to
-            // confirm that he wanted the file overwritten.
-            // Only remove file if final name exists
-            if (result.exists() && this.getFinalLeafName(result.leafName) == result.leafName)
-              result.remove(false);
-          }
-          catch (ex) {
-            // As it turns out, the failure to remove the file, for example due to
-            // permission error, will be handled below eventually somehow.
+        picker.open(returnValue => {
+          if (returnValue == nsIFilePicker.returnCancel) {
+            // null result means user cancelled.
+            aLauncher.saveDestinationAvailable(null);
+            return;
           }
 
-          var newDir = result.parent.QueryInterface(Components.interfaces.nsILocalFile);
-
-          // Do not store the last save directory as a pref inside the private browsing mode
-          gDownloadLastDir.setFile(aLauncher.source, newDir);
+          // Be sure to save the directory the user chose through the Save As...
+          // dialog  as the new browser.download.dir since the old one
+          // didn't exist.
+          result = picker.file;
 
-          try {
-            result = this.validateLeafName(newDir, result.leafName, null);
-          }
-          catch (ex) {
-            // When the chosen download directory is write-protected,
-            // display an informative error message.
-            // In all cases, download will be stopped.
-
-            if (ex.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED) {
-              this.displayBadPermissionAlert();
-              aLauncher.saveDestinationAvailable(null);
-              return;
+          if (result) {
+            try {
+              // Remove the file so that it's not there when we ensure non-existence later;
+              // this is safe because for the file to exist, the user would have had to
+              // confirm that he wanted the file overwritten.
+              // Only remove file if final name exists
+              if (result.exists() && this.getFinalLeafName(result.leafName) == result.leafName)
+                result.remove(false);
+            }
+            catch (ex) {
+              // As it turns out, the failure to remove the file, for example due to
+              // permission error, will be handled below eventually somehow.
             }
 
+            var newDir = result.parent.QueryInterface(Components.interfaces.nsILocalFile);
+
+            // Do not store the last save directory as a pref inside the private browsing mode
+            gDownloadLastDir.setFile(aLauncher.source, newDir);
+
+            try {
+              result = this.validateLeafName(newDir, result.leafName, null);
+            }
+            catch (ex) {
+              // When the chosen download directory is write-protected,
+              // display an informative error message.
+              // In all cases, download will be stopped.
+
+              if (ex.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED) {
+                this.displayBadPermissionAlert();
+                aLauncher.saveDestinationAvailable(null);
+                return;
+              }
+
+            }
           }
-        }
-        aLauncher.saveDestinationAvailable(result);
+          aLauncher.saveDestinationAvailable(result);
+        });
       }.bind(this));
     }.bind(this)).then(null, Components.utils.reportError);
   },
 
   getFinalLeafName: function (aLeafName, aFileExt)
   {
     // Remove any leading periods, since we don't want to save hidden files
     // automatically.
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -1336,27 +1336,29 @@ var gViewController = {
                 gStrings.ext.GetStringFromName("installFromFile.dialogTitle"),
                 nsIFilePicker.modeOpenMultiple);
         try {
           fp.appendFilter(gStrings.ext.GetStringFromName("installFromFile.filterName"),
                           "*.xpi;*.jar");
           fp.appendFilters(nsIFilePicker.filterAll);
         } catch (e) { }
 
-        if (fp.show() != nsIFilePicker.returnOK)
-          return;
-
-        let browser = getBrowserElement();
-        let files = fp.files;
-        while (files.hasMoreElements()) {
-          let file = files.getNext();
-          AddonManager.getInstallForFile(file, install => {
-            AddonManager.installAddonFromAOM(browser, document.documentURI, install);
-          });
-        }
+        fp.open(result => {
+          if (result != nsIFilePicker.returnOK)
+            return;
+
+          let browser = getBrowserElement();
+          let files = fp.files;
+          while (files.hasMoreElements()) {
+            let file = files.getNext();
+            AddonManager.getInstallForFile(file, install => {
+              AddonManager.installAddonFromAOM(browser, document.documentURI, install);
+            });
+          }
+        });
       }
     },
 
     cmd_debugAddons: {
       isEnabled() {
         return true;
       },
       doCommand() {
--- a/toolkit/mozapps/extensions/content/setting.xml
+++ b/toolkit/mozapps/extensions/content/setting.xml
@@ -369,20 +369,22 @@
               let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
               file.initWithPath(this.value);
               filePicker.displayDirectory = this.type == "file" ? file.parent : file;
               if (this.type == "file") {
                 filePicker.defaultString = file.leafName;
               }
             } catch (e) {}
           }
-          if (filePicker.show() != Ci.nsIFilePicker.returnCancel) {
-            this.value = filePicker.file.path;
-            this.inputChanged();
-          }
+          filePicker.open(rv => {
+            if (rv != Ci.nsIFilePicker.returnCancel && filePicker.file) {
+              this.value = filePicker.file.path;
+              this.inputChanged();
+            }
+          });
         ]]>
         </body>
       </method>
 
       <method name="valueFromPreference">
         <body>
         <![CDATA[
           this.value = Preferences.get(this.pref, "");
--- a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js
@@ -272,74 +272,94 @@ add_test(function() {
     input.focus();
     EventUtils.synthesizeKey("VK_RIGHT", {}, gManagerWindow);
     EventUtils.synthesizeKey("VK_RIGHT", {}, gManagerWindow);
     EventUtils.synthesizeKey("VK_RETURN", {}, gManagerWindow);
     input.hidePopup();
     is(input.color, "#FF9900", "Color picker should have updated value");
     is(Services.prefs.getCharPref("extensions.inlinesettings1.color"), "#FF9900", "Color pref should have been updated");
 
-    try {
-      ok(!settings[6].hasAttribute("first-row"), "Not the first row");
-      var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button");
-      input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input");
-      is(input.value, "", "Label value should be empty");
-      is(input.tooltipText, "", "Label tooltip should be empty");
+    ok(!settings[6].hasAttribute("first-row"), "Not the first row");
+    var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button");
+    input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input");
+    is(input.value, "", "Label value should be empty");
+    is(input.tooltipText, "", "Label tooltip should be empty");
+
+    var testFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
+    testFile.append("\u2622");
+    var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile);
 
-      var testFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
-      testFile.append("\u2622");
-      var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile);
+    MockFilePicker.returnFiles = [testFile];
+    MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
 
-      MockFilePicker.returnFiles = [testFile];
-      MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
+    let promise = new Promise(resolve => {
+      MockFilePicker.afterOpenCallback = resolve;
       EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+    });
+
+    promise.then(() => {
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
       is(input.value, testFile.path, "Label value should match file chosen");
       is(input.tooltipText, testFile.path, "Label tooltip should match file chosen");
       is(Preferences.get("extensions.inlinesettings1.file", "wrong"), testFile.path, "File pref should match file chosen");
 
       MockFilePicker.returnFiles = [curProcD];
       MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
-      EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+      return new Promise(resolve => {
+        MockFilePicker.afterOpenCallback = resolve;
+        EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+      });
+    }).then(() => {
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
       is(input.value, testFile.path, "Label value should not have changed");
       is(input.tooltipText, testFile.path, "Label tooltip should not have changed");
       is(Preferences.get("extensions.inlinesettings1.file", "wrong"), testFile.path, "File pref should not have changed");
 
       ok(!settings[7].hasAttribute("first-row"), "Not the first row");
       button = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "button");
       input = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "input");
       is(input.value, "", "Label value should be empty");
       is(input.tooltipText, "", "Label tooltip should be empty");
 
       MockFilePicker.returnFiles = [testFile];
       MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
-      EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+      return new Promise(resolve => {
+        MockFilePicker.afterOpenCallback = resolve;
+        EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+      });
+    }).then(() => {
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
       is(input.value, testFile.path, "Label value should match file chosen");
       is(input.tooltipText, testFile.path, "Label tooltip should match file chosen");
       is(Preferences.get("extensions.inlinesettings1.directory", "wrong"), testFile.path, "Directory pref should match file chosen");
 
       MockFilePicker.returnFiles = [curProcD];
       MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
-      EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+      return new Promise(resolve => {
+        MockFilePicker.afterOpenCallback = resolve;
+        EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+      });
+    }).then(() => {
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
       is(input.value, testFile.path, "Label value should not have changed");
       is(input.tooltipText, testFile.path, "Label tooltip should not have changed");
       is(Preferences.get("extensions.inlinesettings1.directory", "wrong"), testFile.path, "Directory pref should not have changed");
 
       var unsizedInput = gManagerWindow.document.getAnonymousElementByAttribute(settings[2], "anonid", "input");
       var sizedInput = gManagerWindow.document.getAnonymousElementByAttribute(settings[8], "anonid", "input");
       is(unsizedInput.clientWidth > sizedInput.clientWidth, true, "Input with size attribute should be smaller than input without");
-    } finally {
+    }).then(() => {
       button = gManagerWindow.document.getElementById("detail-prefs-btn");
       is_element_hidden(button, "Preferences button should not be visible");
 
       gCategoryUtilities.openType("extension", run_next_test);
-    }
+    });
   });
 });
 
 // Tests for the setting.xml bindings introduced after Mozilla 7
 add_test(function() {
   observer.checkHidden("inlinesettings1@tests.mozilla.org");
 
   var addon = get_addon_element(gManagerWindow, "inlinesettings3@tests.mozilla.org");
--- a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js
@@ -264,74 +264,93 @@ add_test(function() {
     input.focus();
     EventUtils.synthesizeKey("VK_RIGHT", {}, gManagerWindow);
     EventUtils.synthesizeKey("VK_RIGHT", {}, gManagerWindow);
     EventUtils.synthesizeKey("VK_RETURN", {}, gManagerWindow);
     input.hidePopup();
     is(input.color, "#FF9900", "Color picker should have updated value");
     is(Services.prefs.getCharPref("extensions.inlinesettings1.color"), "#FF9900", "Color pref should have been updated");
 
-    try {
-      ok(!settings[6].hasAttribute("first-row"), "Not the first row");
-      var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button");
+    ok(!settings[6].hasAttribute("first-row"), "Not the first row");
+    var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button");
 
-      // Workaround for bug 1155324 - we need to ensure that the button is scrolled into view.
-      button.scrollIntoView();
+    // Workaround for bug 1155324 - we need to ensure that the button is scrolled into view.
+    button.scrollIntoView();
+
+    input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input");
+    is(input.value, "", "Label value should be empty");
+    is(input.tooltipText, "", "Label tooltip should be empty");
 
-      input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input");
-      is(input.value, "", "Label value should be empty");
-      is(input.tooltipText, "", "Label tooltip should be empty");
+    var profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
+    var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile);
+
+    MockFilePicker.returnFiles = [profD];
+    MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
 
-      var profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
-      var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile);
+    let promise = new Promise(resolve => {
+      MockFilePicker.afterOpenCallback = resolve;
+      EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+    });
 
-      MockFilePicker.returnFiles = [profD];
-      MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
-      EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+    promise.then(() => {
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
       is(input.value, profD.path, "Label value should match file chosen");
       is(input.tooltipText, profD.path, "Label tooltip should match file chosen");
       is(Services.prefs.getCharPref("extensions.inlinesettings1.file"), profD.path, "File pref should match file chosen");
 
       MockFilePicker.returnFiles = [curProcD];
       MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
-      EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+      return promise = new Promise(resolve => {
+        MockFilePicker.afterOpenCallback = resolve;
+        EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+      });
+    }).then(() => {
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
       is(input.value, profD.path, "Label value should not have changed");
       is(input.tooltipText, profD.path, "Label tooltip should not have changed");
       is(Services.prefs.getCharPref("extensions.inlinesettings1.file"), profD.path, "File pref should not have changed");
 
       ok(!settings[7].hasAttribute("first-row"), "Not the first row");
       button = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "button");
       input = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "input");
       is(input.value, "", "Label value should be empty");
       is(input.tooltipText, "", "Label tooltip should be empty");
 
       MockFilePicker.returnFiles = [profD];
       MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
-      EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+      return new Promise(resolve => {
+        MockFilePicker.afterOpenCallback = resolve;
+        EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+      });
+    }).then(() => {
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
       is(input.value, profD.path, "Label value should match file chosen");
       is(input.tooltipText, profD.path, "Label tooltip should match file chosen");
       is(Services.prefs.getCharPref("extensions.inlinesettings1.directory"), profD.path, "Directory pref should match file chosen");
 
       MockFilePicker.returnFiles = [curProcD];
       MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
-      EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+      return new Promise(resolve => {
+        MockFilePicker.afterOpenCallback = resolve;
+        EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+      });
+    }).then(() => {
       is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
       is(input.value, profD.path, "Label value should not have changed");
       is(input.tooltipText, profD.path, "Label tooltip should not have changed");
       is(Services.prefs.getCharPref("extensions.inlinesettings1.directory"), profD.path, "Directory pref should not have changed");
-
-    } finally {
+    }).then(() => {
       button = gManagerWindow.document.getElementById("detail-prefs-btn");
       is_element_hidden(button, "Preferences button should not be visible");
 
       gCategoryUtilities.openType("extension", run_next_test);
-    }
+    });
   });
 });
 
 // Tests for the setting.xml bindings introduced after Mozilla 7
 add_test(function() {
   observer.checkHidden("inlinesettings1@tests.mozilla.org");
 
   var addon = get_addon_element(gManagerWindow, "inlinesettings3@tests.mozilla.org");
--- a/toolkit/mozapps/handling/content/dialog.js
+++ b/toolkit/mozapps/handling/content/dialog.js
@@ -161,45 +161,47 @@ var dialog = {
   chooseApplication: function chooseApplication() {
     var bundle = document.getElementById("base-strings");
     var title = bundle.getString("choose.application.title");
 
     var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     fp.init(window, title, Ci.nsIFilePicker.modeOpen);
     fp.appendFilters(Ci.nsIFilePicker.filterApps);
 
-    if (fp.show() == Ci.nsIFilePicker.returnOK && fp.file) {
-      let uri = Cc["@mozilla.org/network/util;1"].
-                getService(Ci.nsIIOService).
-                newFileURI(fp.file);
+    fp.open(rv => {
+      if (rv == Ci.nsIFilePicker.returnOK && fp.file) {
+        let uri = Cc["@mozilla.org/network/util;1"].
+                  getService(Ci.nsIIOService).
+                  newFileURI(fp.file);
 
-      let handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
-                       createInstance(Ci.nsILocalHandlerApp);
-      handlerApp.executable = fp.file;
+        let handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
+                         createInstance(Ci.nsILocalHandlerApp);
+        handlerApp.executable = fp.file;
 
-      // if this application is already in the list, select it and don't add it again
-      let parent = document.getElementById("items");
-      for (let i = 0; i < parent.childNodes.length; ++i) {
-        let elm = parent.childNodes[i];
-        if (elm.obj instanceof Ci.nsILocalHandlerApp && elm.obj.equals(handlerApp)) {
-          parent.selectedItem = elm;
-          parent.ensureSelectedElementIsVisible();
-          return;
+        // if this application is already in the list, select it and don't add it again
+        let parent = document.getElementById("items");
+        for (let i = 0; i < parent.childNodes.length; ++i) {
+          let elm = parent.childNodes[i];
+          if (elm.obj instanceof Ci.nsILocalHandlerApp && elm.obj.equals(handlerApp)) {
+            parent.selectedItem = elm;
+            parent.ensureSelectedElementIsVisible();
+            return;
+          }
         }
+
+        let elm = document.createElement("richlistitem");
+        elm.setAttribute("type", "handler");
+        elm.setAttribute("name", fp.file.leafName);
+        elm.setAttribute("image", "moz-icon://" + uri.spec + "?size=32");
+        elm.obj = handlerApp;
+
+        parent.selectedItem = parent.insertBefore(elm, parent.firstChild);
+        parent.ensureSelectedElementIsVisible();
       }
-
-      let elm = document.createElement("richlistitem");
-      elm.setAttribute("type", "handler");
-      elm.setAttribute("name", fp.file.leafName);
-      elm.setAttribute("image", "moz-icon://" + uri.spec + "?size=32");
-      elm.obj = handlerApp;
-
-      parent.selectedItem = parent.insertBefore(elm, parent.firstChild);
-      parent.ensureSelectedElementIsVisible();
-    }
+    });
   },
 
  /**
   * Function called when the OK button is pressed.
   */
   onAccept: function onAccept() {
     var checkbox = document.getElementById("remember");
     if (!checkbox.hidden) {
--- a/widget/nsIFilePicker.idl
+++ b/widget/nsIFilePicker.idl
@@ -160,16 +160,18 @@ interface nsIFilePicker : nsISupports
   * Controls whether the chosen file(s) should be added to the system's recent
   * documents list. This attribute will be ignored if the system has no "Recent
   * Docs" concept, or if the application is in private browsing mode (in which
   * case the file will not be added). Defaults to true.
   */
   attribute boolean addToRecentDocs;
 
  /**
+  * This method is **deprecated**. Please use open()
+  *
   * Show File Dialog. The dialog is displayed modally.
   *
   * @return returnOK if the user selects OK, returnCancel if the user selects cancel
   *
   */
   [deprecated] short show();