diff --git a/android/build.gradle b/android/build.gradle
index 8a96c2d6..da473746 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -45,3 +45,6 @@ android {
disable 'InvalidPackage'
}
}
+dependencies {
+ implementation group: 'androidx.appcompat', name: 'appcompat', version: '1.0.0'
+}
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index b3b8fc6b..a9e05ce2 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -1,3 +1,16 @@
+
+
+
+
+
diff --git a/android/src/main/java/com/flutter_webview_plugin/FlutterWebviewPlugin.java b/android/src/main/java/com/flutter_webview_plugin/FlutterWebviewPlugin.java
index 65b7e947..53c51434 100644
--- a/android/src/main/java/com/flutter_webview_plugin/FlutterWebviewPlugin.java
+++ b/android/src/main/java/com/flutter_webview_plugin/FlutterWebviewPlugin.java
@@ -24,18 +24,20 @@
public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.ActivityResultListener {
private Activity activity;
private WebviewManager webViewManager;
+ private Context context;
static MethodChannel channel;
private static final String CHANNEL_NAME = "flutter_webview_plugin";
public static void registerWith(PluginRegistry.Registrar registrar) {
channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
- final FlutterWebviewPlugin instance = new FlutterWebviewPlugin(registrar.activity());
+ final FlutterWebviewPlugin instance = new FlutterWebviewPlugin(registrar.activity(),registrar.activeContext());
registrar.addActivityResultListener(instance);
channel.setMethodCallHandler(instance);
}
- private FlutterWebviewPlugin(Activity activity) {
+ private FlutterWebviewPlugin(Activity activity, Context context) {
this.activity = activity;
+ this.context = context;
}
@Override
@@ -102,7 +104,7 @@ private void openUrl(MethodCall call, MethodChannel.Result result) {
boolean geolocationEnabled = call.argument("geolocationEnabled");
if (webViewManager == null || webViewManager.closed == true) {
- webViewManager = new WebviewManager(activity);
+ webViewManager = new WebviewManager(activity, context);
}
FrameLayout.LayoutParams params = buildLayoutParams(call);
diff --git a/android/src/main/java/com/flutter_webview_plugin/WebviewManager.java b/android/src/main/java/com/flutter_webview_plugin/WebviewManager.java
index 1d167e6f..d18a8653 100644
--- a/android/src/main/java/com/flutter_webview_plugin/WebviewManager.java
+++ b/android/src/main/java/com/flutter_webview_plugin/WebviewManager.java
@@ -4,6 +4,7 @@
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.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 mUploadMessage;
private ValueCallback 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 @@ public boolean handleResult(int requestCode, int resultCode, Intent intent){
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 @@ public boolean handleResult(int requestCode, int resultCode, Intent intent){
}
}
+ 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 @@ public boolean onShowFileChooser(
}
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 intentList = new ArrayList();
+ 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 @@ public boolean onShowFileChooser(
});
}
+ 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. , 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() {
diff --git a/android/src/main/res/xml/filepaths.xml b/android/src/main/res/xml/filepaths.xml
new file mode 100644
index 00000000..43f25539
--- /dev/null
+++ b/android/src/main/res/xml/filepaths.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+