diff --git a/android/build.gradle b/android/build.gradle index ad0aaf26..a719a8e2 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -57,6 +57,6 @@ dependencies { //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" // From node_modules implementation 'io.github.lizhangqu:coreprogress:1.0.2' - implementation 'com.github.nomi9995:VideoCompressor:90adcba85a' + implementation 'com.github.nomi9995:VideoCompressor:4f72b53490' // implementation project(path: ':videocompressor') } diff --git a/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.java b/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.java new file mode 100644 index 00000000..aed43061 --- /dev/null +++ b/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.java @@ -0,0 +1,210 @@ +package com.reactnativecompressor.Utils; + +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 androidx.loader.content.CursorLoader; + +public class RealPathUtil { + + public static String getRealPath(Context context, Uri fileUri) { + String realPath; + // SDK < API11 + if (Build.VERSION.SDK_INT < 11) { + realPath = RealPathUtil.getRealPathFromURI_BelowAPI11(context, fileUri); + } + // SDK >= 11 && SDK < 19 + else if (Build.VERSION.SDK_INT < 19) { + realPath = RealPathUtil.getRealPathFromURI_API11to18(context, fileUri); + } + // SDK > 19 (Android 4.4) and up + else { + realPath = RealPathUtil.getRealPathFromURI_API19(context, fileUri); + } + return realPath; + } + + + @SuppressLint("NewApi") + public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) { + String[] proj = {MediaStore.Images.Media.DATA}; + String result = null; + + CursorLoader cursorLoader = new CursorLoader(context, contentUri, proj, null, null, null); + Cursor cursor = cursorLoader.loadInBackground(); + + if (cursor != null) { + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + result = cursor.getString(column_index); + cursor.close(); + } + return result; + } + + public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri) { + String[] proj = {MediaStore.Images.Media.DATA}; + Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null); + int column_index = 0; + String result = ""; + if (cursor != null) { + column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + result = cursor.getString(column_index); + cursor.close(); + return result; + } + return result; + } + + /** + * Get a file path from a Uri. This will get the the path for Storage Access + * Framework Documents, as well as the _data field for the MediaStore and + * other file-based ContentProviders. + * + * @param context The context. + * @param uri The Uri to query. + * @author paulburke + */ + @SuppressLint("NewApi") + public static String getRealPathFromURI_API19(final Context context, 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(); + + 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(Uri uri) { + return "com.google.android.apps.photos.content".equals(uri.getAuthority()); + } + +} diff --git a/android/src/main/java/com/reactnativecompressor/Utils/Utils.java b/android/src/main/java/com/reactnativecompressor/Utils/Utils.java index f77fdafe..9d46ca61 100644 --- a/android/src/main/java/com/reactnativecompressor/Utils/Utils.java +++ b/android/src/main/java/com/reactnativecompressor/Utils/Utils.java @@ -43,7 +43,14 @@ public void onFinish(boolean result) { @Override public void onError(String errorMessage) { - promise.reject("Compression has canncelled"); + if(errorMessage.equals(("class java.lang.AssertionError"))) + { + promise.resolve(srcPath); + } + else + { + promise.reject("Compression has canncelled"); + } } @Override diff --git a/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java b/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java index ac4ee78e..1da2ee65 100644 --- a/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java +++ b/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java @@ -1,5 +1,6 @@ package com.reactnativecompressor.Video; +import android.net.Uri; import android.util.Log; import androidx.annotation.NonNull; @@ -14,14 +15,17 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.modules.core.DeviceEventManagerModule; +import com.reactnativecompressor.Utils.RealPathUtil; import static com.reactnativecompressor.Video.VideoCompressorHelper.video_activateBackgroundTask_helper; import static com.reactnativecompressor.Video.VideoCompressorHelper.video_deactivateBackgroundTask_helper; import static com.reactnativecompressor.Video.VideoCompressorHelper.video_upload_helper; import static com.reactnativecompressor.Utils.Utils.cancelCompressionHelper; + @ReactModule(name = VideoModule.NAME) public class VideoModule extends ReactContextBaseJavaModule { public static final String NAME = "VideoCompressor"; + private static final String TAG = "react-native-compessor"; private final ReactApplicationContext reactContext; public VideoModule(ReactApplicationContext reactContext) { super(reactContext); @@ -50,6 +54,17 @@ public void compress( Promise promise) { final VideoCompressorHelper options = VideoCompressorHelper.fromMap(optionMap); + if(fileUrl.startsWith("content://")) + { + try { + Uri uri= Uri.parse(fileUrl); + fileUrl= RealPathUtil.getRealPath(reactContext,uri); + } + catch (Exception ex) { + Log.d(TAG, " Please see this issue: https://github.com/Shobbak/react-native-compressor/issues/25"); + } + } + if(options.compressionMethod==VideoCompressorHelper.CompressionMethod.auto) { VideoCompressorHelper.VideoCompressAuto(fileUrl,options,promise,reactContext); diff --git a/src/Video/index.tsx b/src/Video/index.tsx index a4f5d628..f85075a6 100644 --- a/src/Video/index.tsx +++ b/src/Video/index.tsx @@ -152,7 +152,7 @@ const Video: VideoCompressorType = { } else { modifiedOptions.maxSize = 640; } - if (options?.minimumFileSizeForCompress) { + if (options?.minimumFileSizeForCompress !== undefined) { modifiedOptions.minimumFileSizeForCompress = options?.minimumFileSizeForCompress; }