зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changesets d3855e27cb32, 6ac71c1149a5, and b8d0cbe94d15 (bug 971939) for Android bustage.
CLOSED TREE
This commit is contained in:
Родитель
8889d81bef
Коммит
98fa8d829d
|
@ -22,31 +22,45 @@ 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.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ActivityHandlerHelper implements GeckoEventListener {
|
||||
private static final String LOGTAG = "GeckoActivityHandlerHelper";
|
||||
|
||||
private final ConcurrentLinkedQueue<String> mFilePickerResult;
|
||||
|
||||
private final ActivityResultHandlerMap mActivityResultHandlerMap;
|
||||
public interface ResultHandler {
|
||||
private final FilePickerResultHandlerSync mFilePickerResultHandlerSync;
|
||||
private final CameraImageResultHandler mCameraImageResultHandler;
|
||||
private final CameraVideoResultHandler mCameraVideoResultHandler;
|
||||
|
||||
public interface FileResultHandler {
|
||||
public void gotFile(String filename);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public ActivityHandlerHelper() {
|
||||
mFilePickerResult = new ConcurrentLinkedQueue<String>() {
|
||||
@Override public boolean offer(String e) {
|
||||
if (super.offer(e)) {
|
||||
// poke the Gecko thread in case it's waiting for new events
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createNoOpEvent());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
mActivityResultHandlerMap = new ActivityResultHandlerMap();
|
||||
mFilePickerResultHandlerSync = new FilePickerResultHandlerSync(mFilePickerResult);
|
||||
mCameraImageResultHandler = new CameraImageResultHandler(mFilePickerResult);
|
||||
mCameraVideoResultHandler = new CameraVideoResultHandler(mFilePickerResult);
|
||||
GeckoAppShell.getEventDispatcher().registerEventListener("FilePicker:Show", this);
|
||||
}
|
||||
|
||||
|
@ -61,7 +75,9 @@ public class ActivityHandlerHelper implements GeckoEventListener {
|
|||
else if ("extension".equals(mode))
|
||||
mimeType = GeckoAppShell.getMimeTypeFromExtensions(message.optString("extensions"));
|
||||
|
||||
showFilePickerAsync(GeckoAppShell.getGeckoInterface().getActivity(), mimeType, new ResultHandler() {
|
||||
Log.i(LOGTAG, "Mime: " + mimeType);
|
||||
|
||||
showFilePickerAsync(GeckoAppShell.getGeckoInterface().getActivity(), mimeType, new FileResultHandler() {
|
||||
public void gotFile(String filename) {
|
||||
try {
|
||||
message.put("file", filename);
|
||||
|
@ -83,86 +99,75 @@ public class ActivityHandlerHelper implements GeckoEventListener {
|
|||
activity.startActivityForResult(intent, mActivityResultHandlerMap.put(activityResultHandler));
|
||||
}
|
||||
|
||||
private void addActivities(Context context, Intent intent, HashMap<String, Intent> intents, HashMap<String, Intent> filters) {
|
||||
private int addIntentActivitiesToList(Context context, Intent intent, ArrayList<Prompt.PromptListItem> items, ArrayList<Intent> aIntents) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
List<ResolveInfo> lri = pm.queryIntentActivityOptions(GeckoAppShell.getGeckoInterface().getActivity().getComponentName(), null, 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);
|
||||
}
|
||||
|
||||
if (lri == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (ResolveInfo ri : lri) {
|
||||
Intent rintent = new Intent(intent);
|
||||
rintent.setComponent(new ComponentName(
|
||||
ri.activityInfo.applicationInfo.packageName,
|
||||
ri.activityInfo.name));
|
||||
|
||||
Prompt.PromptListItem item = new Prompt.PromptListItem(ri.loadLabel(pm).toString());
|
||||
item.icon = ri.loadIcon(pm);
|
||||
items.add(item);
|
||||
aIntents.add(rintent);
|
||||
}
|
||||
|
||||
return lri.size();
|
||||
}
|
||||
|
||||
private Intent getIntent(Context context, String mimeType) {
|
||||
private int addFilePickingActivities(Context context, ArrayList<Prompt.PromptListItem> aItems, String aType, ArrayList<Intent> aIntents) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType(mimeType);
|
||||
intent.setType(aType);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
return intent;
|
||||
|
||||
return addIntentActivitiesToList(context, intent, aItems, aIntents);
|
||||
}
|
||||
|
||||
private List<Intent> getIntentsForFilePicker(final Context context,
|
||||
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 Activitiees 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> ();
|
||||
private Prompt.PromptListItem[] getItemsAndIntentsForFilePicker(Context context, String aMimeType, ArrayList<Intent> aIntents) {
|
||||
ArrayList<Prompt.PromptListItem> items = new ArrayList<Prompt.PromptListItem>();
|
||||
|
||||
if ("audio/*".equals(mimeType)) {
|
||||
// For audio the only intent is the mimetype
|
||||
baseIntent = getIntent(context, mimeType);
|
||||
addActivities(context, 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(context, baseIntent, baseIntents, null);
|
||||
|
||||
// We also add the mimetype intent
|
||||
addActivities(context, getIntent(context, mimeType), intents, baseIntents);
|
||||
} else if ("video/*".equals(mimeType)) {
|
||||
// For videos the base is a capture intent
|
||||
baseIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
|
||||
addActivities(context, baseIntent, baseIntents, null);
|
||||
|
||||
// We also add the mimetype intent
|
||||
addActivities(context, getIntent(context, mimeType), intents, baseIntents);
|
||||
} else {
|
||||
// If we don't have a known mimetype, we just search for */*
|
||||
baseIntent = getIntent(context, "*/*");
|
||||
addActivities(context, baseIntent, baseIntents, null);
|
||||
|
||||
// But we also add the video and audio capture intents
|
||||
if (aMimeType.equals("audio/*")) {
|
||||
if (addFilePickingActivities(context, items, "audio/*", aIntents) <= 0) {
|
||||
addFilePickingActivities(context, items, "*/*", aIntents);
|
||||
}
|
||||
} else if (aMimeType.equals("image/*")) {
|
||||
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT,
|
||||
Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
|
||||
fileHandler.generateImageName())));
|
||||
addActivities(context, intent, intents, baseIntents);
|
||||
CameraImageResultHandler.generateImageName())));
|
||||
addIntentActivitiesToList(context, intent, items, aIntents);
|
||||
|
||||
if (addFilePickingActivities(context, items, "image/*", aIntents) <= 0) {
|
||||
addFilePickingActivities(context, items, "*/*", aIntents);
|
||||
}
|
||||
} else if (aMimeType.equals("video/*")) {
|
||||
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
|
||||
addIntentActivitiesToList(context, intent, items, aIntents);
|
||||
|
||||
if (addFilePickingActivities(context, items, "video/*", aIntents) <= 0) {
|
||||
addFilePickingActivities(context, items, "*/*", aIntents);
|
||||
}
|
||||
} else {
|
||||
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT,
|
||||
Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
|
||||
CameraImageResultHandler.generateImageName())));
|
||||
addIntentActivitiesToList(context, intent, items, aIntents);
|
||||
|
||||
intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
|
||||
addActivities(context, intent, intents, baseIntents);
|
||||
addIntentActivitiesToList(context, intent, items, aIntents);
|
||||
|
||||
addFilePickingActivities(context, items, "*/*", aIntents);
|
||||
}
|
||||
|
||||
// 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(context, "*/*");
|
||||
addActivities(context, baseIntent, baseIntents, null);
|
||||
}
|
||||
|
||||
ArrayList<Intent> vals = new ArrayList<Intent>(intents.values());
|
||||
vals.add(0, baseIntent);
|
||||
return vals;
|
||||
return items.toArray(new Prompt.PromptListItem[] {});
|
||||
}
|
||||
|
||||
private String getFilePickerTitle(Context context, String aMimeType) {
|
||||
|
@ -186,11 +191,10 @@ public class ActivityHandlerHelper implements GeckoEventListener {
|
|||
* 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(final Context context,
|
||||
final String mimeType,
|
||||
final FilePickerResultHandler fileHandler,
|
||||
final IntentHandler handler) {
|
||||
List<Intent> intents = getIntentsForFilePicker(context, mimeType, fileHandler);
|
||||
private void getFilePickerIntentAsync(final Context context, String aMimeType, final IntentHandler handler) {
|
||||
final ArrayList<Intent> intents = new ArrayList<Intent>();
|
||||
final Prompt.PromptListItem[] items =
|
||||
getItemsAndIntentsForFilePicker(context, aMimeType, intents);
|
||||
|
||||
if (intents.size() == 0) {
|
||||
Log.i(LOGTAG, "no activities for the file picker!");
|
||||
|
@ -198,25 +202,48 @@ public class ActivityHandlerHelper implements GeckoEventListener {
|
|||
return;
|
||||
}
|
||||
|
||||
Intent base = intents.remove(0);
|
||||
if (intents.size() == 0) {
|
||||
handler.gotIntent(base);
|
||||
if (intents.size() == 1) {
|
||||
handler.gotIntent(intents.get(0));
|
||||
return;
|
||||
}
|
||||
|
||||
Intent chooser = Intent.createChooser(base, getFilePickerTitle(context, mimeType));
|
||||
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents.toArray(new Parcelable[]{}));
|
||||
handler.gotIntent(chooser);
|
||||
final Prompt prompt = new Prompt(context, new Prompt.PromptCallback() {
|
||||
public void onPromptFinished(String promptServiceResult) {
|
||||
if (handler == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int itemId = -1;
|
||||
try {
|
||||
itemId = new JSONObject(promptServiceResult).getInt("button");
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "result from promptservice was invalid: ", e);
|
||||
}
|
||||
|
||||
if (itemId == -1) {
|
||||
handler.gotIntent(null);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
public void showFilePickerAsync(final Activity parentActivity, String aMimeType, final ResultHandler handler) {
|
||||
final FilePickerResultHandler fileHandler = new FilePickerResultHandler(handler);
|
||||
getFilePickerIntentAsync(parentActivity, aMimeType, fileHandler, new IntentHandler() {
|
||||
@Override
|
||||
public void showFilePickerAsync(final Activity parentActivity, String aMimeType, final FileResultHandler handler) {
|
||||
getFilePickerIntentAsync(parentActivity, aMimeType, new IntentHandler() {
|
||||
public void gotIntent(Intent intent) {
|
||||
if (handler == null) {
|
||||
return;
|
||||
|
@ -227,7 +254,20 @@ public class ActivityHandlerHelper implements GeckoEventListener {
|
|||
return;
|
||||
}
|
||||
|
||||
parentActivity.startActivityForResult(intent, mActivityResultHandlerMap.put(fileHandler));
|
||||
if (MediaStore.ACTION_IMAGE_CAPTURE.equals(intent.getAction())) {
|
||||
CameraImageResultHandler cam = new CameraImageResultHandler(handler);
|
||||
parentActivity.startActivityForResult(intent, mActivityResultHandlerMap.put(cam));
|
||||
} else if (MediaStore.ACTION_VIDEO_CAPTURE.equals(intent.getAction())) {
|
||||
CameraVideoResultHandler vid = new CameraVideoResultHandler(handler);
|
||||
parentActivity.startActivityForResult(intent, mActivityResultHandlerMap.put(vid));
|
||||
} else if (Intent.ACTION_GET_CONTENT.equals(intent.getAction())) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* 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.util.ActivityResultHandler;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Environment;
|
||||
import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Queue;
|
||||
|
||||
class CameraImageResultHandler implements ActivityResultHandler {
|
||||
private static final String LOGTAG = "GeckoCameraImageResultHandler";
|
||||
|
||||
private final Queue<String> mFilePickerResult;
|
||||
private final ActivityHandlerHelper.FileResultHandler mHandler;
|
||||
|
||||
CameraImageResultHandler(Queue<String> resultQueue) {
|
||||
mFilePickerResult = resultQueue;
|
||||
mHandler = null;
|
||||
}
|
||||
|
||||
/* Use this constructor to asynchronously listen for results */
|
||||
public CameraImageResultHandler(ActivityHandlerHelper.FileResultHandler handler) {
|
||||
mHandler = handler;
|
||||
mFilePickerResult = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int resultCode, Intent data) {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
if (mFilePickerResult != null) {
|
||||
mFilePickerResult.offer("");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
File file = new File(Environment.getExternalStorageDirectory(), sImageName);
|
||||
sImageName = "";
|
||||
|
||||
if (mFilePickerResult != null) {
|
||||
mFilePickerResult.offer(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
if (mHandler != null) {
|
||||
mHandler.gotFile(file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
// this code is really hacky and doesn't belong anywhere so I'm putting it here for now
|
||||
// until I can come up with a better solution.
|
||||
|
||||
private static String sImageName = "";
|
||||
|
||||
static String generateImageName() {
|
||||
Time now = new Time();
|
||||
now.setToNow();
|
||||
sImageName = now.format("%Y-%m-%d %H.%M.%S") + ".jpg";
|
||||
return sImageName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/* 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.util.ActivityResultHandler;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Queue;
|
||||
|
||||
class CameraVideoResultHandler implements ActivityResultHandler {
|
||||
private static final String LOGTAG = "GeckoCameraVideoResultHandler";
|
||||
|
||||
private final Queue<String> mFilePickerResult;
|
||||
private final ActivityHandlerHelper.FileResultHandler mHandler;
|
||||
|
||||
CameraVideoResultHandler(Queue<String> 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, final Intent data) {
|
||||
// Intent.getData() can return null. Avoid a crash. See bug 904551.
|
||||
if (data == null || data.getData() == null || resultCode != Activity.RESULT_OK) {
|
||||
sendResult("");
|
||||
return;
|
||||
}
|
||||
|
||||
final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
|
||||
final LoaderManager lm = fa.getSupportLoaderManager();
|
||||
lm.initLoader(data.hashCode(), null, new LoaderCallbacks<Cursor>() {
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
return new CursorLoader(fa,
|
||||
data.getData(),
|
||||
new String[] { MediaStore.Video.Media.DATA },
|
||||
null, // selection
|
||||
null, // selectionArgs
|
||||
null); // sortOrder
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
|
||||
if (cursor.moveToFirst()) {
|
||||
sendResult(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)));
|
||||
} else {
|
||||
sendResult("");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) { }
|
||||
});
|
||||
}
|
||||
}
|
|
@ -12,206 +12,77 @@ import android.content.ContentResolver;
|
|||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Queue;
|
||||
|
||||
class FilePickerResultHandler implements ActivityResultHandler {
|
||||
abstract class FilePickerResultHandler implements ActivityResultHandler {
|
||||
private static final String LOGTAG = "GeckoFilePickerResultHandler";
|
||||
|
||||
protected final Queue<String> mFilePickerResult;
|
||||
protected final ActivityHandlerHelper.ResultHandler mHandler;
|
||||
protected final ActivityHandlerHelper.FileResultHandler mHandler;
|
||||
|
||||
// this code is really hacky and doesn't belong anywhere so I'm putting it here for now
|
||||
// until I can come up with a better solution.
|
||||
private String mImageName = "";
|
||||
|
||||
public FilePickerResultHandler(Queue<String> resultQueue) {
|
||||
protected FilePickerResultHandler(Queue<String> resultQueue, ActivityHandlerHelper.FileResultHandler handler) {
|
||||
mFilePickerResult = resultQueue;
|
||||
mHandler = null;
|
||||
}
|
||||
|
||||
/* Use this constructor to asynchronously listen for results */
|
||||
public FilePickerResultHandler(ActivityHandlerHelper.ResultHandler 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 intent) {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
sendResult("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Camera results won't return an Intent. Use the file name we passed to the original intent.
|
||||
if (intent == null) {
|
||||
if (mImageName != null) {
|
||||
File file = new File(Environment.getExternalStorageDirectory(), mImageName);
|
||||
sendResult(file.getAbsolutePath());
|
||||
} else {
|
||||
sendResult("");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Uri uri = intent.getData();
|
||||
if (uri == null) {
|
||||
sendResult("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Some file pickers may return a file uri
|
||||
protected String handleActivityResult(int resultCode, Intent data) {
|
||||
if (data == null || resultCode != Activity.RESULT_OK)
|
||||
return "";
|
||||
Uri uri = data.getData();
|
||||
if (uri == null)
|
||||
return "";
|
||||
if ("file".equals(uri.getScheme())) {
|
||||
String path = uri.getPath();
|
||||
sendResult(path == null ? "" : path);
|
||||
return;
|
||||
return path == null ? "" : path;
|
||||
}
|
||||
|
||||
final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
|
||||
final LoaderManager lm = fa.getSupportLoaderManager();
|
||||
// Finally, Video pickers and some file pickers may return a content provider.
|
||||
try {
|
||||
// Try a query to make sure the expected columns exist
|
||||
final ContentResolver cr = fa.getContentResolver();
|
||||
Cursor cursor = cr.query(mUri, new String[] { "MediaStore.Video.Media.DATA" }, null, null, null);
|
||||
cursor.close();
|
||||
|
||||
lm.initLoader(intent.hashCode(), null, new VideoLoaderCallbacks(uri));
|
||||
return;
|
||||
} catch(Exception ex) { }
|
||||
|
||||
final LoaderManager lm = fa.getSupportLoaderManager();
|
||||
lm.initLoader(mUri.hashCode(), null, new FileLoaderCallbacks(mUri));
|
||||
return;
|
||||
}
|
||||
|
||||
public String generateImageName() {
|
||||
Time now = new Time();
|
||||
now.setToNow();
|
||||
mImageName = now.format("%Y-%m-%d %H.%M.%S") + ".jpg";
|
||||
return mImageName;
|
||||
}
|
||||
|
||||
private class VideoLoaderCallbacks implements LoaderCallbacks<Cursor> {
|
||||
final private Uri mUri;
|
||||
public VideoLoaderCallbacks(Uri uri) {
|
||||
mUri = uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
|
||||
return new CursorLoader(fa,
|
||||
mUri,
|
||||
new String[] { "MediaStore.Video.Media.DATA" },
|
||||
null, // selection
|
||||
null, // selectionArgs
|
||||
null); // sortOrder
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
|
||||
if (cursor.moveToFirst()) {
|
||||
String res = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
|
||||
sendResult(res);
|
||||
} else {
|
||||
final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
|
||||
final LoaderManager lm = fa.getSupportLoaderManager();
|
||||
lm.initLoader(cursor.hashCode(), null, new FileLoaderCallbacks(mUri));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) { }
|
||||
}
|
||||
|
||||
private class FileLoaderCallbacks implements LoaderCallbacks<Cursor> {
|
||||
final private Uri mUri;
|
||||
public FileLoaderCallbacks(Uri uri) {
|
||||
mUri = uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
|
||||
return new CursorLoader(fa,
|
||||
mUri,
|
||||
new String[] { OpenableColumns.DISPLAY_NAME },
|
||||
null, // selection
|
||||
null, // selectionArgs
|
||||
null); // sortOrder
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
|
||||
if (cursor.moveToFirst()) {
|
||||
String name = cursor.getString(0);
|
||||
// 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;
|
||||
|
||||
final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
|
||||
final ContentResolver cr = fa.getContentResolver();
|
||||
|
||||
// Generate an extension if we don't already have one
|
||||
if (name == null || (period = name.lastIndexOf('.')) == -1) {
|
||||
String mimeType = cr.getType(mUri);
|
||||
fileExt = "." + GeckoAppShell.getExtensionFromMimeType(mimeType);
|
||||
} else {
|
||||
fileExt = name.substring(period);
|
||||
fileName += name.substring(0, period);
|
||||
}
|
||||
|
||||
// Now write the data to the temp file
|
||||
ContentResolver cr = GeckoAppShell.getContext().getContentResolver();
|
||||
Cursor cursor = cr.query(uri, new String[] { OpenableColumns.DISPLAY_NAME },
|
||||
null, null, null);
|
||||
String name = null;
|
||||
if (cursor != null) {
|
||||
try {
|
||||
File file = File.createTempFile(fileName, fileExt, GeckoLoader.getGREDir(GeckoAppShell.getContext()));
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
InputStream is = cr.openInputStream(mUri);
|
||||
byte[] buf = new byte[4096];
|
||||
int len = is.read(buf);
|
||||
while (len != -1) {
|
||||
fos.write(buf, 0, len);
|
||||
len = is.read(buf);
|
||||
if (cursor.moveToNext()) {
|
||||
name = cursor.getString(0);
|
||||
}
|
||||
fos.close();
|
||||
|
||||
String path = file.getAbsolutePath();
|
||||
sendResult((path == null) ? "" : path);
|
||||
} catch(IOException ex) {
|
||||
Log.i(LOGTAG, "Error writing file", ex);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
} else {
|
||||
sendResult("");
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (name == null || (period = name.lastIndexOf('.')) == -1) {
|
||||
String mimeType = cr.getType(uri);
|
||||
fileExt = "." + GeckoAppShell.getExtensionFromMimeType(mimeType);
|
||||
} else {
|
||||
fileExt = name.substring(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);
|
||||
byte[] buf = new byte[4096];
|
||||
int len = is.read(buf);
|
||||
while (len != -1) {
|
||||
fos.write(buf, 0, len);
|
||||
len = is.read(buf);
|
||||
}
|
||||
fos.close();
|
||||
String path = file.getAbsolutePath();
|
||||
return path == null ? "" : path;
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "showing file picker", e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) { }
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* 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 android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Queue;
|
||||
|
||||
class FilePickerResultHandlerSync extends FilePickerResultHandler {
|
||||
private static final String LOGTAG = "GeckoFilePickerResultHandlerSync";
|
||||
|
||||
FilePickerResultHandlerSync(Queue<String> resultQueue) {
|
||||
super(resultQueue, null);
|
||||
}
|
||||
|
||||
/* Use this constructor to asynchronously listen for results */
|
||||
public FilePickerResultHandlerSync(ActivityHandlerHelper.FileResultHandler handler) {
|
||||
super(null, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int resultCode, Intent data) {
|
||||
if (mFilePickerResult != null)
|
||||
mFilePickerResult.offer(handleActivityResult(resultCode, data));
|
||||
|
||||
if (mHandler != null)
|
||||
mHandler.gotFile(handleActivityResult(resultCode, data));
|
||||
}
|
||||
}
|
|
@ -103,6 +103,8 @@ gbjar.sources += [
|
|||
'AppNotificationClient.java',
|
||||
'BaseGeckoInterface.java',
|
||||
'BrowserApp.java',
|
||||
'CameraImageResultHandler.java',
|
||||
'CameraVideoResultHandler.java',
|
||||
'ContactService.java',
|
||||
'ContextGetter.java',
|
||||
'CustomEditText.java',
|
||||
|
@ -135,6 +137,7 @@ gbjar.sources += [
|
|||
'favicons/LoadFaviconTask.java',
|
||||
'favicons/OnFaviconLoadedListener.java',
|
||||
'FilePickerResultHandler.java',
|
||||
'FilePickerResultHandlerSync.java',
|
||||
'FindInPageBar.java',
|
||||
'FormAssistPopup.java',
|
||||
'GeckoAccessibility.java',
|
||||
|
|
Загрузка…
Ссылка в новой задаче