[image_picker] Handle all images through URI (#2728)
diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md
index 15516ca..66264e7 100644
--- a/packages/image_picker/image_picker/CHANGELOG.md
+++ b/packages/image_picker/image_picker/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.6.6+1
+
+* Android: always use URI to get image/video data.
+
## 0.6.6
* Use the new platform_interface package.
diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java
index a8ca394..9ebf1fa 100644
--- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java
+++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java
@@ -23,16 +23,8 @@
package io.flutter.plugins.imagepicker;
-import android.annotation.SuppressLint;
-import android.content.ContentUris;
import android.content.Context;
-import android.database.Cursor;
import android.net.Uri;
-import android.os.Build;
-import android.os.Environment;
-import android.provider.DocumentsContract;
-import android.provider.MediaStore;
-import android.text.TextUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -42,103 +34,6 @@
class FileUtils {
String getPathFromUri(final Context context, final Uri uri) {
- String path = getPathFromLocalUri(context, uri);
- if (path == null) {
- path = getPathFromRemoteUri(context, uri);
- }
- return path;
- }
-
- @SuppressLint("NewApi")
- private String getPathFromLocalUri(final Context context, final Uri uri) {
- final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
-
- if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
- if (isExternalStorageDocument(uri)) {
- final String docId = DocumentsContract.getDocumentId(uri);
- final String[] split = docId.split(":");
- final String type = split[0];
-
- if ("primary".equalsIgnoreCase(type)) {
- return Environment.getExternalStorageDirectory() + "/" + split[1];
- }
- } else if (isDownloadsDocument(uri)) {
- final String id = DocumentsContract.getDocumentId(uri);
-
- if (!TextUtils.isEmpty(id)) {
- try {
- final Uri contentUri =
- ContentUris.withAppendedId(
- Uri.parse(Environment.DIRECTORY_DOWNLOADS), Long.valueOf(id));
- return getDataColumn(context, contentUri, null, null);
- } catch (NumberFormatException e) {
- return null;
- }
- }
-
- } else if (isMediaDocument(uri)) {
- final String docId = DocumentsContract.getDocumentId(uri);
- final String[] split = docId.split(":");
- final String type = split[0];
-
- Uri contentUri = null;
- if ("image".equals(type)) {
- contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
- } else if ("video".equals(type)) {
- contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- } else if ("audio".equals(type)) {
- contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- }
-
- final String selection = "_id=?";
- final String[] selectionArgs = new String[] {split[1]};
-
- return getDataColumn(context, contentUri, selection, selectionArgs);
- }
- } else if ("content".equalsIgnoreCase(uri.getScheme())) {
-
- // Return the remote address
- if (isGooglePhotosUri(uri)) {
- return null;
- }
-
- return getDataColumn(context, uri, null, null);
- } else if ("file".equalsIgnoreCase(uri.getScheme())) {
- return uri.getPath();
- }
-
- return null;
- }
-
- private static String getDataColumn(
- Context context, Uri uri, String selection, String[] selectionArgs) {
- Cursor cursor = null;
-
- final String column = "_data";
- final String[] projection = {column};
-
- try {
- cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
- if (cursor != null && cursor.moveToFirst()) {
- final int column_index = cursor.getColumnIndex(column);
-
- //yandex.disk and dropbox do not have _data column
- if (column_index == -1) {
- return null;
- }
-
- return cursor.getString(column_index);
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- return null;
- }
-
- private static String getPathFromRemoteUri(final Context context, final Uri uri) {
- // The code below is why Java now has try-with-resources and the Files utility.
File file = null;
InputStream inputStream = null;
OutputStream outputStream = null;
@@ -147,6 +42,7 @@
String extension = getImageExtension(uri);
inputStream = context.getContentResolver().openInputStream(uri);
file = File.createTempFile("image_picker", extension, context.getCacheDir());
+ file.deleteOnExit();
outputStream = new FileOutputStream(file);
if (inputStream != null) {
copy(inputStream, outputStream);
@@ -199,20 +95,4 @@
}
out.flush();
}
-
- private static boolean isExternalStorageDocument(Uri uri) {
- return "com.android.externalstorage.documents".equals(uri.getAuthority());
- }
-
- private static boolean isDownloadsDocument(Uri uri) {
- return "com.android.providers.downloads.documents".equals(uri.getAuthority());
- }
-
- private static boolean isMediaDocument(Uri uri) {
- return "com.android.providers.media.documents".equals(uri.getAuthority());
- }
-
- private static boolean isGooglePhotosUri(Uri uri) {
- return "com.google.android.apps.photos.contentprovider".equals(uri.getAuthority());
- }
}
diff --git a/packages/image_picker/image_picker/example/android/app/build.gradle b/packages/image_picker/image_picker/example/android/app/build.gradle
index 600200b..f4b1e02 100755
--- a/packages/image_picker/image_picker/example/android/app/build.gradle
+++ b/packages/image_picker/image_picker/example/android/app/build.gradle
@@ -63,5 +63,6 @@
testImplementation 'org.mockito:mockito-core:2.17.0'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
+ testImplementation 'androidx.test:core:1.2.0'
testImplementation "org.robolectric:robolectric:4.3.1"
}
diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java
new file mode 100644
index 0000000..c9fa338
--- /dev/null
+++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java
@@ -0,0 +1,57 @@
+// Copyright 2019 The Flutter 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 io.flutter.plugins.imagepicker;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertTrue;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Context;
+import android.net.Uri;
+import androidx.test.core.app.ApplicationProvider;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowContentResolver;
+
+@RunWith(RobolectricTestRunner.class)
+public class FileUtilTest {
+
+ private Context context;
+ private FileUtils fileUtils;
+ ShadowContentResolver shadowContentResolver;
+
+ @Before
+ public void before() {
+ context = ApplicationProvider.getApplicationContext();
+ shadowContentResolver = shadowOf(context.getContentResolver());
+ fileUtils = new FileUtils();
+ }
+
+ @Test
+ public void FileUtil_GetPathFromUri() throws IOException {
+ Uri uri = Uri.parse("content://dummy/dummy.png");
+ shadowContentResolver.registerInputStream(
+ uri, new ByteArrayInputStream("imageStream".getBytes(UTF_8)));
+ String path = fileUtils.getPathFromUri(context, uri);
+ File file = new File(path);
+ int size = (int) file.length();
+ byte[] bytes = new byte[size];
+
+ BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
+ buf.read(bytes, 0, bytes.length);
+ buf.close();
+
+ assertTrue(bytes.length > 0);
+ String imageStream = new String(bytes, UTF_8);
+ assertTrue(imageStream.equals("imageStream"));
+ }
+}
diff --git a/packages/image_picker/image_picker/lib/image_picker.dart b/packages/image_picker/image_picker/lib/image_picker.dart
index 114e5a4..0dd9cac 100755
--- a/packages/image_picker/image_picker/lib/image_picker.dart
+++ b/packages/image_picker/image_picker/lib/image_picker.dart
@@ -27,6 +27,8 @@
/// Returns a [File] object pointing to the image that was picked.
///
+ /// The returned [File] is intended to be used within a single APP session. Do not save the file path and use it across sessions.
+ ///
/// The `source` argument controls where the image comes from. This can
/// be either [ImageSource.camera] or [ImageSource.gallery].
///
@@ -39,7 +41,6 @@
/// image types such as JPEG. If compression is not supported for the image that is picked,
/// an warning message will be logged.
///
- ///
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
/// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
/// Defaults to [CameraDevice.rear].
@@ -65,6 +66,8 @@
/// Returns a [File] object pointing to the video that was picked.
///
+ /// The returned [File] is intended to be used within a single APP session. Do not save the file path and use it across sessions.
+ ///
/// The [source] argument controls where the video comes from. This can
/// be either [ImageSource.camera] or [ImageSource.gallery].
///
diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml
index 8f7ed44..48b781a 100755
--- a/packages/image_picker/image_picker/pubspec.yaml
+++ b/packages/image_picker/image_picker/pubspec.yaml
@@ -2,7 +2,7 @@
description: Flutter plugin for selecting images from the Android and iOS image
library, and taking new pictures with the camera.
homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker
-version: 0.6.6
+version: 0.6.6+1
flutter:
plugin: