зеркало из https://github.com/mozilla/gecko-dev.git
Bug 936342 - Make downloads end up in the default storage area on b2g r=dhylands,paolo
This commit is contained in:
Родитель
74ff1235b7
Коммит
05ec709d36
|
@ -71,3 +71,7 @@ contract @mozilla.org/filepicker;1 {436ff8f9-0acc-4b11-8ec7-e293efba3141}
|
|||
component {637b0f77-2429-49a0-915f-abf5d0db8b9a} WebappsUpdateTimer.js
|
||||
contract @mozilla.org/b2g/webapps-update-timer;1 {637b0f77-2429-49a0-915f-abf5d0db8b9a}
|
||||
category update-timer WebappsUpdateTimer @mozilla.org/b2g/webapps-update-timer;1,getService,background-update-timer,webapps.update.interval,86400
|
||||
|
||||
# HelperAppDialog.js
|
||||
component {710322af-e6ae-4b0c-b2c9-1474a87b077e} HelperAppDialog.js
|
||||
contract @mozilla.org/helperapplauncherdialog;1 {710322af-e6ae-4b0c-b2c9-1474a87b077e}
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
||||
"resource://gre/modules/Downloads.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// HelperApp Launcher Dialog
|
||||
//
|
||||
// For now on b2g we never prompt and just download to the default
|
||||
// location.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function HelperAppLauncherDialog() { }
|
||||
|
||||
HelperAppLauncherDialog.prototype = {
|
||||
classID: Components.ID("{710322af-e6ae-4b0c-b2c9-1474a87b077e}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
|
||||
|
||||
show: function(aLauncher, aContext, aReason) {
|
||||
aLauncher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.saveToDisk;
|
||||
aLauncher.saveToDisk(null, false);
|
||||
},
|
||||
|
||||
promptForSaveToFile: function(aLauncher,
|
||||
aContext,
|
||||
aDefaultFile,
|
||||
aSuggestedFileExt,
|
||||
aForcePrompt) {
|
||||
throw Cr.NS_ERROR_NOT_AVAILABLE;
|
||||
},
|
||||
|
||||
promptForSaveToFileAsync: function(aLauncher,
|
||||
aContext,
|
||||
aDefaultFile,
|
||||
aSuggestedFileExt,
|
||||
aForcePrompt) {
|
||||
// Retrieve the user's default download directory.
|
||||
Task.spawn(function() {
|
||||
let file = null;
|
||||
try {
|
||||
let defaultFolder = yield Downloads.getPreferredDownloadsDirectory();
|
||||
let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
dir.initWithPath(defaultFolder);
|
||||
file = this.validateLeafName(dir, aDefaultFile, aSuggestedFileExt);
|
||||
} catch(e) { }
|
||||
aLauncher.saveDestinationAvailable(file);
|
||||
}.bind(this)).then(null, Cu.reportError);
|
||||
},
|
||||
|
||||
validateLeafName: function(aLocalFile, aLeafName, aFileExt) {
|
||||
if (!(aLocalFile && this.isUsableDirectory(aLocalFile)))
|
||||
return null;
|
||||
|
||||
// Remove any leading periods, since we don't want to save hidden files
|
||||
// automatically.
|
||||
aLeafName = aLeafName.replace(/^\.+/, "");
|
||||
|
||||
if (aLeafName == "")
|
||||
aLeafName = "unnamed" + (aFileExt ? "." + aFileExt : "");
|
||||
aLocalFile.append(aLeafName);
|
||||
|
||||
this.makeFileUnique(aLocalFile);
|
||||
return aLocalFile;
|
||||
},
|
||||
|
||||
makeFileUnique: function(aLocalFile) {
|
||||
try {
|
||||
// Note - this code is identical to that in
|
||||
// toolkit/content/contentAreaUtils.js.
|
||||
// If you are updating this code, update that code too! We can't share code
|
||||
// here since this is called in a js component.
|
||||
let collisionCount = 0;
|
||||
while (aLocalFile.exists()) {
|
||||
collisionCount++;
|
||||
if (collisionCount == 1) {
|
||||
// Append "(2)" before the last dot in (or at the end of) the filename
|
||||
// special case .ext.gz etc files so we don't wind up with .tar(2).gz
|
||||
if (aLocalFile.leafName.match(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i))
|
||||
aLocalFile.leafName = aLocalFile.leafName.replace(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i, "(2)$&");
|
||||
else
|
||||
aLocalFile.leafName = aLocalFile.leafName.replace(/(\.[^\.]*)?$/, "(2)$&");
|
||||
}
|
||||
else {
|
||||
// replace the last (n) in the filename with (n+1)
|
||||
aLocalFile.leafName = aLocalFile.leafName.replace(/^(.*\()\d+\)/, "$1" + (collisionCount+1) + ")");
|
||||
}
|
||||
}
|
||||
aLocalFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
|
||||
}
|
||||
catch (e) {
|
||||
dump("*** exception in makeFileUnique: " + e + "\n");
|
||||
|
||||
if (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED)
|
||||
throw e;
|
||||
|
||||
if (aLocalFile.leafName == "" || aLocalFile.isDirectory()) {
|
||||
aLocalFile.append("unnamed");
|
||||
if (aLocalFile.exists())
|
||||
aLocalFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isUsableDirectory: function(aDirectory) {
|
||||
return aDirectory.exists() &&
|
||||
aDirectory.isDirectory() &&
|
||||
aDirectory.isWritable();
|
||||
},
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HelperAppLauncherDialog]);
|
|
@ -15,6 +15,7 @@ EXTRA_COMPONENTS += [
|
|||
'ContentHandler.js',
|
||||
'ContentPermissionPrompt.js',
|
||||
'FilePicker.js',
|
||||
'HelperAppDialog.js',
|
||||
'MailtoProtocolHandler.js',
|
||||
'PaymentGlue.js',
|
||||
'ProcessGlobal.js',
|
||||
|
|
|
@ -395,8 +395,6 @@
|
|||
@BINPATH@/components/crypto-SDR.js
|
||||
@BINPATH@/components/jsconsole-clhandler.manifest
|
||||
@BINPATH@/components/jsconsole-clhandler.js
|
||||
@BINPATH@/components/nsHelperAppDlg.manifest
|
||||
@BINPATH@/components/nsHelperAppDlg.js
|
||||
@BINPATH@/components/nsDownloadManagerUI.manifest
|
||||
@BINPATH@/components/nsDownloadManagerUI.js
|
||||
@BINPATH@/components/nsSidebar.manifest
|
||||
|
@ -774,6 +772,7 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
|
|||
@BINPATH@/components/TelProtocolHandler.js
|
||||
@BINPATH@/components/B2GAboutRedirector.js
|
||||
@BINPATH@/components/FilePicker.js
|
||||
@BINPATH@/components/HelperAppDialog.js
|
||||
|
||||
@BINPATH@/components/DataStore.manifest
|
||||
@BINPATH@/components/DataStoreService.js
|
||||
|
|
|
@ -83,6 +83,10 @@ XPCOMUtils.defineLazyGetter(this, "gInternetZoneIdentifier", function() {
|
|||
return new TextEncoder().encode("[ZoneTransfer]\r\nZoneId=3\r\n");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "volumeService",
|
||||
"@mozilla.org/telephony/volume-service;1",
|
||||
"nsIVolumeService");
|
||||
|
||||
const Timer = Components.Constructor("@mozilla.org/timer;1", "nsITimer",
|
||||
"initWithCallback");
|
||||
|
||||
|
@ -231,6 +235,48 @@ this.DownloadIntegration = {
|
|||
}.bind(this));
|
||||
},
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
/**
|
||||
* Finds the default download directory which can be either in the
|
||||
* internal storage or on the sdcard.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves The downloads directory string path.
|
||||
*/
|
||||
_getDefaultDownloadDirectory: function() {
|
||||
return Task.spawn(function() {
|
||||
let directoryPath;
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let storages = win.navigator.getDeviceStorages("sdcard");
|
||||
let preferredStorageName;
|
||||
// Use the first one or the default storage.
|
||||
storages.forEach((aStorage) => {
|
||||
if (aStorage.default || !preferredStorageName) {
|
||||
preferredStorageName = aStorage.storageName;
|
||||
}
|
||||
});
|
||||
|
||||
// Now get the path for this storage area.
|
||||
if (preferredStorageName) {
|
||||
let volume = volumeService.getVolumeByName(preferredStorageName);
|
||||
if (volume &&
|
||||
volume.isMediaPresent &&
|
||||
!volume.isMountLocked &&
|
||||
!volume.isSharing) {
|
||||
directoryPath = OS.Path.join(volume.mountPoint, "downloads");
|
||||
yield OS.File.makeDir(directoryPath, { ignoreExisting: true });
|
||||
}
|
||||
}
|
||||
if (directoryPath) {
|
||||
throw new Task.Result(directoryPath);
|
||||
} else {
|
||||
throw new Components.Exception("No suitable storage for downloads.",
|
||||
Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH);
|
||||
}
|
||||
});
|
||||
},
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Determines if a Download object from the list of persistent downloads
|
||||
* should be saved into a file, so that it can be restored across sessions.
|
||||
|
@ -286,7 +332,7 @@ this.DownloadIntegration = {
|
|||
directoryPath = this._getDirectory("DfltDwnld");
|
||||
}
|
||||
#elifdef XP_UNIX
|
||||
#ifdef ANDROID
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// Android doesn't have a $HOME directory, and by default we only have
|
||||
// write access to /data/data/org.mozilla.{$APP} and /sdcard
|
||||
directoryPath = gEnvironment.get("DOWNLOADS_DIRECTORY");
|
||||
|
@ -294,6 +340,8 @@ this.DownloadIntegration = {
|
|||
throw new Components.Exception("DOWNLOADS_DIRECTORY is not set.",
|
||||
Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH);
|
||||
}
|
||||
#elifdef MOZ_WIDGET_GONK
|
||||
directoryPath = this._getDefaultDownloadDirectory();
|
||||
#else
|
||||
// For Linux, use XDG download dir, with a fallback to Home/Downloads
|
||||
// if the XDG user dirs are disabled.
|
||||
|
@ -321,6 +369,9 @@ this.DownloadIntegration = {
|
|||
getPreferredDownloadsDirectory: function DI_getPreferredDownloadsDirectory() {
|
||||
return Task.spawn(function() {
|
||||
let directoryPath = null;
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
directoryPath = this._getDefaultDownloadDirectory();
|
||||
#else
|
||||
let prefValue = 1;
|
||||
|
||||
try {
|
||||
|
@ -348,6 +399,7 @@ this.DownloadIntegration = {
|
|||
default:
|
||||
directoryPath = yield this.getSystemDownloadsDirectory();
|
||||
}
|
||||
#endif
|
||||
throw new Task.Result(directoryPath);
|
||||
}.bind(this));
|
||||
},
|
||||
|
@ -363,7 +415,9 @@ this.DownloadIntegration = {
|
|||
let directoryPath = null;
|
||||
#ifdef XP_MACOSX
|
||||
directoryPath = yield this.getPreferredDownloadsDirectory();
|
||||
#elifdef ANDROID
|
||||
#elifdef MOZ_WIDGET_ANDROID
|
||||
directoryPath = yield this.getSystemDownloadsDirectory();
|
||||
#elifdef MOZ_WIDGET_GONK
|
||||
directoryPath = yield this.getSystemDownloadsDirectory();
|
||||
#else
|
||||
// For Metro mode on Windows 8, we want searchability for documents
|
||||
|
|
|
@ -116,6 +116,10 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "nsDeviceStorage.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
|
@ -328,6 +332,32 @@ static nsresult GetDownloadDirectory(nsIFile **_directory)
|
|||
getter_AddRefs(dir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
#elif defined(MOZ_WIDGET_GONK)
|
||||
// On Gonk, store the files on the sdcard in the downloads directory.
|
||||
// We need to check with the volume manager which storage point is
|
||||
// available.
|
||||
|
||||
// Pick the default storage in case multiple (internal and external) ones
|
||||
// are available.
|
||||
nsString storageName;
|
||||
nsDOMDeviceStorage::GetDefaultStorageName(NS_LITERAL_STRING("sdcard"),
|
||||
storageName);
|
||||
NS_ENSURE_TRUE(!storageName.IsEmpty(), NS_ERROR_FAILURE);
|
||||
|
||||
DeviceStorageFile dsf(NS_LITERAL_STRING("sdcard"),
|
||||
storageName,
|
||||
NS_LITERAL_STRING("downloads"));
|
||||
NS_ENSURE_TRUE(dsf.mFile, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(dsf.IsAvailable(), NS_ERROR_FAILURE);
|
||||
|
||||
bool alreadyThere;
|
||||
nsresult rv = dsf.mFile->Exists(&alreadyThere);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!alreadyThere) {
|
||||
rv = dsf.mFile->Create(nsIFile::DIRECTORY_TYPE, 0770);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
dir = dsf.mFile;
|
||||
#elif defined(ANDROID)
|
||||
// On mobile devices, we are avoiding exposing users to the file
|
||||
// system, and don't save downloads to temp directories
|
||||
|
|
Загрузка…
Ссылка в новой задаче