summaryrefslogtreecommitdiffstats
path: root/mobile/android/components/FilePicker.js
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/components/FilePicker.js')
-rw-r--r--mobile/android/components/FilePicker.js302
1 files changed, 302 insertions, 0 deletions
diff --git a/mobile/android/components/FilePicker.js b/mobile/android/components/FilePicker.js
new file mode 100644
index 000000000..2de81ca46
--- /dev/null
+++ b/mobile/android/components/FilePicker.js
@@ -0,0 +1,302 @@
+/* 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");
+
+Cu.importGlobalProperties(['File']);
+
+function FilePicker() {
+}
+
+FilePicker.prototype = {
+ _mimeTypeFilter: 0,
+ _extensionsFilter: "",
+ _defaultString: "",
+ _domWin: null,
+ _defaultExtension: null,
+ _displayDirectory: null,
+ _filePath: null,
+ _promptActive: false,
+ _filterIndex: 0,
+ _addToRecentDocs: false,
+ _title: "",
+
+ init: function(aParent, aTitle, aMode) {
+ this._domWin = aParent;
+ this._mode = aMode;
+ this._title = aTitle;
+ 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;
+ });
+ },
+
+ // We don't support directory selection yet.
+ get domFileOrDirectory() {
+ let f = this.file;
+ if (!f) {
+ return null;
+ }
+
+ let win = this._domWin;
+ if (win) {
+ let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+ return utils.wrapDOMFile(f);
+ }
+
+ return File.createFromNsIFile(f);
+ },
+
+ get domFileOrDirectoryEnumerator() {
+ let win = this._domWin;
+ return this.getEnumerator([this.file], function(file) {
+ if (win) {
+ let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+ return utils.wrapDOMFile(file);
+ }
+
+ return File.createFromNsIFile(file);
+ });
+ },
+
+ get addToRecentDocs() {
+ return this._addToRecentDocs;
+ },
+
+ set addToRecentDocs(val) {
+ this._addToRecentDocs = val;
+ },
+
+ get mode() {
+ return this._mode;
+ },
+
+ show: function() {
+ if (this._domWin) {
+ this.fireDialogEvent(this._domWin, "DOMWillOpenModalDialog");
+ let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+ winUtils.enterModalState();
+ }
+
+ this._promptActive = true;
+ this._sendMessage();
+
+ let thread = Services.tm.currentThread;
+ while (this._promptActive)
+ thread.processNextEvent(true);
+ delete this._promptActive;
+
+ if (this._domWin) {
+ let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+ winUtils.leaveModalState();
+ this.fireDialogEvent(this._domWin, "DOMModalDialogClosed");
+ }
+
+ 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,
+ title: this._title,
+ };
+
+ // Knowing the window lets us destroy any temp files when the tab is closed
+ // Other consumers of the file picker may have to either wait for Android
+ // to clean up the temp dir (not guaranteed) or clean up after themselves.
+ let win = Services.wm.getMostRecentWindow('navigator:browser');
+ let tab = win.BrowserApp.getTabForWindow(this._domWin.top)
+ if (tab) {
+ msg.tabId = tab.id;
+ }
+
+ 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) {
+ Services.androidBridge.handleGeckoMessage(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 mapFunction(this.mFiles[this.mIndex++]);
+ }
+ };
+ },
+
+ fireDialogEvent: function(aDomWin, aEventName) {
+ // accessing the document object can throw if this window no longer exists. See bug 789888.
+ try {
+ if (!aDomWin.document)
+ return;
+ let event = aDomWin.document.createEvent("Events");
+ event.initEvent(aEventName, true, true);
+ let winUtils = aDomWin.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ winUtils.dispatchEventToChromeOnly(aDomWin, event);
+ } catch(ex) {
+ }
+ },
+
+ classID: Components.ID("{18a4e042-7c7c-424b-a583-354e68553a7f}"),
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker, Ci.nsIObserver])
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FilePicker]);