diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 5b28096..ccc450d 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -12,6 +12,7 @@
+
diff --git a/app/build.gradle b/app/build.gradle
index fb4ee2f..0568e02 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -64,4 +64,5 @@ dependencies {
implementation project(path: ':quick_android_webview')
implementation project(path: ':quick_android_custom_view')
implementation project(path: ':quick_android_easy_bar')
+ implementation project(path: ':quick_android_file_picker')
}
diff --git a/app/src/main/java/cn/qjm253/quick_android/MainActivity.kt b/app/src/main/java/cn/qjm253/quick_android/MainActivity.kt
index 745a04d..b6a024a 100644
--- a/app/src/main/java/cn/qjm253/quick_android/MainActivity.kt
+++ b/app/src/main/java/cn/qjm253/quick_android/MainActivity.kt
@@ -5,6 +5,7 @@ import android.os.Bundle
import cn.qjm253.quick_android.custom_view_demo.CustomViewDemoActivity
import cn.qjm253.quick_android.mvp_demo.MVPDemoActivity
import cn.qjm253.quick_android.webview_demo.WebViewDemo
+import cn.qjm253.quick_android_base.QuickAndroid
import cn.qjm253.quick_android_base.base.activity.BaseQuickAndroidActivity
import cn.qjm253.quick_android_base.extensions.*
import cn.qjm253.quick_android_base.util.ContentUriUtil
@@ -14,15 +15,18 @@ import cn.qjm253.quick_android_easy_bar.init
import cn.qjm253.quick_android_image_picker.openWechatStyleGallery
import cn.qjm253.quick_android_image_picker.startClipImage
import cn.qjm253.quick_android_qrcode.QuickAndroidQrCode
-import cn.qjm253.quick_android_qrcode.scanCode
import cn.qjm253.quick_android_rx_permission.QuickAndroidRxPermission
+import cn.qjm253.quick_android_rx_permission.createRxPermission
+import com.example.quick_android_file_picker.QuickAndroidFilePicker
+import com.example.quick_android_file_picker.createFilePicker
import com.qingmei2.rximagepicker_extension.MimeType
import com.qingmei2.rximagepicker_extension_wechat.WechatConfigrationBuilder
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : BaseQuickAndroidActivity() {
- val rxPermission = QuickAndroidRxPermission(this)
+ private val rxPermission = QuickAndroidRxPermission(this)
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
@@ -101,6 +105,28 @@ class MainActivity : BaseQuickAndroidActivity() {
btnCustomViewDemo.setOnClickListener {
jumpTo(CustomViewDemoActivity::class.java)
}
+
+ btnPickerFile.setOnClickListener {
+ QuickAndroid
+ .createRxPermission(this)
+ .request(
+ arrayOf(
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ )
+ )
+ .subscribe {
+ if (it.granted) {
+ checkMyPermission(Manifest.permission.READ_EXTERNAL_STORAGE, {
+ QuickAndroid
+ .createFilePicker(this)
+ .pickerFile()
+ .subscribe { fpr ->
+ toast(fpr.path)
+ }
+ })
+ }
+ }
+ }
}
// override fun onPermissionsGranted(requestCode: Int, perms: MutableList) {
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 46bff7d..5dbedb1 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -78,4 +78,16 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnWebviewDemo" />
+
+
\ No newline at end of file
diff --git a/quick_android_base/src/main/java/cn/qjm253/quick_android_base/util/ContentUriUtil.java b/quick_android_base/src/main/java/cn/qjm253/quick_android_base/util/ContentUriUtil.java
index 73613b9..69f6da2 100644
--- a/quick_android_base/src/main/java/cn/qjm253/quick_android_base/util/ContentUriUtil.java
+++ b/quick_android_base/src/main/java/cn/qjm253/quick_android_base/util/ContentUriUtil.java
@@ -1,5 +1,6 @@
package cn.qjm253.quick_android_base.util;
+import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
@@ -9,146 +10,357 @@
import android.provider.DocumentsContract;
import android.provider.MediaStore;
+import androidx.loader.content.CursorLoader;
+
+import java.io.File;
+
public class ContentUriUtil {
- /**
- * 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
- */
- public static String getPath(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());
- }
+ /**
+ * // * 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
+ * //
+ */
+// public static String getPath(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);
+// if (id.startsWith("raw:")) {
+// return uri.getPath();
+// }
+// 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());
+// }
+
+ private static String failReason;
+
+ static String errorReason() {
+ return failReason;
+ }
+
+ public static String getPath(final Context context, final Uri uri) {
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
+ return getRealPathFromURI_BelowAPI19(context, uri);
+ }
+ return getRealPathFromURI_API19(context, uri);
+ }
+
+
+ @SuppressLint("NewApi")
+ public static String getRealPathFromURI_API19(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)) {
+ if (split.length > 1) {
+ return Environment.getExternalStorageDirectory() + "/" + split[1];
+ } else {
+ return Environment.getExternalStorageDirectory() + "/";
+ }
+ } else {
+ return "storage" + "/" + docId.replace(":", "/");
+ }
+
+ } else if (isRawDownloadsDocument(uri)) {
+ String fileName = getFilePath(context, uri);
+ String subFolderName = getSubFolders(uri);
+
+ if (fileName != null) {
+ return Environment.getExternalStorageDirectory().toString() + "/Download/" + subFolderName + fileName;
+ }
+ 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);
+ } else if (isDownloadsDocument(uri)) {
+
+ System.out.println("downloadsDocument");
+ 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;
+ }
+ if (id.startsWith("raw%3A%2F")) {
+ id = id.replaceFirst("raw%3A%2F", "");
+ 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);
+ } 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())) {
+ if (isGooglePhotosUri(uri)) {
+ return uri.getLastPathSegment();
+ }
+ if (getDataColumn(context, uri, null, null) == null) {
+ failReason = "dataReturnedNull";
+ }
+ return getDataColumn(context, uri, null, null);
+ } else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return uri.getPath();
+ }
+
+ return null;
+ }
+
+ private static String getSubFolders(Uri uri) {
+ String replaceChars = String.valueOf(uri).replace("%2F", "/").replace("%20", " ").replace("%3A", ":");
+ String[] bits = replaceChars.split("/");
+ String sub5 = bits[bits.length - 2];
+ String sub4 = bits[bits.length - 3];
+ String sub3 = bits[bits.length - 4];
+ String sub2 = bits[bits.length - 5];
+ String sub1 = bits[bits.length - 6];
+ if (sub1.equals("Download")) {
+ return sub2 + "/" + sub3 + "/" + sub4 + "/" + sub5 + "/";
+ } else if (sub2.equals("Download")) {
+ return sub3 + "/" + sub4 + "/" + sub5 + "/";
+ } else if (sub3.equals("Download")) {
+ return sub4 + "/" + sub5 + "/";
+ } else if (sub4.equals("Download")) {
+ return sub5 + "/";
+ } else {
+ return "";
+ }
+ }
+
+ static String getRealPathFromURI_BelowAPI19(Context context, Uri contentUri) {
+ String[] proj = {MediaStore.Video.Media.DATA};
+ CursorLoader loader = new CursorLoader(context, contentUri, proj, null, null, null);
+ Cursor cursor = loader.loadInBackground();
+ assert cursor != null;
+ int column_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
+ cursor.moveToFirst();
+ String result = cursor.getString(column_index);
+ cursor.close();
+ return result;
+ }
+
+ @SuppressWarnings("TryFinallyCanBeTryWithResources")
+ 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 index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(index);
+ }
+ } catch (Exception e) {
+ failReason = e.getMessage();
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ return null;
+ }
+
+
+ @SuppressWarnings("TryFinallyCanBeTryWithResources")
+ private static String getFilePath(Context context, Uri uri) {
+ Cursor cursor = null;
+ final String[] projection = {MediaStore.Files.FileColumns.DISPLAY_NAME};
+ try {
+ cursor = context.getContentResolver().query(uri, projection, null, null,
+ null);
+ if (cursor != null && cursor.moveToFirst()) {
+ final int index = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME);
+ return cursor.getString(index);
+ }
+ } catch (Exception e) {
+ failReason = e.getMessage();
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ return null;
+ }
+
+
+ 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 isRawDownloadsDocument(Uri uri) {
+ String uriToString = String.valueOf(uri);
+ return uriToString.contains("com.android.providers.downloads.documents/document/raw");
+ }
+
+ 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.content".equals(uri.getAuthority());
+ }
}
\ No newline at end of file
diff --git a/quick_android_easy_bar/src/main/res/values/strings.xml b/quick_android_easy_bar/src/main/res/values/strings.xml
index 527871a..8542005 100644
--- a/quick_android_easy_bar/src/main/res/values/strings.xml
+++ b/quick_android_easy_bar/src/main/res/values/strings.xml
@@ -1,3 +1,2 @@
- quick_android_easy_bar
diff --git a/quick_android_file_picker/.gitignore b/quick_android_file_picker/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/quick_android_file_picker/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/quick_android_file_picker/build.gradle b/quick_android_file_picker/build.gradle
new file mode 100644
index 0000000..ae1af08
--- /dev/null
+++ b/quick_android_file_picker/build.gradle
@@ -0,0 +1,45 @@
+apply plugin: 'com.android.library'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+
+apply plugin: 'kotlin-kapt'
+
+android {
+ compileSdkVersion compile_sdk_version
+
+ defaultConfig {
+ minSdkVersion min_sdk_version
+ targetSdkVersion target_sdk_version
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "androidx.appcompat:appcompat:${appcompact_version}"
+ testImplementation "junit:junit:${junit_version}"
+ androidTestImplementation "androidx.test:runner:${test_runner_version}"
+ androidTestImplementation "androidx.test.espresso:espresso-core:${espresso_core_version}"
+
+ implementation project(path: ':quick_android_base')
+}
diff --git a/quick_android_file_picker/consumer-rules.pro b/quick_android_file_picker/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/quick_android_file_picker/proguard-rules.pro b/quick_android_file_picker/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/quick_android_file_picker/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/quick_android_file_picker/src/androidTest/java/com/example/quick_android_file_picker/ExampleInstrumentedTest.kt b/quick_android_file_picker/src/androidTest/java/com/example/quick_android_file_picker/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..2bbecd9
--- /dev/null
+++ b/quick_android_file_picker/src/androidTest/java/com/example/quick_android_file_picker/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.example.quick_android_file_picker
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.example.quick_android_file_picker.test", appContext.packageName)
+ }
+}
diff --git a/quick_android_file_picker/src/main/AndroidManifest.xml b/quick_android_file_picker/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..fac2a43
--- /dev/null
+++ b/quick_android_file_picker/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/quick_android_file_picker/src/main/java/com/example/quick_android_file_picker/QuickAndroidFilePicker.kt b/quick_android_file_picker/src/main/java/com/example/quick_android_file_picker/QuickAndroidFilePicker.kt
new file mode 100644
index 0000000..4a13da5
--- /dev/null
+++ b/quick_android_file_picker/src/main/java/com/example/quick_android_file_picker/QuickAndroidFilePicker.kt
@@ -0,0 +1,50 @@
+package com.example.quick_android_file_picker
+
+import androidx.annotation.RequiresPermission
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
+import androidx.fragment.app.FragmentManager
+import cn.qjm253.quick_android_base.QuickAndroid
+import cn.qjm253.quick_android_base.extensions.getLazySingleton
+import com.example.quick_android_file_picker.model.FilePickerResult
+import io.reactivex.Observable
+
+class QuickAndroidFilePicker(fragmentManager: FragmentManager) {
+ companion object {
+ const val TAG = "QuickAndroidFilePicker"
+
+ fun create(activity: FragmentActivity): QuickAndroidFilePicker {
+ return QuickAndroidFilePicker(activity.supportFragmentManager)
+ }
+
+ fun create(fragment: Fragment): QuickAndroidFilePicker {
+ return QuickAndroidFilePicker(fragment.childFragmentManager)
+ }
+ }
+
+ private var mRxAndroidFilePickerFragment: Lazy
+
+ init {
+ mRxAndroidFilePickerFragment =
+ fragmentManager.getLazySingleton(TAG, QuickAndroidFilePickerFragment::class.java)
+ }
+
+ @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
+ fun pickerFile(fileType: String = "*/*"): Observable {
+ return mRxAndroidFilePickerFragment
+ .value
+ .pickerFile(fileType)
+ }
+}
+
+//////////////////////////////////////////////////////////
+////////// QuickAndroid 扩展
+//////////////////////////////////////////////////////////
+
+fun QuickAndroid.createFilePicker(activity: FragmentActivity): QuickAndroidFilePicker {
+ return QuickAndroidFilePicker(activity.supportFragmentManager)
+}
+
+fun QuickAndroid.createFilePicker(fragment: Fragment): QuickAndroidFilePicker {
+ return QuickAndroidFilePicker(fragment.childFragmentManager)
+}
\ No newline at end of file
diff --git a/quick_android_file_picker/src/main/java/com/example/quick_android_file_picker/QuickAndroidFilePickerFragment.kt b/quick_android_file_picker/src/main/java/com/example/quick_android_file_picker/QuickAndroidFilePickerFragment.kt
new file mode 100644
index 0000000..249fa12
--- /dev/null
+++ b/quick_android_file_picker/src/main/java/com/example/quick_android_file_picker/QuickAndroidFilePickerFragment.kt
@@ -0,0 +1,49 @@
+package com.example.quick_android_file_picker
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.annotation.RequiresPermission
+import androidx.fragment.app.Fragment
+import cn.qjm253.quick_android_base.extensions.i
+import cn.qjm253.quick_android_base.util.ContentUriUtil
+import com.example.quick_android_file_picker.model.FilePickerResult
+import io.reactivex.Observable
+import io.reactivex.ObservableEmitter
+
+/**
+ * 这个fragment用于接收文件选择的结果
+ */
+class QuickAndroidFilePickerFragment : Fragment() {
+ private var emitter: ObservableEmitter? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ retainInstance = true
+ }
+
+ @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
+ fun pickerFile(fileType: String = "*/*"): Observable {
+ return Observable.create { _emitter ->
+ this.emitter = _emitter
+
+ // 调用系统的文件选择器
+ Intent(Intent.ACTION_GET_CONTENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = fileType
+ this@QuickAndroidFilePickerFragment.startActivityForResult(this, 0)
+ }
+ }
+
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ data?.data?.let {
+ it.path?.i()
+ val path = ContentUriUtil.getPath(context, it)
+ println(it.toString())
+ emitter?.onNext(FilePickerResult(path, it))
+ emitter?.onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/quick_android_file_picker/src/main/java/com/example/quick_android_file_picker/model/FilePickerResult.kt b/quick_android_file_picker/src/main/java/com/example/quick_android_file_picker/model/FilePickerResult.kt
new file mode 100644
index 0000000..352227f
--- /dev/null
+++ b/quick_android_file_picker/src/main/java/com/example/quick_android_file_picker/model/FilePickerResult.kt
@@ -0,0 +1,8 @@
+package com.example.quick_android_file_picker.model
+
+import android.net.Uri
+
+data class FilePickerResult (
+ val path: String,
+ val uri: Uri
+)
\ No newline at end of file
diff --git a/quick_android_file_picker/src/main/res/values/strings.xml b/quick_android_file_picker/src/main/res/values/strings.xml
new file mode 100644
index 0000000..8542005
--- /dev/null
+++ b/quick_android_file_picker/src/main/res/values/strings.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/quick_android_file_picker/src/test/java/com/example/quick_android_file_picker/ExampleUnitTest.kt b/quick_android_file_picker/src/test/java/com/example/quick_android_file_picker/ExampleUnitTest.kt
new file mode 100644
index 0000000..98c2794
--- /dev/null
+++ b/quick_android_file_picker/src/test/java/com/example/quick_android_file_picker/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.example.quick_android_file_picker
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
diff --git a/settings.gradle b/settings.gradle
index d4a1759..435ca4e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app', ':quick_android_base', ':quick_android_mvp', ':quick_android_qrcode', ':quick_android_image_picker', ':quick_android_webview', ':quick_android_rx_permission', ':quick_android_custom_view', ':quick_android_easy_bar'
+include ':app', ':quick_android_base', ':quick_android_mvp', ':quick_android_qrcode', ':quick_android_image_picker', ':quick_android_webview', ':quick_android_rx_permission', ':quick_android_custom_view', ':quick_android_easy_bar', ':quick_android_file_picker'