diff --git a/mobile/android/base/ActivityResultHandler.java b/mobile/android/base/ActivityResultHandler.java new file mode 100644 index 000000000000..d312f18fac39 --- /dev/null +++ b/mobile/android/base/ActivityResultHandler.java @@ -0,0 +1,11 @@ +/* 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; + +interface ActivityResultHandler { + public void onActivityResult(int resultCode, Intent data); +} diff --git a/mobile/android/base/ActivityResultHandlerMap.java b/mobile/android/base/ActivityResultHandlerMap.java new file mode 100644 index 000000000000..6896c4f96ac1 --- /dev/null +++ b/mobile/android/base/ActivityResultHandlerMap.java @@ -0,0 +1,22 @@ +/* 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 java.util.HashMap; +import java.util.Map; + +class ActivityResultHandlerMap { + private Map mMap = new HashMap(); + private int mCounter = 0; + + synchronized int put(ActivityResultHandler handler) { + mMap.put(mCounter, handler); + return mCounter++; + } + + synchronized ActivityResultHandler getAndRemove(int i) { + return mMap.remove(i); + } +} diff --git a/mobile/android/base/AwesomebarResultHandler.java b/mobile/android/base/AwesomebarResultHandler.java new file mode 100644 index 000000000000..1b1508c1a1d2 --- /dev/null +++ b/mobile/android/base/AwesomebarResultHandler.java @@ -0,0 +1,23 @@ +/* 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 java.util.concurrent.SynchronousQueue; +import android.content.Intent; + +class AwesomebarResultHandler implements ActivityResultHandler { + private static final String LOGTAG = "GeckoAwesomebarResultHandler"; + + public void onActivityResult(int resultCode, Intent data) { + if (data != null) { + String url = data.getStringExtra(AwesomeBar.URL_KEY); + AwesomeBar.Target target = AwesomeBar.Target.valueOf(data.getStringExtra(AwesomeBar.TARGET_KEY)); + String searchEngine = data.getStringExtra(AwesomeBar.SEARCH_KEY); + boolean userEntered = data.getBooleanExtra(AwesomeBar.USER_ENTERED_KEY, false); + if (url != null && url.length() > 0) + GeckoApp.mAppContext.loadRequest(url, target, searchEngine, userEntered); + } + } +} diff --git a/mobile/android/base/CameraImageResultHandler.java b/mobile/android/base/CameraImageResultHandler.java new file mode 100644 index 000000000000..51b619ae410f --- /dev/null +++ b/mobile/android/base/CameraImageResultHandler.java @@ -0,0 +1,50 @@ +/* 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 java.io.File; +import java.util.concurrent.SynchronousQueue; +import android.app.Activity; +import android.content.Intent; +import android.os.Environment; +import android.text.format.Time; +import android.util.Log; + +class CameraImageResultHandler implements ActivityResultHandler { + private static final String LOGTAG = "GeckoCameraImageResultHandler"; + + private final SynchronousQueue mFilePickerResult; + + CameraImageResultHandler(SynchronousQueue resultQueue) { + mFilePickerResult = resultQueue; + } + + public void onActivityResult(int resultCode, Intent data) { + try { + if (resultCode != Activity.RESULT_OK) { + mFilePickerResult.put(""); + return; + } + + File file = new File(Environment.getExternalStorageDirectory(), sImageName); + sImageName = ""; + mFilePickerResult.put(file.getAbsolutePath()); + } catch (InterruptedException e) { + Log.i(LOGTAG, "error returning file picker result", e); + } + } + + // 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; + } +} diff --git a/mobile/android/base/CameraVideoResultHandler.java b/mobile/android/base/CameraVideoResultHandler.java new file mode 100644 index 000000000000..0300d68d1728 --- /dev/null +++ b/mobile/android/base/CameraVideoResultHandler.java @@ -0,0 +1,41 @@ +/* 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 java.util.concurrent.SynchronousQueue; +import android.app.Activity; +import android.content.Intent; +import android.database.Cursor; +import android.provider.MediaStore; +import android.util.Log; + +class CameraVideoResultHandler implements ActivityResultHandler { + private static final String LOGTAG = "GeckoCameraVideoResultHandler"; + + private final SynchronousQueue mFilePickerResult; + + CameraVideoResultHandler(SynchronousQueue resultQueue) { + mFilePickerResult = resultQueue; + } + + public void onActivityResult(int resultCode, Intent data) { + try { + if (data == null || resultCode != Activity.RESULT_OK) { + mFilePickerResult.put(""); + return; + } + + Cursor cursor = GeckoApp.mAppContext.managedQuery(data.getData(), + new String[] { MediaStore.Video.Media.DATA }, + null, + null, + null); + cursor.moveToFirst(); + mFilePickerResult.put(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))); + } catch (InterruptedException e) { + Log.i(LOGTAG, "error returning file picker result", e); + } + } +} diff --git a/mobile/android/base/FilePickerResultHandler.java b/mobile/android/base/FilePickerResultHandler.java new file mode 100644 index 000000000000..b5c7aa7674f6 --- /dev/null +++ b/mobile/android/base/FilePickerResultHandler.java @@ -0,0 +1,79 @@ +/* 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 java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.util.concurrent.SynchronousQueue; +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.provider.OpenableColumns; +import android.util.Log; + +abstract class FilePickerResultHandler implements ActivityResultHandler { + private static final String LOGTAG = "GeckoFilePickerResultHandler"; + + protected final SynchronousQueue mFilePickerResult; + + protected FilePickerResultHandler(SynchronousQueue resultQueue) { + mFilePickerResult = resultQueue; + } + + 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(); + return path == null ? "" : path; + } + try { + ContentResolver cr = GeckoApp.mAppContext.getContentResolver(); + Cursor cursor = cr.query(uri, new String[] { OpenableColumns.DISPLAY_NAME }, + null, null, null); + String name = null; + if (cursor != null) { + try { + if (cursor.moveToNext()) { + name = cursor.getString(0); + } + } finally { + cursor.close(); + } + } + 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); + } + File file = File.createTempFile(fileName, fileExt, GeckoAppShell.getGREDir(GeckoApp.mAppContext)); + 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); + } + return ""; + } +} diff --git a/mobile/android/base/FilePickerResultHandlerSync.java b/mobile/android/base/FilePickerResultHandlerSync.java new file mode 100644 index 000000000000..ed652acfebd2 --- /dev/null +++ b/mobile/android/base/FilePickerResultHandlerSync.java @@ -0,0 +1,25 @@ +/* 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 java.util.concurrent.SynchronousQueue; +import android.content.Intent; +import android.util.Log; + +class FilePickerResultHandlerSync extends FilePickerResultHandler { + private static final String LOGTAG = "GeckoFilePickerResultHandlerSync"; + + FilePickerResultHandlerSync(SynchronousQueue resultQueue) { + super(resultQueue); + } + + public void onActivityResult(int resultCode, Intent data) { + try { + mFilePickerResult.put(handleActivityResult(resultCode, data)); + } catch (InterruptedException e) { + Log.i(LOGTAG, "error returning file picker result", e); + } + } +} diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 6f599e38fd76..a234690e096e 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -31,7 +31,6 @@ import org.json.*; import android.os.*; import android.app.*; import android.text.*; -import android.text.format.Time; import android.view.*; import android.view.inputmethod.*; import android.content.*; @@ -122,11 +121,13 @@ abstract public class GeckoApp Launched, GeckoRunning, GeckoExiting}; private static LaunchState sLaunchState = LaunchState.Launching; + private SynchronousQueue mFilePickerResult = new SynchronousQueue(); + private ActivityResultHandlerMap mActivityResultHandlerMap = new ActivityResultHandlerMap(); - private FilePickerResultHandlerSync mFilePickerResultHandlerSync = new FilePickerResultHandlerSync(); + private FilePickerResultHandlerSync mFilePickerResultHandlerSync = new FilePickerResultHandlerSync(mFilePickerResult); private AwesomebarResultHandler mAwesomebarResultHandler = new AwesomebarResultHandler(); - private CameraImageResultHandler mCameraImageResultHandler = new CameraImageResultHandler(); - private CameraVideoResultHandler mCameraVideoResultHandler = new CameraVideoResultHandler(); + private CameraImageResultHandler mCameraImageResultHandler = new CameraImageResultHandler(mFilePickerResult); + private CameraVideoResultHandler mCameraVideoResultHandler = new CameraVideoResultHandler(mFilePickerResult); abstract public int getLayout(); abstract public boolean isBrowserToolbarSupported(); @@ -2682,12 +2683,6 @@ abstract public class GeckoApp return addIntentActivitiesToList(intent, aItems, aIntents); } - static private String generateImageName() { - Time now = new Time(); - now.setToNow(); - return now.format("%Y-%m-%d %H.%M.%S") + ".jpg"; - } - private PromptService.PromptListItem[] getItemsAndIntentsForFilePicker(String aMimeType, ArrayList aIntents) { ArrayList items = new ArrayList(); @@ -2696,11 +2691,10 @@ abstract public class GeckoApp AddFilePickingActivities(items, "*/*", aIntents); } } else if (aMimeType.equals("image/*")) { - mImageFilePath = generateImageName(); Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory(), - mImageFilePath))); + CameraImageResultHandler.generateImageName()))); addIntentActivitiesToList(intent, items, aIntents); if (AddFilePickingActivities(items, "image/*", aIntents) <= 0) { @@ -2714,11 +2708,10 @@ abstract public class GeckoApp AddFilePickingActivities(items, "*/*", aIntents); } } else { - mImageFilePath = generateImageName(); Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory(), - mImageFilePath))); + CameraImageResultHandler.generateImageName()))); addIntentActivitiesToList(intent, items, aIntents); intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE); @@ -2779,9 +2772,6 @@ abstract public class GeckoApp return intents.get(itemId); } - private String mImageFilePath = ""; - private SynchronousQueue mFilePickerResult = new SynchronousQueue(); - public boolean showFilePicker(String aMimeType, ActivityResultHandler handler) { Intent intent = getFilePickerIntent(aMimeType); @@ -2912,24 +2902,6 @@ abstract public class GeckoApp moveTaskToBack(true); } - public interface ActivityResultHandler { - public void onActivityResult(int resultCode, Intent data); - } - - class ActivityResultHandlerMap { - private Map mMap = new HashMap(); - private int mCounter = 0; - - synchronized int put(ActivityResultHandler handler) { - mMap.put(mCounter, handler); - return mCounter++; - } - - synchronized ActivityResultHandler getAndRemove(int i) { - return mMap.remove(i); - } - } - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { @@ -2940,123 +2912,6 @@ abstract public class GeckoApp super.onActivityResult(requestCode, resultCode, data); } - static abstract class FilePickerResultHandler implements ActivityResultHandler { - String handleActivityResult(int resultCode, Intent data) { - if (data == null || resultCode != RESULT_OK) - return ""; - Uri uri = data.getData(); - if (uri == null) - return ""; - if ("file".equals(uri.getScheme())) { - String path = uri.getPath(); - return path == null ? "" : path; - } - try { - ContentResolver cr = GeckoApp.mAppContext.getContentResolver(); - Cursor cursor = cr.query(uri, new String[] { OpenableColumns.DISPLAY_NAME }, - null, null, null); - String name = null; - if (cursor != null) { - try { - if (cursor.moveToNext()) { - name = cursor.getString(0); - } - } finally { - cursor.close(); - } - } - 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); - } - File file = File.createTempFile(fileName, fileExt, GeckoAppShell.getGREDir(GeckoApp.mAppContext)); - 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); - } - return ""; - } - } - - class FilePickerResultHandlerSync extends FilePickerResultHandler { - public void onActivityResult(int resultCode, Intent data) { - try { - mFilePickerResult.put(handleActivityResult(resultCode, data)); - } catch (InterruptedException e) { - Log.i(LOGTAG, "error returning file picker result", e); - } - - } - } - - class AwesomebarResultHandler implements ActivityResultHandler { - public void onActivityResult(int resultCode, Intent data) { - if (data != null) { - String url = data.getStringExtra(AwesomeBar.URL_KEY); - AwesomeBar.Target target = AwesomeBar.Target.valueOf(data.getStringExtra(AwesomeBar.TARGET_KEY)); - String searchEngine = data.getStringExtra(AwesomeBar.SEARCH_KEY); - boolean userEntered = data.getBooleanExtra(AwesomeBar.USER_ENTERED_KEY, false); - if (url != null && url.length() > 0) - loadRequest(url, target, searchEngine, userEntered); - } - } - } - - class CameraImageResultHandler implements ActivityResultHandler { - public void onActivityResult(int resultCode, Intent data) { - try { - if (resultCode != Activity.RESULT_OK) { - mFilePickerResult.put(""); - return; - } - - File file = new File(Environment.getExternalStorageDirectory(), mImageFilePath); - mImageFilePath = ""; - mFilePickerResult.put(file.getAbsolutePath()); - } catch (InterruptedException e) { - Log.i(LOGTAG, "error returning file picker result", e); - } - } - } - - class CameraVideoResultHandler implements ActivityResultHandler { - public void onActivityResult(int resultCode, Intent data) { - try { - if (data == null || resultCode != Activity.RESULT_OK) { - mFilePickerResult.put(""); - return; - } - - Cursor cursor = managedQuery(data.getData(), - new String[] { MediaStore.Video.Media.DATA }, - null, - null, - null); - cursor.moveToFirst(); - mFilePickerResult.put(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))); - } catch (InterruptedException e) { - Log.i(LOGTAG, "error returning file picker result", e); - } - - } - } - // If searchEngine is provided, url will be used as the search query. // Otherwise, the url is loaded. protected void loadRequest(String url, AwesomeBar.Target target, String searchEngine, boolean userEntered) { diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 47d58ed88f61..66ae42b110d0 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -2271,9 +2271,10 @@ public class GeckoAppShell msg.recycle(); } - static class AsyncResultHandler extends GeckoApp.FilePickerResultHandler { + static class AsyncResultHandler extends FilePickerResultHandler { private long mId; AsyncResultHandler(long id) { + super(null); mId = id; } diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 1c8f0376ec06..696f79505155 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -23,10 +23,13 @@ SYNC_PP_RES_XML=res/xml/sync_syncadapter.xml res/xml/sync_options.xml FENNEC_JAVA_FILES = \ AboutHomeContent.java \ AboutHomeSection.java \ + ActivityResultHandler.java \ + ActivityResultHandlerMap.java \ AndroidImport.java \ AndroidImportPreference.java \ AlertNotification.java \ AwesomeBar.java \ + AwesomebarResultHandler.java \ AwesomeBarTabs.java \ awesomebar/AwesomeBarTab.java \ awesomebar/AllPagesTab.java \ @@ -34,6 +37,8 @@ FENNEC_JAVA_FILES = \ awesomebar/HistoryTab.java \ BrowserApp.java \ BrowserToolbar.java \ + CameraImageResultHandler.java \ + CameraVideoResultHandler.java \ SyncPreference.java \ db/AndroidBrowserDB.java \ db/BrowserDB.java \ @@ -42,6 +47,8 @@ FENNEC_JAVA_FILES = \ DoorHanger.java \ DoorHangerPopup.java \ Favicons.java \ + FilePickerResultHandler.java \ + FilePickerResultHandlerSync.java \ FindInPageBar.java \ FloatUtils.java \ FlowLayout.java \