summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorqinmin <qinmin@chromium.org>2014-08-27 16:01:21 -0700
committerCommit bot <commit-bot@chromium.org>2014-08-27 23:05:47 +0000
commit22b41158f1be60572f4eaa1da8676c36f69cb394 (patch)
tree192388f709b003a1d859429e68180b9643d8ebae
parent39a6a1b1e570f54aaa957095400b6d40aae0e0f1 (diff)
downloadchromium_src-22b41158f1be60572f4eaa1da8676c36f69cb394.zip
chromium_src-22b41158f1be60572f4eaa1da8676c36f69cb394.tar.gz
chromium_src-22b41158f1be60572f4eaa1da8676c36f69cb394.tar.bz2
Use content URI to upload photos taken by camera
Currently chrome creates a file path when uploading a photo taken through camera However, this doesn't always work. Instead, we should use content URI. See more details in the crbug. BUG=405593 Review URL: https://codereview.chromium.org/489053003 Cr-Commit-Position: refs/heads/master@{#292257}
-rw-r--r--base/android/java/src/org/chromium/base/ContentUriUtils.java28
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/FileProviderHelper.java27
-rw-r--r--chrome/android/shell/java/AndroidManifest.xml9
-rw-r--r--chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java3
-rw-r--r--chrome/android/shell/res/xml/file_paths.xml7
-rw-r--r--chrome/chrome.gyp1
-rw-r--r--remoting/remoting_android.gypi12
-rw-r--r--ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java45
8 files changed, 108 insertions, 24 deletions
diff --git a/base/android/java/src/org/chromium/base/ContentUriUtils.java b/base/android/java/src/org/chromium/base/ContentUriUtils.java
index b806b47..70c27ed 100644
--- a/base/android/java/src/org/chromium/base/ContentUriUtils.java
+++ b/base/android/java/src/org/chromium/base/ContentUriUtils.java
@@ -11,15 +11,43 @@ import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;
+import java.io.File;
+
/**
* This class provides methods to access content URI schemes.
*/
public abstract class ContentUriUtils {
private static final String TAG = "ContentUriUtils";
+ private static FileProviderUtil sFileProviderUtil;
+
+ /**
+ * Provides functionality to translate a file into a content URI for use
+ * with a content provider.
+ */
+ public interface FileProviderUtil {
+ /**
+ * Generate a content uri from the given file.
+ * @param context Application context.
+ * @param file The file to be translated.
+ */
+ public Uri getContentUriFromFile(Context context, File file);
+ }
// Prevent instantiation.
private ContentUriUtils() {}
+ public static void setFileProviderUtil(FileProviderUtil util) {
+ sFileProviderUtil = util;
+ }
+
+ public static Uri getContentUriFromFile(Context context, File file) {
+ ThreadUtils.assertOnUiThread();
+ if (sFileProviderUtil != null) {
+ return sFileProviderUtil.getContentUriFromFile(context, file);
+ }
+ return null;
+ }
+
/**
* Opens the content URI for reading, and returns the file descriptor to
* the caller. The caller is responsible for closing the file desciptor.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/FileProviderHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/FileProviderHelper.java
new file mode 100644
index 0000000..7576389
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/FileProviderHelper.java
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser;
+
+import android.content.Context;
+import android.net.Uri;
+import android.support.v4.content.FileProvider;
+
+import org.chromium.base.ContentUriUtils;
+
+import java.io.File;
+
+/**
+ * Utilities for translating a file into content URI.
+ */
+public class FileProviderHelper implements ContentUriUtils.FileProviderUtil {
+ // Keep this variable in sync with the value defined in file_paths.xml.
+ private static final String API_AUTHORITY_SUFFIX = ".FileProvider";
+
+ @Override
+ public Uri getContentUriFromFile(Context context, File file) {
+ return FileProvider.getUriForFile(context,
+ context.getPackageName() + API_AUTHORITY_SUFFIX, file);
+ }
+}
diff --git a/chrome/android/shell/java/AndroidManifest.xml b/chrome/android/shell/java/AndroidManifest.xml
index ad27000..84ca1957 100644
--- a/chrome/android/shell/java/AndroidManifest.xml
+++ b/chrome/android/shell/java/AndroidManifest.xml
@@ -217,6 +217,15 @@
android:authorities="org.chromium.chrome.shell"
android:exported="true" />
+ <!-- Provider for FileProvider. -->
+ <provider android:name="android.support.v4.content.FileProvider"
+ android:authorities="org.chromium.chrome.shell.FileProvider"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_paths" />
+ </provider>
+
<!-- Sync adapter for browser sync. -->
<service android:exported="false"
android:name="org.chromium.chrome.shell.sync.ChromeShellSyncAdapterService">
diff --git a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
index 05608d3..dd31f98 100644
--- a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
+++ b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
@@ -20,9 +20,11 @@ import com.google.common.annotations.VisibleForTesting;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.BaseSwitches;
import org.chromium.base.CommandLine;
+import org.chromium.base.ContentUriUtils;
import org.chromium.base.MemoryPressureListener;
import org.chromium.base.library_loader.ProcessInitException;
import org.chromium.chrome.browser.DevToolsServer;
+import org.chromium.chrome.browser.FileProviderHelper;
import org.chromium.chrome.browser.appmenu.AppMenuHandler;
import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate;
import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils;
@@ -173,6 +175,7 @@ public class ChromeShellActivity extends Activity implements AppMenuPropertiesDe
// In case this method is called after the first onStart(), we need to inform the
// SyncController that we have started.
mSyncController.onStart();
+ ContentUriUtils.setFileProviderUtil(new FileProviderHelper());
}
@Override
diff --git a/chrome/android/shell/res/xml/file_paths.xml b/chrome/android/shell/res/xml/file_paths.xml
new file mode 100644
index 0000000..f40426a
--- /dev/null
+++ b/chrome/android/shell/res/xml/file_paths.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the ContentProvider. -->
+
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+ <files-path name="images" path="images/"/>
+</paths>
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 85a1330..e97ccc3 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -653,6 +653,7 @@
'../printing/printing.gyp:printing_java',
'../sync/sync.gyp:sync_java',
'../third_party/android_tools/android_tools.gyp:android_support_v7_appcompat_javalib',
+ '../third_party/android_tools/android_tools.gyp:android_support_v13_javalib',
'../third_party/guava/guava.gyp:guava_javalib',
'../ui/android/ui_android.gyp:ui_java',
],
diff --git a/remoting/remoting_android.gypi b/remoting/remoting_android.gypi
index b9f0778..744b302 100644
--- a/remoting/remoting_android.gypi
+++ b/remoting/remoting_android.gypi
@@ -102,12 +102,12 @@
],
},
'dependencies': [
- 'android_support_v4_javalib_no_res',
'../base/base.gyp:base_java',
'../ui/android/ui_android.gyp:ui_java',
'remoting_android_resources',
'../third_party/android_tools/android_tools.gyp:android_support_v7_appcompat_javalib',
'../third_party/android_tools/android_tools.gyp:android_support_v7_mediarouter_javalib',
+ '../third_party/android_tools/android_tools.gyp:android_support_v13_javalib',
],
'includes': [ '../build/java.gypi' ],
'conditions' : [
@@ -155,16 +155,6 @@
},
'includes': [ '../build/java_apk.gypi' ],
}, # end of target 'remoting_test_apk'
- {
- # This jar contains the Android support v4 libary. It does not have
- # any associated resources.
- 'target_name': 'android_support_v4_javalib_no_res',
- 'type': 'none',
- 'variables': {
- 'jar_path': '../third_party/android_tools/sdk/extras/android/support/v4/android-support-v4.jar',
- },
- 'includes': ['../build/java_prebuilt.gypi'],
- }, # end of target 'android_support_v4_javalib_no_res'
], # end of 'targets'
'conditions': [
['enable_cast==1', {
diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
index 05186eb..180b493 100644
--- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
+++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
@@ -8,13 +8,14 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ClipData;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
-import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
+import android.util.Log;
import org.chromium.base.CalledByNative;
import org.chromium.base.ContentUriUtils;
@@ -22,6 +23,7 @@ import org.chromium.base.JNINamespace;
import org.chromium.ui.R;
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -32,6 +34,7 @@ import java.util.List;
*/
@JNINamespace("ui")
class SelectFileDialog implements WindowAndroid.IntentCallback{
+ private static final String TAG = "SelectFileDialog";
private static final String IMAGE_TYPE = "image/";
private static final String VIDEO_TYPE = "video/";
private static final String AUDIO_TYPE = "audio/";
@@ -40,6 +43,8 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
private static final String ALL_AUDIO_TYPES = AUDIO_TYPE + "*";
private static final String ANY_TYPES = "*/*";
private static final String CAPTURE_IMAGE_DIRECTORY = "browser-photos";
+ // Keep this variable in sync with the value defined in file_paths.xml.
+ private static final String IMAGE_FILE_PATH = "images";
private final long mNativeSelectFileDialog;
private List<String> mFileTypes;
@@ -66,8 +71,23 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
- mCameraOutputUri = Uri.fromFile(getFileForImageCapture());
+ camera.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ Context context = window.getApplicationContext();
+ try {
+ mCameraOutputUri = ContentUriUtils.getContentUriFromFile(
+ context, getFileForImageCapture(context));
+ } catch (IOException e) {
+ Log.e(TAG, "Cannot retrieve content uri from file", e);
+ }
+ if (mCameraOutputUri == null) {
+ onFileNotSelected();
+ return;
+ }
+
camera.putExtra(MediaStore.EXTRA_OUTPUT, mCameraOutputUri);
+ camera.setClipData(
+ ClipData.newUri(context.getContentResolver(), IMAGE_FILE_PATH, mCameraOutputUri));
Intent camcorder = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
Intent soundRecorder = new Intent(
MediaStore.Audio.Media.RECORD_SOUND_ACTION);
@@ -125,18 +145,16 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
}
/**
- * Get a file for the image capture in the CAPTURE_IMAGE_DIRECTORY directory.
+ * Get a file for the image capture in the IMAGE_FILE_PATH directory.
+ * @param context The application context.
*/
- private File getFileForImageCapture() {
- File externalDataDir = Environment.getExternalStoragePublicDirectory(
- Environment.DIRECTORY_DCIM);
- File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
- File.separator + CAPTURE_IMAGE_DIRECTORY);
- if (!cameraDataDir.exists() && !cameraDataDir.mkdirs()) {
- cameraDataDir = externalDataDir;
+ private File getFileForImageCapture(Context context) throws IOException {
+ final File path = new File(context.getFilesDir(), IMAGE_FILE_PATH);
+ if (!path.exists() && !path.mkdir()) {
+ throw new IOException("Folder cannot be created.");
}
- File photoFile = new File(cameraDataDir.getAbsolutePath() +
- File.separator + System.currentTimeMillis() + ".jpg");
+ File photoFile = File.createTempFile(
+ String.valueOf(System.currentTimeMillis()), ".jpg", path);
return photoFile;
}
@@ -160,7 +178,8 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
if (results == null) {
// If we have a successful return but no data, then assume this is the camera returning
// the photo that we requested.
- nativeOnFileSelected(mNativeSelectFileDialog, mCameraOutputUri.getPath(), "");
+ nativeOnFileSelected(mNativeSelectFileDialog, mCameraOutputUri.toString(),
+ mCameraOutputUri.getLastPathSegment());
// Broadcast to the media scanner that there's a new photo on the device so it will
// show up right away in the gallery (rather than waiting until the next time the media