diff --git a/app b/app index e74a419f..2f0014be 160000 --- a/app +++ b/app @@ -1 +1 @@ -Subproject commit e74a419ffd5b0a078a9f30da2dd8442556188392 +Subproject commit 2f0014be080a5d691ef59934a12ca8f88c6c092e diff --git a/p4a/pythonforandroid/bootstraps/lbry/build/templates/build.tmpl.gradle b/p4a/pythonforandroid/bootstraps/lbry/build/templates/build.tmpl.gradle index de156ff5..23c4e407 100644 --- a/p4a/pythonforandroid/bootstraps/lbry/build/templates/build.tmpl.gradle +++ b/p4a/pythonforandroid/bootstraps/lbry/build/templates/build.tmpl.gradle @@ -106,7 +106,6 @@ subprojects { dependencies { compile project(':@react-native-community_async-storage') compile project(':react-native-camera') - compile project(':react-native-document-picker') compile project(':react-native-exception-handler') compile project(':react-native-fast-image') compile project(':react-native-fs') diff --git a/p4a/pythonforandroid/bootstraps/lbry/build/templates/build.tmpl.gradle.arm b/p4a/pythonforandroid/bootstraps/lbry/build/templates/build.tmpl.gradle.arm index b031079d..cbab6435 100644 --- a/p4a/pythonforandroid/bootstraps/lbry/build/templates/build.tmpl.gradle.arm +++ b/p4a/pythonforandroid/bootstraps/lbry/build/templates/build.tmpl.gradle.arm @@ -106,7 +106,6 @@ subprojects { dependencies { compile project(':@react-native-community_async-storage') compile project(':react-native-camera') - compile project(':react-native-document-picker') compile project(':react-native-exception-handler') compile project(':react-native-fast-image') compile project(':react-native-fs') diff --git a/p4a/pythonforandroid/bootstraps/lbry/build/templates/settings.gradle b/p4a/pythonforandroid/bootstraps/lbry/build/templates/settings.gradle index d874c600..b2010967 100644 --- a/p4a/pythonforandroid/bootstraps/lbry/build/templates/settings.gradle +++ b/p4a/pythonforandroid/bootstraps/lbry/build/templates/settings.gradle @@ -3,8 +3,6 @@ include ':@react-native-community_async-storage' project(':@react-native-community_async-storage').projectDir = new File(rootProject.projectDir, './react/node_modules/@react-native-community/async-storage/android') include ':react-native-camera' project(':react-native-camera').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-camera/android') -include ':react-native-document-picker' -project(':react-native-document-picker').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-document-picker/android') include ':react-native-exception-handler' project(':react-native-exception-handler').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-exception-handler/android') include ':react-native-fast-image' diff --git a/src/main/java/io/lbry/browser/MainActivity.java b/src/main/java/io/lbry/browser/MainActivity.java index 6df7994f..eeb5d7fe 100644 --- a/src/main/java/io/lbry/browser/MainActivity.java +++ b/src/main/java/io/lbry/browser/MainActivity.java @@ -1,18 +1,24 @@ package io.lbry.browser; +import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.app.Activity; import android.app.ActivityManager; import android.content.BroadcastReceiver; +import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.SharedPreferences; +import android.database.Cursor; import android.Manifest; import android.net.Uri; +import android.provider.DocumentsContract; +import android.provider.MediaStore; import android.provider.Settings; import android.support.v4.app.ActivityCompat; import android.support.v4.app.NotificationManagerCompat; @@ -37,7 +43,6 @@ import com.facebook.react.modules.core.PermissionListener; import com.facebook.react.shell.MainReactPackage; import com.facebook.react.ReactRootView; import com.reactnativecommunity.asyncstorage.AsyncStoragePackage; -import io.github.elyx0.reactnativedocumentpicker.DocumentPickerPackage; import com.rnfs.RNFSPackage; import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView; import com.swmansion.gesturehandler.react.RNGestureHandlerPackage; @@ -47,8 +52,10 @@ import com.RNFetchBlob.RNFetchBlobPackage; import io.lbry.browser.reactpackages.LbryReactPackage; import io.lbry.browser.reactmodules.BackgroundMediaModule; +import java.io.File; import java.io.UnsupportedEncodingException; import java.math.BigInteger; +import java.net.URISyntaxException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; @@ -73,6 +80,8 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand private static final int PHONE_STATE_PERMISSION_REQ_CODE = 202; private static final int RECEIVE_SMS_PERMISSION_REQ_CODE = 203; + + public static final int DOCUMENT_PICKER_RESULT_CODE = 301; private BroadcastReceiver notificationsReceiver; @@ -148,7 +157,6 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand .addPackage(new MainReactPackage()) .addPackage(new AsyncStoragePackage()) .addPackage(new FastImageViewPackage()) - .addPackage(new DocumentPickerPackage()) .addPackage(new ReactVideoPackage()) .addPackage(new ReanimatedPackage()) .addPackage(new RNCameraPackage()) @@ -289,7 +297,7 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand }; registerReceiver(smsReceiver, smsFilter); } - + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == OVERLAY_PERMISSION_REQ_CODE) { @@ -299,6 +307,26 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand } } } + + if (requestCode == DOCUMENT_PICKER_RESULT_CODE) { + ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); + if (reactContext != null) { + if (resultCode == RESULT_OK) { + Uri fileUri = data.getData(); + String filePath = getRealPathFromURI_API19(this, fileUri); + android.util.Log.d("ReactNativeJS", "fileUri=" + filePath); + + WritableMap params = Arguments.createMap(); + params.putString("path", filePath); + reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit("onDocumentPickerFilePicked", params); + } else if (resultCode == RESULT_CANCELED) { + // user canceled or request failed + reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit("onDocumentPickerCanceled", null); + } + } + } } public static Activity getActivity() { @@ -611,4 +639,161 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand return array; } + + /** + * https://gist.github.com/HBiSoft/15899990b8cd0723c3a894c1636550a8 + */ + @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]; + + // This is for checking Main Memory + if ("primary".equalsIgnoreCase(type)) { + if (split.length > 1) { + return Environment.getExternalStorageDirectory() + "/" + split[1]; + } else { + return Environment.getExternalStorageDirectory() + "/"; + } + // This is for checking SD Card + } else { + return "storage" + "/" + docId.replace(":", "/"); + } + + } + // DownloadsProvider + else if (isDownloadsDocument(uri)) { + String fileName = getFilePath(context, uri); + if (fileName != null) { + return Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName; + } + + String id = DocumentsContract.getDocumentId(uri); + if (id.startsWith("raw:")) { + id = id.replaceFirst("raw:", ""); + File file = new File(id); + if (file.exists()) + return id; + } + + 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; + } + + 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; + } + + + public static String getFilePath(Context context, Uri uri) { + Cursor cursor = null; + final String[] projection = { MediaStore.MediaColumns.DISPLAY_NAME }; + + try { + cursor = context.getContentResolver().query(uri, projection, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + final int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME); + 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/src/main/java/io/lbry/browser/reactmodules/UtilityModule.java b/src/main/java/io/lbry/browser/reactmodules/UtilityModule.java index c48c0eae..f6e46bd0 100644 --- a/src/main/java/io/lbry/browser/reactmodules/UtilityModule.java +++ b/src/main/java/io/lbry/browser/reactmodules/UtilityModule.java @@ -354,4 +354,15 @@ public class UtilityModule extends ReactContextBaseJavaModule { context.sendBroadcast(intent); } } + + @ReactMethod + public void openDocumentPicker(String type) { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.setType(type); + Activity activity = MainActivity.getActivity(); + if (activity != null) { + activity.startActivityForResult( + Intent.createChooser(intent, "Select a file"), MainActivity.DOCUMENT_PICKER_RESULT_CODE); + } + } }