diff --git a/src/main/java/xyz/wbsite/dbtool/javafx/manger/callable/AndroidCallable.java b/src/main/java/xyz/wbsite/dbtool/javafx/manger/callable/AndroidCallable.java index da50de5c..b92083b6 100644 --- a/src/main/java/xyz/wbsite/dbtool/javafx/manger/callable/AndroidCallable.java +++ b/src/main/java/xyz/wbsite/dbtool/javafx/manger/callable/AndroidCallable.java @@ -149,6 +149,7 @@ public class AndroidCallable implements Callable { freeMarkerManager.outputTemp(new File(util, "StorageUtil.java"), "Android/app/src/main/java/base/util/StorageUtil.java", ctx); freeMarkerManager.outputTemp(new File(util, "Tasker.java"), "Android/app/src/main/java/base/util/Tasker.java", ctx); freeMarkerManager.outputTemp(new File(util, "Toaster.java"), "Android/app/src/main/java/base/util/Toaster.java", ctx); + freeMarkerManager.outputTemp(new File(util, "UriUtil.java"), "Android/app/src/main/java/base/util/UriUtil.java", ctx); } { diff --git a/src/main/resources/modules/Android/app/src/main/java/base/util/UriUtil.java b/src/main/resources/modules/Android/app/src/main/java/base/util/UriUtil.java new file mode 100644 index 00000000..3d6249c6 --- /dev/null +++ b/src/main/resources/modules/Android/app/src/main/java/base/util/UriUtil.java @@ -0,0 +1,154 @@ +package ${domain}.base.util; + +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; + +public class UriUtil { + /** + * 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()); + } +} diff --git a/src/main/resources/modules/Android/app/src/main/java/fragment/WebViewFragment.java b/src/main/resources/modules/Android/app/src/main/java/fragment/WebViewFragment.java index cbc21776..5dc5823a 100644 --- a/src/main/resources/modules/Android/app/src/main/java/fragment/WebViewFragment.java +++ b/src/main/resources/modules/Android/app/src/main/java/fragment/WebViewFragment.java @@ -1,23 +1,34 @@ package ${domain}.fragment; +import android.app.Activity; +import android.content.DialogInterface; +import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; +import android.net.Uri; import android.os.Build; +import android.os.Bundle; import android.util.Log; import android.view.View; import android.webkit.CookieManager; import android.webkit.CookieSyncManager; import android.webkit.JavascriptInterface; +import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; - import ${package}.R; +import ${domain}.WBUIApplication; import ${domain}.base.BaseSPAFragment; +import ${domain}.base.IActivityResult; +import ${domain}.base.activity.TakePhotoActivity; +import ${domain}.base.util.UriUtil; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; - +import com.qmuiteam.qmui.widget.dialog.QMUIBottomSheet; +import com.qmuiteam.qmui.widget.pullRefreshLayout.QMUIPullRefreshLayout; +import java.io.File; import butterknife.BindView; public class WebViewFragment extends BaseSPAFragment { @@ -96,7 +107,75 @@ public class WebViewFragment extends BaseSPAFragment { return super.shouldOverrideUrlLoading(view, url); } }); - webView.setWebChromeClient(new WebChromeClient()); + webView.setWebChromeClient(new WebChromeClient() { + @Override + public boolean onShowFileChooser(WebView webView, final ValueCallback filePathCallback, FileChooserParams fileChooserParams) { + String[] acceptTypes = fileChooserParams.getAcceptTypes(); + if (acceptTypes.length == 1){ + if (!"image/*".equals(acceptTypes[0])){ + //选择文件 + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + intent.addCategory(Intent.CATEGORY_OPENABLE); + startForResult(intent, new IActivityResult() { + @Override + public void onResult(int resultCode, Intent data) { + if (resultCode == Activity.RESULT_OK){ + Uri uri = data.getData(); + String path = UriUtil.getPath(getContext(), uri); + filePathCallback.onReceiveValue(new Uri[]{Uri.fromFile(new File(path))}); + }else { + filePathCallback.onReceiveValue(null); + } + } + }); + }else { + QMUIBottomSheet bottomSheet = new QMUIBottomSheet.BottomListSheetBuilder(getContext()) + .addItem("拍照") + .addItem("从相册选择") + .setOnSheetItemClickListener(new QMUIBottomSheet.BottomListSheetBuilder.OnSheetItemClickListener() { + @Override + public void onClick(QMUIBottomSheet dialog, View itemView, int position, String tag) { + dialog.dismiss(); + Intent intent = new Intent(getActivity(), TakePhotoActivity.class); + + switch (position) { + case 0: + intent.putExtra(TakePhotoActivity.POSITION_PARAM, TakePhotoActivity.POSITION_CAPTURE); + break; + case 1: + intent.putExtra(TakePhotoActivity.POSITION_PARAM, TakePhotoActivity.POSITION_GALLERY); + break; + default: + return; + } + + startForResult(intent, new IActivityResult() { + @Override + public void onResult(int resultCode, Intent data) { + if (resultCode == Activity.RESULT_OK) { + filePathCallback.onReceiveValue(new Uri[]{data.getData()}); + } else { + filePathCallback.onReceiveValue(null); + } + } + }); + } + }).build(); + + bottomSheet.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialogInterface) { + filePathCallback.onReceiveValue(null); + } + }); + bottomSheet.show(); + } + + } + return true; + } + }); webView.addJavascriptInterface(new AndroidInterface(), "android"); webView.loadUrl(url); }