|
|
@@ -4,6 +4,7 @@ import android.content.Intent;
|
|
|
import android.net.Uri;
|
|
|
import android.annotation.TargetApi;
|
|
|
import android.app.Activity;
|
|
|
+import android.content.Context;
|
|
|
import android.os.Build;
|
|
|
import android.view.KeyEvent;
|
|
|
import android.view.View;
|
|
|
@@ -15,9 +16,19 @@ import android.webkit.WebChromeClient;
|
|
|
import android.webkit.WebSettings;
|
|
|
import android.webkit.WebView;
|
|
|
import android.widget.FrameLayout;
|
|
|
+import android.provider.MediaStore;
|
|
|
+import androidx.core.content.FileProvider;
|
|
|
+import android.database.Cursor;
|
|
|
+import android.provider.OpenableColumns;
|
|
|
|
|
|
+import java.util.List;
|
|
|
+import java.util.ArrayList;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
|
+import java.io.File;
|
|
|
+import java.util.Date;
|
|
|
+import java.io.IOException;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
|
|
|
import io.flutter.plugin.common.MethodCall;
|
|
|
import io.flutter.plugin.common.MethodChannel;
|
|
|
@@ -33,6 +44,15 @@ class WebviewManager {
|
|
|
private ValueCallback<Uri> mUploadMessage;
|
|
|
private ValueCallback<Uri[]> mUploadMessageArray;
|
|
|
private final static int FILECHOOSER_RESULTCODE=1;
|
|
|
+ private Uri fileUri;
|
|
|
+ private Uri videoUri;
|
|
|
+
|
|
|
+ private long getFileSize(Uri fileUri) {
|
|
|
+ Cursor returnCursor = context.getContentResolver().query(fileUri, null, null, null, null);
|
|
|
+ returnCursor.moveToFirst();
|
|
|
+ int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
|
|
|
+ return returnCursor.getLong(sizeIndex);
|
|
|
+ }
|
|
|
|
|
|
@TargetApi(7)
|
|
|
class ResultHandler {
|
|
|
@@ -41,10 +61,13 @@ class WebviewManager {
|
|
|
if(Build.VERSION.SDK_INT >= 21){
|
|
|
if(requestCode == FILECHOOSER_RESULTCODE){
|
|
|
Uri[] results = null;
|
|
|
- if(resultCode == Activity.RESULT_OK && intent != null){
|
|
|
- String dataString = intent.getDataString();
|
|
|
- if(dataString != null){
|
|
|
- results = new Uri[]{ Uri.parse(dataString) };
|
|
|
+ if (resultCode == Activity.RESULT_OK) {
|
|
|
+ if (fileUri != null && getFileSize(fileUri) > 0) {
|
|
|
+ results = new Uri[] { fileUri };
|
|
|
+ } else if (videoUri != null && getFileSize(videoUri) > 0) {
|
|
|
+ results = new Uri[] { videoUri };
|
|
|
+ } else if (intent != null) {
|
|
|
+ results = getSelectedFiles(intent);
|
|
|
}
|
|
|
}
|
|
|
if(mUploadMessageArray != null){
|
|
|
@@ -70,15 +93,37 @@ class WebviewManager {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private Uri[] getSelectedFiles(Intent data) {
|
|
|
+ // we have one files selected
|
|
|
+ if (data.getData() != null) {
|
|
|
+ String dataString = data.getDataString();
|
|
|
+ if(dataString != null){
|
|
|
+ return new Uri[]{ Uri.parse(dataString) };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // we have multiple files selected
|
|
|
+ if (data.getClipData() != null) {
|
|
|
+ final int numSelectedFiles = data.getClipData().getItemCount();
|
|
|
+ Uri[] result = new Uri[numSelectedFiles];
|
|
|
+ for (int i = 0; i < numSelectedFiles; i++) {
|
|
|
+ result[i] = data.getClipData().getItemAt(i).getUri();
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
boolean closed = false;
|
|
|
WebView webView;
|
|
|
Activity activity;
|
|
|
BrowserClient webViewClient;
|
|
|
ResultHandler resultHandler;
|
|
|
+ Context context;
|
|
|
|
|
|
- WebviewManager(final Activity activity) {
|
|
|
+ WebviewManager(final Activity activity, final Context context) {
|
|
|
this.webView = new ObservableWebView(activity);
|
|
|
this.activity = activity;
|
|
|
+ this.context = context;
|
|
|
this.resultHandler = new ResultHandler();
|
|
|
webViewClient = new BrowserClient();
|
|
|
webView.setOnKeyListener(new View.OnKeyListener() {
|
|
|
@@ -157,15 +202,36 @@ class WebviewManager {
|
|
|
}
|
|
|
mUploadMessageArray = filePathCallback;
|
|
|
|
|
|
- Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
|
- contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
|
- contentSelectionIntent.setType("*/*");
|
|
|
- Intent[] intentArray;
|
|
|
- intentArray = new Intent[0];
|
|
|
+ final String[] acceptTypes = getSafeAcceptedTypes(fileChooserParams);
|
|
|
+ List<Intent> intentList = new ArrayList<Intent>();
|
|
|
+ fileUri = null;
|
|
|
+ videoUri = null;
|
|
|
+ if (acceptsImages(acceptTypes)) {
|
|
|
+ Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
|
|
+ fileUri = getOutputFilename(MediaStore.ACTION_IMAGE_CAPTURE);
|
|
|
+ takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
|
|
|
+ intentList.add(takePhotoIntent);
|
|
|
+ }
|
|
|
+ if (acceptsVideo(acceptTypes)) {
|
|
|
+ Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
|
|
|
+ videoUri = getOutputFilename(MediaStore.ACTION_VIDEO_CAPTURE);
|
|
|
+ takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, videoUri);
|
|
|
+ intentList.add(takeVideoIntent);
|
|
|
+ }
|
|
|
+ Intent contentSelectionIntent;
|
|
|
+ if (Build.VERSION.SDK_INT >= 21) {
|
|
|
+ final boolean allowMultiple = fileChooserParams.getMode() == FileChooserParams.MODE_OPEN_MULTIPLE;
|
|
|
+ contentSelectionIntent = fileChooserParams.createIntent();
|
|
|
+ contentSelectionIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultiple);
|
|
|
+ } else {
|
|
|
+ contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
|
+ contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
|
+ contentSelectionIntent.setType("*/*");
|
|
|
+ }
|
|
|
+ Intent[] intentArray = intentList.toArray(new Intent[intentList.size()]);
|
|
|
|
|
|
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
|
|
|
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
|
|
|
- chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
|
|
|
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
|
|
|
activity.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
|
|
|
return true;
|
|
|
@@ -173,6 +239,72 @@ class WebviewManager {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ private Uri getOutputFilename(String intentType) {
|
|
|
+ String prefix = "";
|
|
|
+ String suffix = "";
|
|
|
+
|
|
|
+ if (intentType == MediaStore.ACTION_IMAGE_CAPTURE) {
|
|
|
+ prefix = "image-";
|
|
|
+ suffix = ".jpg";
|
|
|
+ } else if (intentType == MediaStore.ACTION_VIDEO_CAPTURE) {
|
|
|
+ prefix = "video-";
|
|
|
+ suffix = ".mp4";
|
|
|
+ }
|
|
|
+
|
|
|
+ String packageName = context.getPackageName();
|
|
|
+ File capturedFile = null;
|
|
|
+ try {
|
|
|
+ capturedFile = createCapturedFile(prefix, suffix);
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return FileProvider.getUriForFile(context, packageName + ".fileprovider", capturedFile);
|
|
|
+ }
|
|
|
+
|
|
|
+ private File createCapturedFile(String prefix, String suffix) throws IOException {
|
|
|
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
|
|
+ String imageFileName = prefix + "_" + timeStamp;
|
|
|
+ File storageDir = context.getExternalFilesDir(null);
|
|
|
+ return File.createTempFile(imageFileName, suffix, storageDir);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Boolean acceptsImages(String[] types) {
|
|
|
+ return isArrayEmpty(types) || arrayContainsString(types, "image");
|
|
|
+ }
|
|
|
+
|
|
|
+ private Boolean acceptsVideo(String[] types) {
|
|
|
+ return isArrayEmpty(types) || arrayContainsString(types, "video");
|
|
|
+ }
|
|
|
+
|
|
|
+ private Boolean arrayContainsString(String[] array, String pattern) {
|
|
|
+ for (String content : array) {
|
|
|
+ if (content.contains(pattern)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Boolean isArrayEmpty(String[] arr) {
|
|
|
+ // when our array returned from getAcceptTypes() has no values set from the
|
|
|
+ // webview
|
|
|
+ // i.e. <input type="file" />, without any "accept" attr
|
|
|
+ // will be an array with one empty string element, afaik
|
|
|
+ return arr.length == 0 || (arr.length == 1 && arr[0].length() == 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String[] getSafeAcceptedTypes(WebChromeClient.FileChooserParams params) {
|
|
|
+
|
|
|
+ // the getAcceptTypes() is available only in api 21+
|
|
|
+ // for lower level, we ignore it
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
|
+ return params.getAcceptTypes();
|
|
|
+ }
|
|
|
+
|
|
|
+ final String[] EMPTY = {};
|
|
|
+ return EMPTY;
|
|
|
+ }
|
|
|
+
|
|
|
private void clearCookies() {
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
|
CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
|