diff options
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/FilePicker.java')
-rw-r--r-- | mobile/android/base/java/org/mozilla/gecko/FilePicker.java | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/FilePicker.java b/mobile/android/base/java/org/mozilla/gecko/FilePicker.java new file mode 100644 index 000000000..8ac5428a4 --- /dev/null +++ b/mobile/android/base/java/org/mozilla/gecko/FilePicker.java @@ -0,0 +1,227 @@ +/* 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.util.GeckoEventListener; + +import org.json.JSONException; +import org.json.JSONObject; + +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.text.TextUtils; +import android.util.Log; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class FilePicker implements GeckoEventListener { + private static final String LOGTAG = "GeckoFilePicker"; + private static FilePicker sFilePicker; + private final Context context; + + public interface ResultHandler { + public void gotFile(String filename); + } + + public static void init(Context context) { + if (sFilePicker == null) { + sFilePicker = new FilePicker(context.getApplicationContext()); + } + } + + protected FilePicker(Context context) { + this.context = context; + EventDispatcher.getInstance().registerGeckoThreadListener(this, "FilePicker:Show"); + } + + @Override + public void handleMessage(String event, final JSONObject message) { + if (event.equals("FilePicker:Show")) { + String mimeType = "*/*"; + final String mode = message.optString("mode"); + final int tabId = message.optInt("tabId", -1); + final String title = message.optString("title"); + + if ("mimeType".equals(mode)) + mimeType = message.optString("mimeType"); + else if ("extension".equals(mode)) + mimeType = GeckoAppShell.getMimeTypeFromExtensions(message.optString("extensions")); + + showFilePickerAsync(title, mimeType, new ResultHandler() { + @Override + public void gotFile(String filename) { + try { + message.put("file", filename); + } catch (JSONException ex) { + Log.i(LOGTAG, "Can't add filename to message " + filename); + } + + + GeckoAppShell.notifyObservers("FilePicker:Result", message.toString()); + } + }, tabId); + } + } + + private void addActivities(Intent intent, HashMap<String, Intent> intents, HashMap<String, Intent> filters) { + PackageManager pm = context.getPackageManager(); + List<ResolveInfo> lri = pm.queryIntentActivities(intent, 0); + for (ResolveInfo ri : lri) { + ComponentName cn = new ComponentName(ri.activityInfo.applicationInfo.packageName, ri.activityInfo.name); + if (filters != null && !filters.containsKey(cn.toString())) { + Intent rintent = new Intent(intent); + rintent.setComponent(cn); + intents.put(cn.toString(), rintent); + } + } + } + + private Intent getIntent(String mimeType) { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType(mimeType); + intent.addCategory(Intent.CATEGORY_OPENABLE); + return intent; + } + + private List<Intent> getIntentsForFilePicker(final String mimeType, + 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 shwo in the picker (and the intents to launch them). + HashMap<String, Intent> intents = new HashMap<String, Intent> (); + + if ("audio/*".equals(mimeType)) { + // For audio the only intent is the mimetype + baseIntent = getIntent(mimeType); + addActivities(baseIntent, baseIntents, null); + } else if ("image/*".equals(mimeType)) { + // For images the base is a capture intent + baseIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + baseIntent.putExtra(MediaStore.EXTRA_OUTPUT, + Uri.fromFile(new File(Environment.getExternalStorageDirectory(), + fileHandler.generateImageName()))); + addActivities(baseIntent, baseIntents, null); + + // We also add the mimetype intent + addActivities(getIntent(mimeType), intents, baseIntents); + } else if ("video/*".equals(mimeType)) { + // For videos the base is a capture intent + baseIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); + addActivities(baseIntent, baseIntents, null); + + // We also add the mimetype intent + addActivities(getIntent(mimeType), intents, baseIntents); + } else { + baseIntent = getIntent("*/*"); + addActivities(baseIntent, baseIntents, null); + + Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, + Uri.fromFile(new File(Environment.getExternalStorageDirectory(), + fileHandler.generateImageName()))); + addActivities(intent, intents, baseIntents); + intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); + addActivities(intent, intents, baseIntents); + } + + // If we didn't find any activities, we fall back to the */* mimetype intent + if (baseIntents.size() == 0 && intents.size() == 0) { + intents.clear(); + + baseIntent = getIntent("*/*"); + addActivities(baseIntent, baseIntents, null); + } + + ArrayList<Intent> vals = new ArrayList<Intent>(intents.values()); + vals.add(0, baseIntent); + return vals; + } + + private String getFilePickerTitle(String mimeType) { + if (mimeType.equals("audio/*")) { + return context.getString(R.string.filepicker_audio_title); + } else if (mimeType.equals("image/*")) { + return context.getString(R.string.filepicker_image_title); + } else if (mimeType.equals("video/*")) { + return context.getString(R.string.filepicker_video_title); + } else { + return context.getString(R.string.filepicker_title); + } + } + + private interface IntentHandler { + public void gotIntent(Intent intent); + } + + /* 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 void getFilePickerIntentAsync(String title, + final String mimeType, + final FilePickerResultHandler fileHandler, + final IntentHandler handler) { + List<Intent> intents = getIntentsForFilePicker(mimeType, fileHandler); + + if (intents.size() == 0) { + Log.i(LOGTAG, "no activities for the file picker!"); + handler.gotIntent(null); + return; + } + + Intent base = intents.remove(0); + + if (intents.size() == 0) { + handler.gotIntent(base); + return; + } + + if (TextUtils.isEmpty(title)) { + title = getFilePickerTitle(mimeType); + } + Intent chooser = Intent.createChooser(base, title); + chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents.toArray(new Parcelable[intents.size()])); + handler.gotIntent(chooser); + } + + /* 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 String mimeType, final ResultHandler handler, final int tabId) { + final FilePickerResultHandler fileHandler = new FilePickerResultHandler(handler, context, tabId); + getFilePickerIntentAsync(title, mimeType, fileHandler, new IntentHandler() { + @Override + public void gotIntent(Intent intent) { + if (handler == null) { + return; + } + + if (intent == null) { + handler.gotFile(""); + return; + } + + ActivityHandlerHelper.startIntent(intent, fileHandler); + } + }); + } +} |