--- a/mobile/android/base/java/org/mozilla/gecko/FilePicker.java
+++ b/mobile/android/base/java/org/mozilla/gecko/FilePicker.java
@@ -1,49 +1,48 @@
/* 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/. */
package org.mozilla.gecko;
-import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.permissions.PermissionBlock;
import org.mozilla.gecko.permissions.Permissions;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import android.Manifest;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.net.Uri;
import android.os.Environment;
import android.os.Parcelable;
-import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
public class FilePicker implements BundleEventListener {
private static final String LOGTAG = "GeckoFilePicker";
private static FilePicker sFilePicker;
+ private static final int MODE_OPEN_MULTIPLE_ATTRIBUTE_VALUE = 3;
+ private static final int MODE_OPEN_SINGLE_ATTRIBUTE_VALUE = 0;
private final Context context;
public interface ResultHandler {
- public void gotFile(String filename);
+ void gotFile(String filename);
}
public static void init(Context context) {
if (sFilePicker == null) {
sFilePicker = new FilePicker(context.getApplicationContext());
}
}
@@ -55,16 +54,18 @@ public class FilePicker implements Bundl
@Override // BundleEventListener
public void handleMessage(final String event, final GeckoBundle message,
final EventCallback callback) {
if ("FilePicker:Show".equals(event)) {
String mimeType = "*/*";
final String mode = message.getString("mode", "");
final int tabId = message.getInt("tabId", -1);
final String title = message.getString("title", "");
+ final boolean isModeOpenMultiple = message.getInt("modeOpenAttribute", MODE_OPEN_SINGLE_ATTRIBUTE_VALUE)
+ == MODE_OPEN_MULTIPLE_ATTRIBUTE_VALUE;
if ("mimeType".equals(mode)) {
mimeType = message.getString("mimeType", "");
} else if ("extension".equals(mode)) {
mimeType = GeckoAppShell.getMimeTypeFromExtensions(message.getString("extensions", ""));
}
final String[] requiredPermission = getPermissionsForMimeType(mimeType);
@@ -84,28 +85,28 @@ public class FilePicker implements Bundl
.andFallback(new Runnable() {
@Override
public void run() {
// In the fallback case, we still show the picker, just
// with the default file list.
// TODO: Figure out which permissions have been denied and use that
// knowledge for availPermissions. For now we assume we don't have any
// permissions at all (bug 1411014).
- showFilePickerAsync(title, "*/*", new String[0], new ResultHandler() {
+ showFilePickerAsync(title, "*/*", new String[0], isModeOpenMultiple, new ResultHandler() {
@Override
public void gotFile(final String filename) {
callback.sendSuccess(filename);
}
}, tabId);
}
})
.run(new Runnable() {
@Override
public void run() {
- showFilePickerAsync(title, finalMimeType, requiredPermission, new ResultHandler() {
+ showFilePickerAsync(title, finalMimeType, requiredPermission, isModeOpenMultiple, new ResultHandler() {
@Override
public void gotFile(final String filename) {
callback.sendSuccess(filename);
}
}, tabId);
}
});
}
@@ -144,60 +145,63 @@ public class FilePicker implements Bundl
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(mimeType);
intent.addCategory(Intent.CATEGORY_OPENABLE);
return intent;
}
private List<Intent> getIntentsForFilePicker(final @NonNull String mimeType,
final @NonNull String[] availPermissions,
+ final boolean isModeOpenMultiple,
final FilePickerResultHandler fileHandler) {
// The base intent to use for the file picker. Even if this is an implicit intent, Android will
// still show a list of Activities that match this action/type.
Intent baseIntent;
// A HashMap of Activities the base intent will show in the chooser. This is used
// to filter activities from other intents so that we don't show duplicates.
HashMap<String, Intent> baseIntents = new HashMap<String, Intent>();
// A list of other activities to show in the picker (and the intents to launch them).
HashMap<String, Intent> intents = new HashMap<String, Intent> ();
+ baseIntent = getIntent(mimeType);
+ if (isModeOpenMultiple) {
+ baseIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ }
+
if (mimeType.startsWith("audio/")) {
- baseIntent = getIntent(mimeType);
addActivities(baseIntent, baseIntents, null);
-
if (mimeType.equals("audio/*") &&
hasPermissionsForMimeType(mimeType, availPermissions)) {
// We also add a capture intent
Intent intent = IntentHelper.getAudioCaptureIntent();
addActivities(intent, intents, baseIntents);
}
- } else if (mimeType.startsWith("image/")) {
- baseIntent = getIntent(mimeType);
+ } else if (mimeType.startsWith("image/") ) {
addActivities(baseIntent, baseIntents, null);
-
if (mimeType.equals("image/*") &&
hasPermissionsForMimeType(mimeType, availPermissions)) {
// We also add a capture intent
Intent intent = IntentHelper.getImageCaptureIntent(
new File(Environment.getExternalStorageDirectory(),
fileHandler.generateImageName()));
addActivities(intent, intents, baseIntents);
}
} else if (mimeType.startsWith("video/")) {
- baseIntent = getIntent(mimeType);
addActivities(baseIntent, baseIntents, null);
-
if (mimeType.equals("video/*") &&
hasPermissionsForMimeType(mimeType, availPermissions)) {
// We also add a capture intent
Intent intent = IntentHelper.getVideoCaptureIntent();
addActivities(intent, intents, baseIntents);
}
} else {
baseIntent = getIntent("*/*");
+ if (isModeOpenMultiple) {
+ baseIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ }
addActivities(baseIntent, baseIntents, null);
Intent intent;
if (hasPermissionsForMimeType("audio/*", availPermissions)) {
intent = IntentHelper.getAudioCaptureIntent();
addActivities(intent, intents, baseIntents);
}
if (hasPermissionsForMimeType("image/*", availPermissions)) {
@@ -240,18 +244,19 @@ public class FilePicker implements Bundl
/* Gets an intent that can open a particular mimetype. Will show a prompt with a list
* of Activities that can handle the mietype. Asynchronously calls the handler when
* one of the intents is selected. If the caller passes in null for the handler, will still
* prompt for the activity, but will throw away the result.
*/
private Intent getFilePickerIntent(String title,
final @NonNull String mimeType,
final @NonNull String[] availPermissions,
+ final boolean isModeOpenMultiple,
final FilePickerResultHandler fileHandler) {
- final List<Intent> intents = getIntentsForFilePicker(mimeType, availPermissions, fileHandler);
+ final List<Intent> intents = getIntentsForFilePicker(mimeType, availPermissions, isModeOpenMultiple, fileHandler);
if (intents.size() == 0) {
Log.i(LOGTAG, "no activities for the file picker!");
return null;
}
final Intent base = intents.remove(0);
@@ -269,20 +274,21 @@ public class FilePicker implements Bundl
}
/* Allows the user to pick an activity to load files from using a list prompt. Then opens the activity and
* sends the file returned to the passed in handler. If a null handler is passed in, will still
* pick and launch the file picker, but will throw away the result.
*/
protected void showFilePickerAsync(final String title, final @NonNull String mimeType,
final @NonNull String[] availPermissions,
+ final boolean isModeOpenMultiple,
final ResultHandler handler, final int tabId) {
final FilePickerResultHandler fileHandler =
new FilePickerResultHandler(handler, context, tabId);
- final Intent intent = getFilePickerIntent(title, mimeType, availPermissions, fileHandler);
+ final Intent intent = getFilePickerIntent(title, mimeType, availPermissions, isModeOpenMultiple, fileHandler);
final Activity currentActivity =
GeckoActivityMonitor.getInstance().getCurrentActivity();
if (intent == null || currentActivity == null) {
handler.gotFile("");
return;
}