diff --git a/mobile/android/base/ActivityHandlerHelper.java b/mobile/android/base/ActivityHandlerHelper.java index 255d57b36d3e..5d356601b538 100644 --- a/mobile/android/base/ActivityHandlerHelper.java +++ b/mobile/android/base/ActivityHandlerHelper.java @@ -7,7 +7,6 @@ package org.mozilla.gecko; import org.mozilla.gecko.util.ActivityResultHandler; import org.mozilla.gecko.util.ActivityResultHandlerMap; import org.mozilla.gecko.util.ThreadUtils; -import org.mozilla.gecko.util.GeckoEventListener; import org.json.JSONException; import org.json.JSONObject; @@ -29,7 +28,7 @@ import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; -public class ActivityHandlerHelper implements GeckoEventListener { +public class ActivityHandlerHelper { private static final String LOGTAG = "GeckoActivityHandlerHelper"; private final ConcurrentLinkedQueue mFilePickerResult; @@ -40,10 +39,6 @@ public class ActivityHandlerHelper implements GeckoEventListener { private final CameraImageResultHandler mCameraImageResultHandler; private final CameraVideoResultHandler mCameraVideoResultHandler; - public interface FileResultHandler { - public void gotFile(String filename); - } - @SuppressWarnings("serial") public ActivityHandlerHelper() { mFilePickerResult = new ConcurrentLinkedQueue() { @@ -61,34 +56,6 @@ public class ActivityHandlerHelper implements GeckoEventListener { mAwesomebarResultHandler = new AwesomebarResultHandler(); mCameraImageResultHandler = new CameraImageResultHandler(mFilePickerResult); mCameraVideoResultHandler = new CameraVideoResultHandler(mFilePickerResult); - GeckoAppShell.getEventDispatcher().registerEventListener("FilePicker:Show", this); - } - - @Override - public void handleMessage(String event, final JSONObject message) { - if (event.equals("FilePicker:Show")) { - String mimeType = "*/*"; - String mode = message.optString("mode"); - - if ("mimeType".equals(mode)) - mimeType = message.optString("mimeType"); - else if ("extension".equals(mode)) - mimeType = GeckoAppShell.getMimeTypeFromExtensions(message.optString("extensions")); - - Log.i(LOGTAG, "Mime: " + mimeType); - - showFilePickerAsync(GeckoApp.mAppContext, mimeType, new FileResultHandler() { - public void gotFile(String filename) { - try { - message.put("file", filename); - } catch (JSONException ex) { - Log.i(LOGTAG, "Can't add filename to message " + filename); - } - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent( - "FilePicker:Result", message.toString())); - } - }); - } } public int makeRequestCodeForAwesomebar() { @@ -182,57 +149,6 @@ public class ActivityHandlerHelper implements GeckoEventListener { } } - private interface IntentHandler { - public void gotIntent(Intent intent); - } - - private void getFilePickerIntentAsync(final Context context, String aMimeType, final IntentHandler handler) { - final ArrayList intents = new ArrayList(); - final Prompt.PromptListItem[] items = - getItemsAndIntentsForFilePicker(context, aMimeType, intents); - - if (intents.size() == 0) { - Log.i(LOGTAG, "no activities for the file picker!"); - handler.gotIntent(null); - return; - } - - if (intents.size() == 1) { - handler.gotIntent(intents.get(0)); - return; - } - - final Prompt prompt = new Prompt(context, null, new Prompt.PromptCallback() { - public void onPromptFinished(String promptServiceResult) { - int itemId = -1; - try { - itemId = new JSONObject(promptServiceResult).getInt("button"); - - if (itemId == -1) { - handler.gotIntent(null); - return; - } - } catch (JSONException e) { - Log.e(LOGTAG, "result from promptservice was invalid: ", e); - handler.gotIntent(null); - return; - } - - if (handler != null) - handler.gotIntent(intents.get(itemId)); - } - }); - - final String title = getFilePickerTitle(context, aMimeType); - // Runnable has to be called to show an intent-like - // context menu UI using the PromptService. - ThreadUtils.postToUiThread(new Runnable() { - @Override public void run() { - prompt.show(title, "", items, false); - } - }); - } - private Intent getFilePickerIntent(Context context, String aMimeType) { ArrayList intents = new ArrayList(); final Prompt.PromptListItem[] items = @@ -309,31 +225,6 @@ public class ActivityHandlerHelper implements GeckoEventListener { return filePickerResult; } - public void showFilePickerAsync(final Activity parentActivity, String aMimeType, final FileResultHandler handler) { - getFilePickerIntentAsync(parentActivity, aMimeType, new IntentHandler() { - public void gotIntent(Intent intent) { - if (intent == null) { - handler.gotFile(""); - } - - if (intent.getAction().equals(MediaStore.ACTION_IMAGE_CAPTURE)) { - CameraImageResultHandler cam = new CameraImageResultHandler(handler); - parentActivity.startActivityForResult(intent, mActivityResultHandlerMap.put(cam)); - } else if (intent.getAction().equals(MediaStore.ACTION_VIDEO_CAPTURE)) { - CameraVideoResultHandler vid = new CameraVideoResultHandler(handler); - parentActivity.startActivityForResult(intent, mActivityResultHandlerMap.put(vid)); - } else if (intent.getAction().equals(Intent.ACTION_GET_CONTENT)) { - FilePickerResultHandlerSync file = new FilePickerResultHandlerSync(handler); - parentActivity.startActivityForResult(intent, mActivityResultHandlerMap.put(file)); - } else { - Log.e(LOGTAG, "We should not get an intent with another action!"); - handler.gotFile(""); - return; - } - } - }); - } - boolean handleActivityResult(int requestCode, int resultCode, Intent data) { ActivityResultHandler handler = mActivityResultHandlerMap.getAndRemove(requestCode); if (handler != null) { diff --git a/mobile/android/base/CameraImageResultHandler.java b/mobile/android/base/CameraImageResultHandler.java index d2d5b45b4357..d57d70c41d66 100644 --- a/mobile/android/base/CameraImageResultHandler.java +++ b/mobile/android/base/CameraImageResultHandler.java @@ -19,17 +19,9 @@ class CameraImageResultHandler implements ActivityResultHandler { private static final String LOGTAG = "GeckoCameraImageResultHandler"; private final Queue mFilePickerResult; - private final ActivityHandlerHelper.FileResultHandler mHandler; CameraImageResultHandler(Queue resultQueue) { mFilePickerResult = resultQueue; - mHandler = null; - } - - /* Use this constructor to asynchronously listen for results */ - public CameraImageResultHandler(ActivityHandlerHelper.FileResultHandler handler) { - mHandler = handler; - mFilePickerResult = null; } @Override @@ -41,12 +33,7 @@ class CameraImageResultHandler implements ActivityResultHandler { File file = new File(Environment.getExternalStorageDirectory(), sImageName); sImageName = ""; - - if (mFilePickerResult != null) - mFilePickerResult.offer(file.getAbsolutePath()); - - if (mHandler != null) - mHandler.gotFile(file.getAbsolutePath()); + mFilePickerResult.offer(file.getAbsolutePath()); } // this code is really hacky and doesn't belong anywhere so I'm putting it here for now diff --git a/mobile/android/base/CameraVideoResultHandler.java b/mobile/android/base/CameraVideoResultHandler.java index 4aa1895d57c6..bf99e2cd5cc8 100644 --- a/mobile/android/base/CameraVideoResultHandler.java +++ b/mobile/android/base/CameraVideoResultHandler.java @@ -18,31 +18,15 @@ class CameraVideoResultHandler implements ActivityResultHandler { private static final String LOGTAG = "GeckoCameraVideoResultHandler"; private final Queue mFilePickerResult; - private final ActivityHandlerHelper.FileResultHandler mHandler; CameraVideoResultHandler(Queue resultQueue) { mFilePickerResult = resultQueue; - mHandler = null; - } - - /* Use this constructor to asynchronously listen for results */ - public CameraVideoResultHandler(ActivityHandlerHelper.FileResultHandler handler) { - mFilePickerResult = null; - mHandler = handler; - } - - private void sendResult(String res) { - if (mFilePickerResult != null) - mFilePickerResult.offer(res); - - if (mHandler != null) - mHandler.gotFile(res); } @Override public void onActivityResult(int resultCode, Intent data) { if (data == null || resultCode != Activity.RESULT_OK) { - sendResult(""); + mFilePickerResult.offer(""); return; } @@ -52,7 +36,7 @@ class CameraVideoResultHandler implements ActivityResultHandler { null, null); cursor.moveToFirst(); - - sendResult(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))); + mFilePickerResult.offer(cursor.getString( + cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))); } } diff --git a/mobile/android/base/FilePickerResultHandler.java b/mobile/android/base/FilePickerResultHandler.java index d1b9f9d9b504..e515929a49ff 100644 --- a/mobile/android/base/FilePickerResultHandler.java +++ b/mobile/android/base/FilePickerResultHandler.java @@ -24,11 +24,9 @@ abstract class FilePickerResultHandler implements ActivityResultHandler { private static final String LOGTAG = "GeckoFilePickerResultHandler"; protected final Queue mFilePickerResult; - protected final ActivityHandlerHelper.FileResultHandler mHandler; - protected FilePickerResultHandler(Queue resultQueue, ActivityHandlerHelper.FileResultHandler handler) { + protected FilePickerResultHandler(Queue resultQueue) { mFilePickerResult = resultQueue; - mHandler = handler; } protected String handleActivityResult(int resultCode, Intent data) { @@ -55,8 +53,6 @@ abstract class FilePickerResultHandler implements ActivityResultHandler { cursor.close(); } } - - // tmp filenames must be at least 3 characters long. Add a prefix to make sure that happens String fileName = "tmp_"; String fileExt = null; int period; @@ -65,9 +61,8 @@ abstract class FilePickerResultHandler implements ActivityResultHandler { fileExt = "." + GeckoAppShell.getExtensionFromMimeType(mimeType); } else { fileExt = name.substring(period); - fileName += name.substring(0, period); + fileName = name.substring(0, period); } - Log.i(LOGTAG, "Filename: " + fileName + " . " + fileExt); File file = File.createTempFile(fileName, fileExt, GeckoLoader.getGREDir(GeckoAppShell.getContext())); FileOutputStream fos = new FileOutputStream(file); InputStream is = cr.openInputStream(uri); diff --git a/mobile/android/base/FilePickerResultHandlerSync.java b/mobile/android/base/FilePickerResultHandlerSync.java index 0ab5a8c71d30..9b9a2ab983ed 100644 --- a/mobile/android/base/FilePickerResultHandlerSync.java +++ b/mobile/android/base/FilePickerResultHandlerSync.java @@ -13,20 +13,11 @@ class FilePickerResultHandlerSync extends FilePickerResultHandler { private static final String LOGTAG = "GeckoFilePickerResultHandlerSync"; FilePickerResultHandlerSync(Queue resultQueue) { - super(resultQueue, null); - } - - /* Use this constructor to asynchronously listen for results */ - public FilePickerResultHandlerSync(ActivityHandlerHelper.FileResultHandler handler) { - super(null, handler); + super(resultQueue); } @Override public void onActivityResult(int resultCode, Intent data) { - if (mFilePickerResult != null) - mFilePickerResult.offer(handleActivityResult(resultCode, data)); - - if (mHandler != null) - mHandler.gotFile(handleActivityResult(resultCode, data)); + mFilePickerResult.offer(handleActivityResult(resultCode, data)); } } diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 358a3b9b8a02..a29fb1424fcb 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -2467,12 +2467,28 @@ public class GeckoAppShell return true; } - public static void showFilePickerAsync(String aMimeType, final long id) { - sActivityHelper.showFilePickerAsync(GeckoApp.mAppContext, aMimeType, new ActivityHandlerHelper.FileResultHandler() { - public void gotFile(String filename) { - GeckoAppShell.notifyFilePickerResult(filename, id); + static class AsyncResultHandler extends FilePickerResultHandler { + private long mId; + AsyncResultHandler(long id) { + super(null); + mId = id; + } + + @Override + public void onActivityResult(int resultCode, Intent data) { + GeckoAppShell.notifyFilePickerResult(handleActivityResult(resultCode, data), mId); + } + + } + + static native void notifyFilePickerResult(String filePath, long id); + + /* Called by JNI from AndroidBridge */ + public static void showFilePickerAsync(String aMimeType, long id) { + if (getGeckoInterface() != null) + if (!sActivityHelper.showFilePicker(getGeckoInterface().getActivity(), aMimeType, new AsyncResultHandler(id))) { + GeckoAppShell.notifyFilePickerResult("", id); } - }); } public static void notifyWakeLockChanged(String topic, String state) { diff --git a/mobile/android/components/FilePicker.js b/mobile/android/components/FilePicker.js deleted file mode 100644 index 24b0b60ef097..000000000000 --- a/mobile/android/components/FilePicker.js +++ /dev/null @@ -1,247 +0,0 @@ -/* 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 Ci = Components.interfaces; -const Cu = Components.utils; -const Cc = Components.classes; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); - -function FilePicker() { -} - -FilePicker.prototype = { - _mimeTypeFilter: 0, - _extensionsFilter: "", - _defaultString: "", - _domWin: null, - _defaultExtension: null, - _displayDirectory: null, - _filePath: null, - _promptActive: false, - _filterIndex: 0, - - init: function(aParent, aTitle, aMode) { - this._domWin = aParent; - Services.obs.addObserver(this, "FilePicker:Result", false); - - let idService = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); - this.guid = idService.generateUUID().toString(); - - if (aMode != Ci.nsIFilePicker.modeOpen && aMode != Ci.nsIFilePicker.modeOpenMultiple) - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - }, - - appendFilters: function(aFilterMask) { - if (aFilterMask & Ci.nsIFilePicker.filterAudio) { - this._mimeTypeFilter = "audio/*"; - return; - } - - if (aFilterMask & Ci.nsIFilePicker.filterImages) { - this._mimeTypeFilter = "image/*"; - return; - } - - if (aFilterMask & Ci.nsIFilePicker.filterVideo) { - this._mimeTypeFilter = "video/*"; - return; - } - - if (aFilterMask & Ci.nsIFilePicker.filterAll) { - this._mimeTypeFilter = "*/*"; - return; - } - - /* From BaseFilePicker.cpp */ - if (aFilterMask & Ci.nsIFilePicker.filterHTML) { - this.appendFilter("*.html; *.htm; *.shtml; *.xhtml"); - } - if (aFilterMask & Ci.nsIFilePicker.filterText) { - this.appendFilter("*.txt; *.text"); - } - - if (aFilterMask & Ci.nsIFilePicker.filterXML) { - this.appendFilter("*.xml"); - } - - if (aFilterMask & Ci.nsIFilePicker.xulFilter) { - this.appendFilter("*.xul"); - } - - if (aFilterMask & Ci.nsIFilePicker.xulFilter) { - this.appendFilter("..apps"); - } - }, - - appendFilter: function(title, filter) { - if (this._extensionsFilter) - this._extensionsFilter += ", "; - this._extensionsFilter += filter; - }, - - get defaultString() { - return this._defaultString; - }, - - set defaultString(defaultString) { - this._defaultString = defaultString; - }, - - get defaultExtension() { - return this._defaultExtension; - }, - - set defaultExtension(defaultExtension) { - this._defaultExtension = defaultExtension; - }, - - get filterIndex() { - return this._filterIndex; - }, - - set filterIndex(val) { - this._filterIndex = val; - }, - - get displayDirectory() { - return this._displayDirectory; - }, - - set displayDirectory(dir) { - this._displayDirectory = dir; - }, - - get file() { - if (!this._filePath) { - return null; - } - - return new FileUtils.File(this._filePath); - }, - - get fileURL() { - let file = this.getFile(); - return Services.io.newFileURI(file); - }, - - get files() { - return this.getEnumerator([this.file], function(file) { - return file; - }); - }, - - get domfile() { - let f = this.file; - if (!f) { - return null; - } - return File(f); - }, - - get domfiles() { - return this.getEnumerator([this.file], function(file) { - return File(file); - }); - }, - - get addToRecentDocs() { - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - }, - - set addToRecentDocs(val) { - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - }, - - show: function() { - if (this._domWin) { - PromptUtils.fireDialogEvent(this._domWin, "DOMWillOpenModalDialog"); - let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); - callerWin = winUtils.enterModalStateWithWindow(); - } - - this._promptActive = true; - this._sendMessage(); - - let thread = Services.tm.currentThread; - while (this._promptActive) - thread.processNextEvent(true); - delete this._promptActive; - - if (this._filePath) - return Ci.nsIFilePicker.returnOK; - - return Ci.nsIFilePicker.returnCancel; - }, - - open: function(callback) { - this._callback = callback; - this._sendMessage(); - }, - - _sendMessage: function() { - let msg = { - type: "FilePicker:Show", - guid: this.guid - }; - if (!this._extensionsFilter && !this._mimeTypeFilter) { - // If neither filters is set show anything we can. - msg.mode = "mimeType"; - msg.mimeType = "*/*"; - } else if (this._extensionsFilter) { - msg.mode = "extension"; - msg.extensions = this._extensionsFilter; - } else { - msg.mode = "mimeType"; - msg.mimeType = this._mimeTypeFilter; - } - - this.sendMessageToJava(msg); - }, - - sendMessageToJava: function(aMsg) { - Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge).handleGeckoMessage(JSON.stringify(aMsg)); - }, - - observe: function(aSubject, aTopic, aData) { - let data = JSON.parse(aData); - if (data.guid != this.guid) - return; - - this._filePath = null; - if (data.file) - this._filePath = data.file; - - this._promptActive = false; - - if (this._callback) { - this._callback.done(this._filePath ? Ci.nsIFilePicker.returnOK : Ci.nsIFilePicker.returnCancel); - } - delete this._callback; - }, - - getEnumerator: function(files, mapFunction) { - return { - QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]), - mFiles: files, - mIndex: 0, - hasMoreElements: function() { - return (this.mIndex < this.mFiles.length); - }, - getNext: function() { - if (this.mIndex >= this.mFiles.length) { - throw Components.results.NS_ERROR_FAILURE; - } - return map(this.mFiles[this.mIndex++]); - } - }; - }, - - classID: Components.ID("{18a4e042-7c7c-424b-a583-354e68553a7f}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker, Ci.nsIObserver]) -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FilePicker]); diff --git a/mobile/android/components/Makefile.in b/mobile/android/components/Makefile.in index b6644a6d890d..0920b0301751 100644 --- a/mobile/android/components/Makefile.in +++ b/mobile/android/components/Makefile.in @@ -32,7 +32,6 @@ EXTRA_COMPONENTS = \ NSSDialogService.js \ SiteSpecificUserAgent.js \ PaymentsUI.js \ - FilePicker.js \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/mobile/android/components/MobileComponents.manifest b/mobile/android/components/MobileComponents.manifest index b25c1c70d6d3..92f680f36ae3 100644 --- a/mobile/android/components/MobileComponents.manifest +++ b/mobile/android/components/MobileComponents.manifest @@ -102,6 +102,3 @@ contract @mozilla.org/dom/site-specific-user-agent;1 {d5234c9d-0ee2-4b3c-9da3-18 component {3c6c9575-f57e-427b-a8aa-57bc3cbff48f} PaymentsUI.js contract @mozilla.org/payment/ui-glue;1 {3c6c9575-f57e-427b-a8aa-57bc3cbff48f} -# FilePicker.js -component {18a4e042-7c7c-424b-a583-354e68553a7f} FilePicker.js -contract @mozilla.org/filepicker;1 {18a4e042-7c7c-424b-a583-354e68553a7f} diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index 5f14d29d43ca..adcd4ca33dc9 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -156,6 +156,9 @@ @BINPATH@/components/exthelper.xpt @BINPATH@/components/fastfind.xpt @BINPATH@/components/feeds.xpt +#ifdef MOZ_GTK2 +@BINPATH@/components/filepicker.xpt +#endif @BINPATH@/components/find.xpt @BINPATH@/components/fuel.xpt @BINPATH@/components/gfx.xpt @@ -293,6 +296,10 @@ @BINPATH@/components/crypto-SDR.js @BINPATH@/components/jsconsole-clhandler.manifest @BINPATH@/components/jsconsole-clhandler.js +#ifdef MOZ_GTK2 +@BINPATH@/components/nsFilePicker.manifest +@BINPATH@/components/nsFilePicker.js +#endif @BINPATH@/components/nsHelperAppDlg.manifest @BINPATH@/components/nsHelperAppDlg.js @BINPATH@/components/nsDownloadManagerUI.manifest @@ -344,6 +351,8 @@ @BINPATH@/components/contentAreaDropListener.js @BINPATH@/components/messageWakeupService.js @BINPATH@/components/messageWakeupService.manifest +@BINPATH@/components/nsFilePicker.js +@BINPATH@/components/nsFilePicker.manifest #ifdef MOZ_ENABLE_DBUS @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@ #endif @@ -550,7 +559,6 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@ @BINPATH@/components/ContentPermissionPrompt.js @BINPATH@/components/DirectoryProvider.js @BINPATH@/components/DownloadManagerUI.js -@BINPATH@/components/FilePicker.js @BINPATH@/components/HelperAppDialog.js @BINPATH@/components/LoginManagerPrompter.js @BINPATH@/components/MobileComponents.manifest diff --git a/widget/android/moz.build b/widget/android/moz.build index 51640c2b618d..4424d0f8f5af 100644 --- a/widget/android/moz.build +++ b/widget/android/moz.build @@ -29,6 +29,7 @@ CPP_SOURCES += [ 'nsAppShell.cpp', 'nsClipboard.cpp', 'nsDeviceContextAndroid.cpp', + 'nsFilePicker.cpp', 'nsIMEPicker.cpp', 'nsIdleServiceAndroid.cpp', 'nsLookAndFeel.cpp', diff --git a/widget/android/nsFilePicker.cpp b/widget/android/nsFilePicker.cpp new file mode 100644 index 000000000000..db6e48a33cb3 --- /dev/null +++ b/widget/android/nsFilePicker.cpp @@ -0,0 +1,136 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * 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/. */ + +#include "nsFilePicker.h" +#include "AndroidBridge.h" +#include "nsNetUtil.h" +#include "nsIURI.h" + +NS_IMPL_ISUPPORTS1(nsFilePicker, nsIFilePicker) + +NS_IMETHODIMP nsFilePicker::Init(nsIDOMWindow *parent, const nsAString& title, + int16_t mode) +{ + return (mode == nsIFilePicker::modeOpen || + mode == nsIFilePicker::modeOpenMultiple) + ? NS_OK + : NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsFilePicker::AppendFilters(int32_t aFilterMask) +{ + if (aFilterMask & filterAudio) { + mMimeTypeFilter.AssignLiteral("audio/*"); + return NS_OK; + } + + if (aFilterMask & filterImages) { + mMimeTypeFilter.AssignLiteral("image/*"); + return NS_OK; + } + + if (aFilterMask & filterVideo) { + mMimeTypeFilter.AssignLiteral("video/*"); + return NS_OK; + } + + if (aFilterMask & filterAll) { + mMimeTypeFilter.AssignLiteral("*/*"); + return NS_OK; + } + + return nsBaseFilePicker::AppendFilters(aFilterMask); +} + +NS_IMETHODIMP nsFilePicker::AppendFilter(const nsAString& /*title*/, + const nsAString& filter) +{ + if (!mExtensionsFilter.IsEmpty()) + mExtensionsFilter.AppendLiteral(", "); + mExtensionsFilter.Append(filter); + return NS_OK; +} + +NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString & aDefaultString) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString & aDefaultString) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString & aDefaultExtension) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString & aDefaultExtension) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsFilePicker::GetDisplayDirectory(nsIFile **aDisplayDirectory) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsFilePicker::SetDisplayDirectory(nsIFile *aDisplayDirectory) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsFilePicker::GetFile(nsIFile **aFile) +{ + NS_ENSURE_ARG_POINTER(aFile); + + *aFile = nullptr; + if (mFilePath.IsEmpty()) { + return NS_OK; + } + + nsCOMPtr file(do_CreateInstance("@mozilla.org/file/local;1")); + NS_ENSURE_TRUE(file, NS_ERROR_FAILURE); + + file->InitWithPath(mFilePath); + + NS_ADDREF(*aFile = file); + + nsCString path; + (*aFile)->GetNativePath(path); + return NS_OK; +} + +NS_IMETHODIMP nsFilePicker::GetFileURL(nsIURI **aFileURL) +{ + nsCOMPtr file; + GetFile(getter_AddRefs(file)); + + nsCOMPtr uri; + NS_NewFileURI(getter_AddRefs(uri), file); + NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); + + return CallQueryInterface(uri, aFileURL); +} + +NS_IMETHODIMP nsFilePicker::Show(int16_t *_retval) +{ + if (!mozilla::AndroidBridge::Bridge()) + return NS_ERROR_NOT_IMPLEMENTED; + nsAutoString filePath; + + if (mExtensionsFilter.IsEmpty() && mMimeTypeFilter.IsEmpty()) { + // If neither filters is set show anything we can. + mozilla::AndroidBridge::Bridge()->ShowFilePickerForMimeType(filePath, NS_LITERAL_STRING("*/*")); + } else if (!mExtensionsFilter.IsEmpty()) { + mozilla::AndroidBridge::Bridge()->ShowFilePickerForExtensions(filePath, mExtensionsFilter); + } else { + mozilla::AndroidBridge::Bridge()->ShowFilePickerForMimeType(filePath, mMimeTypeFilter); + } + + *_retval = EmptyString().Equals(filePath) ? + nsIFilePicker::returnCancel : nsIFilePicker::returnOK; + if (*_retval == nsIFilePicker::returnOK) + mFilePath.Assign(filePath); + return NS_OK; +} diff --git a/widget/android/nsFilePicker.h b/widget/android/nsFilePicker.h new file mode 100644 index 000000000000..783c55a1e8db --- /dev/null +++ b/widget/android/nsFilePicker.h @@ -0,0 +1,37 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * 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/. */ + +#ifndef NSFILEPICKER_H +#define NSFILEPICKER_H + +#include "nsBaseFilePicker.h" +#include "nsString.h" + +class nsFilePicker : public nsBaseFilePicker +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHODIMP Init(nsIDOMWindow *parent, const nsAString& title, + int16_t mode); + NS_IMETHOD AppendFilters(int32_t aFilterMask); + NS_IMETHOD AppendFilter(const nsAString & aTitle, + const nsAString & aFilter); + NS_IMETHOD GetDefaultString(nsAString & aDefaultString); + NS_IMETHOD SetDefaultString(const nsAString & aDefaultString); + NS_IMETHOD GetDefaultExtension(nsAString & aDefaultExtension); + NS_IMETHOD SetDefaultExtension(const nsAString & aDefaultExtension); + NS_IMETHOD GetFile(nsIFile * *aFile); + NS_IMETHOD GetFileURL(nsIURI * *aFileURL); + NS_IMETHOD SetDisplayDirectory(nsIFile *aDisplayDirectory); + NS_IMETHOD GetDisplayDirectory(nsIFile **aDisplayDirectory); + NS_IMETHOD Show(int16_t *aReturn); +private: + void InitNative(nsIWidget*, const nsAString&, int16_t) {}; + nsString mFilePath; + nsString mExtensionsFilter; + nsString mMimeTypeFilter; +}; +#endif diff --git a/widget/android/nsWidgetFactory.cpp b/widget/android/nsWidgetFactory.cpp index 132be57b8e27..de7acad1f860 100644 --- a/widget/android/nsWidgetFactory.cpp +++ b/widget/android/nsWidgetFactory.cpp @@ -22,8 +22,10 @@ #include "nsPrintOptionsAndroid.h" #include "nsPrintSession.h" #include "nsDeviceContextAndroid.h" +#include "nsFilePicker.h" #include "nsHTMLFormatConverter.h" #include "nsIMEPicker.h" +#include "nsFilePickerProxy.h" #include "nsXULAppAPI.h" NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow) @@ -47,6 +49,24 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(GfxInfo, Init) } } +static nsresult +nsFilePickerConstructor(nsISupports *aOuter, REFNSIID aIID, + void **aResult) +{ + *aResult = nullptr; + if (aOuter != nullptr) { + return NS_ERROR_NO_AGGREGATION; + } + nsCOMPtr picker; + + if (XRE_GetProcessType() == GeckoProcessType_Content) + picker = new nsFilePickerProxy(); + else + picker = new nsFilePicker; + + return picker->QueryInterface(aIID, aResult); +} + NS_DEFINE_NAMED_CID(NS_APPSHELL_CID); NS_DEFINE_NAMED_CID(NS_WINDOW_CID); NS_DEFINE_NAMED_CID(NS_CHILD_CID); @@ -58,6 +78,7 @@ NS_DEFINE_NAMED_CID(NS_CLIPBOARDHELPER_CID); NS_DEFINE_NAMED_CID(NS_PRINTSETTINGSSERVICE_CID); NS_DEFINE_NAMED_CID(NS_PRINTSESSION_CID); NS_DEFINE_NAMED_CID(NS_DEVICE_CONTEXT_SPEC_CID); +NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID); NS_DEFINE_NAMED_CID(NS_HTMLFORMATCONVERTER_CID); NS_DEFINE_NAMED_CID(NS_IMEPICKER_CID); NS_DEFINE_NAMED_CID(NS_GFXINFO_CID); @@ -75,6 +96,7 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { { &kNS_PRINTSETTINGSSERVICE_CID, false, NULL, nsPrintOptionsAndroidConstructor }, { &kNS_PRINTSESSION_CID, false, NULL, nsPrintSessionConstructor }, { &kNS_DEVICE_CONTEXT_SPEC_CID, false, NULL, nsDeviceContextSpecAndroidConstructor }, + { &kNS_FILEPICKER_CID, false, NULL, nsFilePickerConstructor }, { &kNS_HTMLFORMATCONVERTER_CID, false, NULL, nsHTMLFormatConverterConstructor }, { &kNS_IMEPICKER_CID, false, NULL, nsIMEPickerConstructor }, { &kNS_GFXINFO_CID, false, NULL, mozilla::widget::GfxInfoConstructor }, @@ -94,6 +116,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { { "@mozilla.org/gfx/printsettings-service;1", &kNS_PRINTSETTINGSSERVICE_CID }, { "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID }, { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID }, + { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID }, { "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID }, { "@mozilla.org/imepicker;1", &kNS_IMEPICKER_CID }, { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID },