diff --git a/.gitignore b/.gitignore
index 66f4b35e7..83b85db7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,8 @@
+### Android Studio ###
+.idea/
+.gradle/
+local.properties
+
### Xcode ###
## Build generated
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..13372aef5
Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..a6d5f24a0
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Dec 28 10:00:20 PST 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip
diff --git a/android/gradlew b/android/gradlew
new file mode 100644
index 000000000..9d82f7891
--- /dev/null
+++ b/android/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/android/gradlew.bat b/android/gradlew.bat
new file mode 100644
index 000000000..aec99730b
--- /dev/null
+++ b/android/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 2f482edc9..0502baed4 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -1,4 +1,15 @@
+
+
+
+
+
diff --git a/android/src/main/java/com/imagepicker/ImagePickerModule.java b/android/src/main/java/com/imagepicker/ImagePickerModule.java
index d036b642b..5a5518e19 100644
--- a/android/src/main/java/com/imagepicker/ImagePickerModule.java
+++ b/android/src/main/java/com/imagepicker/ImagePickerModule.java
@@ -2,8 +2,8 @@
import android.Manifest;
import android.app.Activity;
-import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
@@ -14,9 +14,14 @@
import android.graphics.drawable.ColorDrawable;
import android.media.ExifInterface;
import android.net.Uri;
+import android.os.Build;
import android.os.Environment;
+import android.provider.ContactsContract;
import android.provider.MediaStore;
+import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.FileProvider;
+import android.app.AlertDialog;
import android.util.Base64;
import android.util.Log;
import android.widget.ArrayAdapter;
@@ -33,6 +38,7 @@
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.WritableMap;
+import com.reactnative.ivpusic.imagepicker.RealPathUtil;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -66,7 +72,6 @@ public class ImagePickerModule extends ReactContextBaseJavaModule implements Act
private Uri mCameraCaptureURI;
private Callback mCallback;
private Boolean noData = false;
- private Boolean tmpImage;
private Boolean pickVideo = false;
private int maxWidth = 0;
private int maxHeight = 0;
@@ -218,7 +223,7 @@ public void launchCamera(final ReadableMap options, final Callback callback) {
// we create a tmp file to save the result
File imageFile = createNewFile();
- mCameraCaptureURI = Uri.fromFile(imageFile);
+ mCameraCaptureURI = compatUriFromFile(mReactContext, imageFile);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCameraCaptureURI);
}
@@ -331,9 +336,13 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode,
uri = null;
}
+ Log.w("URI", String.valueOf(uri));
+
String realPath = getRealPathFromURI(uri);
boolean isUrl = false;
+ Log.w("URI_FILE", String.valueOf(realPath));
+
if (realPath != null) {
try {
URL url = new URL(realPath);
@@ -500,19 +509,8 @@ private boolean isCameraAvailable() {
|| mReactContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
}
- private String getRealPathFromURI(Uri uri) {
- String result;
- String[] projection = {MediaStore.Images.Media.DATA};
- Cursor cursor = mReactContext.getContentResolver().query(uri, projection, null, null, null);
- if (cursor == null) { // Source is Dropbox or other similar local file path
- result = uri.getPath();
- } else {
- cursor.moveToFirst();
- int idx = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
- result = cursor.getString(idx);
- cursor.close();
- }
- return result;
+ private @NonNull String getRealPathFromURI(@NonNull final Uri uri) {
+ return RealPathUtil.getRealPathFromURI(mReactContext, uri);
}
/**
@@ -654,13 +652,11 @@ private File getResizedImage(final String realPath, final int initialWidth, fina
* @return an empty file
*/
private File createNewFile() {
- String filename = "image-" + UUID.randomUUID().toString() + ".jpg";
- File path;
- if (tmpImage) {
- path = mReactContext.getExternalCacheDir();
- } else {
- path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
- }
+ String filename = new StringBuilder("image-")
+ .append(UUID.randomUUID().toString())
+ .append(".jpg")
+ .toString();
+ File path = mReactContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File f = new File(path, filename);
try {
@@ -707,10 +703,6 @@ private void parseOptions(final ReadableMap options) {
if (options.hasKey("quality")) {
quality = (int) (options.getDouble("quality") * 100);
}
- tmpImage = true;
- if (options.hasKey("storageOptions")) {
- tmpImage = false;
- }
rotation = 0;
if (options.hasKey("rotation")) {
rotation = options.getInt("rotation");
@@ -742,4 +734,28 @@ public void onScanCompleted(String path, Uri uri) {
// Required for ActivityEventListener
public void onNewIntent(Intent intent) { }
+
+ public void onActivityResult(int requestCode,
+ int resultCode,
+ Intent data)
+ {
+
+ }
+
+ private static Uri compatUriFromFile(@NonNull final Context context,
+ @NonNull final File file)
+ {
+ Uri result = null;
+ if (Build.VERSION.SDK_INT < 19)
+ {
+ result = Uri.fromFile(file);
+ }
+ else
+ {
+ final String packageName = context.getApplicationContext().getPackageName();
+ final String authority = new StringBuilder(packageName).append(".provider").toString();
+ result = FileProvider.getUriForFile(context, authority, file);
+ }
+ return result;
+ }
}
diff --git a/android/src/main/java/com/reactnative/ivpusic/imagepicker/RealPathUtil.java b/android/src/main/java/com/reactnative/ivpusic/imagepicker/RealPathUtil.java
new file mode 100644
index 000000000..fcbdd6e0c
--- /dev/null
+++ b/android/src/main/java/com/reactnative/ivpusic/imagepicker/RealPathUtil.java
@@ -0,0 +1,178 @@
+package com.reactnative.ivpusic.imagepicker;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.content.ContentUris;
+import android.os.Environment;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.io.File;
+
+public class RealPathUtil {
+ public static @Nullable String getRealPathFromURI(@NonNull final Context context,
+ @NonNull final Uri uri) {
+
+ final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+
+ // DocumentProvider
+ if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+ // ExternalStorageProvider
+ 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];
+ }
+
+ // TODO handle non-primary volumes
+ }
+ // DownloadsProvider
+ else if (isDownloadsDocument(uri)) {
+
+ final String id = DocumentsContract.getDocumentId(uri);
+ final Uri contentUri = ContentUris.withAppendedId(
+ Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
+
+ return getDataColumn(context, contentUri, null, null);
+ }
+ // MediaProvider
+ 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);
+ }
+ }
+ // MediaStore (and general)
+ else if ("content".equalsIgnoreCase(uri.getScheme())) {
+
+ // Return the remote address
+ if (isGooglePhotosUri(uri))
+ return uri.getLastPathSegment();
+
+ if (isFileProviderUri(context, uri))
+ return getFileProviderPath(context, uri);
+
+ return getDataColumn(context, uri, null, null);
+ }
+ // File
+ else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return uri.getPath();
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the value of the data column for this Uri. This is useful for
+ * MediaStore Uris, and other file-based ContentProviders.
+ *
+ * @param context The context.
+ * @param uri The Uri to query.
+ * @param selection (Optional) Filter used in the query.
+ * @param selectionArgs (Optional) Selection arguments used in the query.
+ * @return The value of the _data column, which is typically a file path.
+ */
+ public 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 index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(index);
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ return null;
+ }
+
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is ExternalStorageProvider.
+ */
+ public static boolean isExternalStorageDocument(Uri uri) {
+ return "com.android.externalstorage.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is DownloadsProvider.
+ */
+ public static boolean isDownloadsDocument(Uri uri) {
+ return "com.android.providers.downloads.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is MediaProvider.
+ */
+ public static boolean isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is Google Photos.
+ */
+ public static boolean isGooglePhotosUri(@NonNull final Uri uri) {
+ return "com.google.android.apps.photos.content".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param context The Application context
+ * @param uri The Uri is checked by functions
+ * @return Whether the Uri authority is FileProvider
+ */
+ public static boolean isFileProviderUri(@NonNull final Context context,
+ @NonNull final Uri uri) {
+ final String packageName = context.getPackageName();
+ final String authority = new StringBuilder(packageName).append(".provider").toString();
+ return authority.equals(uri.getAuthority());
+ }
+
+ /**
+ * @param context The Application context
+ * @param uri The Uri is checked by functions
+ * @return File path or null if file is missing
+ */
+ public static @Nullable String getFileProviderPath(@NonNull final Context context,
+ @NonNull final Uri uri)
+ {
+ final File appDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
+ final File file = new File(appDir, uri.getLastPathSegment());
+ return file.exists() ? file.toString(): null;
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/res/xml/provider_paths.xml b/android/src/main/res/xml/provider_paths.xml
new file mode 100644
index 000000000..4c87e9262
--- /dev/null
+++ b/android/src/main/res/xml/provider_paths.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file