From 405e5f979f815564f2841579d52544890b7569fc Mon Sep 17 00:00:00 2001 From: Christofer Bodin Date: Thu, 10 Dec 2020 12:40:36 +0100 Subject: [PATCH 1/4] fix android intent chooser not showing camera/camcorder when all mime types are supported. --- .../InAppWebView/InAppWebViewChromeClient.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java index 7cf1fec26..6cee2869f 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java @@ -971,6 +971,20 @@ private Intent getFileChooserIntent(String[] acceptTypes, boolean allowMultiple) return intent; } + private Boolean acceptsAny(String[] types) { + if (isArrayEmpty(types)) { + return true; + } + + for (String type : types) { + if (type.equals("*/*")) { + return true; + } + } + + return false; + } + private Boolean acceptsImages(String types) { String mimeType = types; if (types.matches("\\.\\w+")) { @@ -981,7 +995,7 @@ private Boolean acceptsImages(String types) { private Boolean acceptsImages(String[] types) { String[] mimeTypes = getAcceptedMimeType(types); - return isArrayEmpty(mimeTypes) || arrayContainsString(mimeTypes, "image"); + return acceptsAny(types) || arrayContainsString(mimeTypes, "image"); } private Boolean acceptsVideo(String types) { @@ -994,7 +1008,7 @@ private Boolean acceptsVideo(String types) { private Boolean acceptsVideo(String[] types) { String[] mimeTypes = getAcceptedMimeType(types); - return isArrayEmpty(mimeTypes) || arrayContainsString(mimeTypes, "video"); + return acceptsAny(types) || arrayContainsString(mimeTypes, "video"); } private Boolean arrayContainsString(String[] array, String pattern) { From 69fd5c7d22dbd6a6086730b167edfc108ae550f1 Mon Sep 17 00:00:00 2001 From: Christofer Bodin Date: Thu, 10 Dec 2020 15:19:01 +0100 Subject: [PATCH 2/4] fix input fields accepting both images and videos getting a .mp4 file as a result --- .../InAppWebViewChromeClient.java | 78 ++++++++++++++----- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java index 6cee2869f..53b4babc9 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java @@ -3,9 +3,11 @@ import android.Manifest; import android.annotation.TargetApi; import android.app.Activity; +import android.content.ContentResolver; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; @@ -46,6 +48,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -72,7 +75,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR private static final int PICKER = 1; private static final int PICKER_LEGACY = 3; final String DEFAULT_MIME_TYPES = "*/*"; - private static Uri outputFileUri; + private static Uri videoOutputFileUri; + private static Uri imageOutputFileUri; protected static final FrameLayout.LayoutParams FULLSCREEN_LAYOUT_PARAMS = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER); @@ -810,28 +814,30 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { // this filename instead switch (requestCode) { case PICKER: - if (resultCode != RESULT_OK) { - if (InAppWebViewFlutterPlugin.filePathCallback != null) { - InAppWebViewFlutterPlugin.filePathCallback.onReceiveValue(null); - } - } else { - Uri result[] = this.getSelectedFiles(data, resultCode); - if (result != null) { - InAppWebViewFlutterPlugin.filePathCallback.onReceiveValue(result); - } else { - InAppWebViewFlutterPlugin.filePathCallback.onReceiveValue(new Uri[]{outputFileUri}); - } + Uri[] results = null; + if (resultCode == RESULT_OK) { + results = getSelectedFiles(data, resultCode); + } + + if (InAppWebViewFlutterPlugin.filePathCallback != null) { + InAppWebViewFlutterPlugin.filePathCallback.onReceiveValue(results); } break; + case PICKER_LEGACY: - Uri result = resultCode != Activity.RESULT_OK ? null : data == null ? outputFileUri : data.getData(); + Uri result = null; + if (resultCode == RESULT_OK) { + result = data != null ? data.getData() : getCapturedMediaFile(); + } + InAppWebViewFlutterPlugin.filePathCallbackLegacy.onReceiveValue(result); break; - } + InAppWebViewFlutterPlugin.filePathCallback = null; InAppWebViewFlutterPlugin.filePathCallbackLegacy = null; - outputFileUri = null; + imageOutputFileUri = null; + videoOutputFileUri = null; return true; } @@ -859,6 +865,40 @@ private Uri[] getSelectedFiles(Intent data, int resultCode) { } return result; } + + // we have a captured image or video file + Uri mediaUri = getCapturedMediaFile(); + if (mediaUri != null) { + return new Uri[]{mediaUri}; + } + + return null; + } + + private boolean isFileNotEmpty(Uri uri) { + Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity; + + long length; + try { + AssetFileDescriptor descriptor = activity.getContentResolver().openAssetFileDescriptor(uri, "r"); + length = descriptor.getLength(); + descriptor.close(); + } catch (IOException e) { + return false; + } + + return length > 0; + } + + private Uri getCapturedMediaFile() { + if (imageOutputFileUri != null && isFileNotEmpty(imageOutputFileUri)) { + return imageOutputFileUri; + } + + if (videoOutputFileUri != null && isFileNotEmpty(videoOutputFileUri)) { + return videoOutputFileUri; + } + return null; } @@ -935,15 +975,15 @@ protected boolean needsCameraPermission() { private Intent getPhotoIntent() { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - outputFileUri = getOutputUri(MediaStore.ACTION_IMAGE_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); + imageOutputFileUri = getOutputUri(MediaStore.ACTION_IMAGE_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, imageOutputFileUri); return intent; } private Intent getVideoIntent() { Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); - outputFileUri = getOutputUri(MediaStore.ACTION_VIDEO_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); + videoOutputFileUri = getOutputUri(MediaStore.ACTION_VIDEO_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, videoOutputFileUri); return intent; } From 4f316d5b549b945c5fafb13a90d79cc96aef8336 Mon Sep 17 00:00:00 2001 From: Christofer Bodin Date: Thu, 10 Dec 2020 20:30:22 +0100 Subject: [PATCH 3/4] fix selected files not returning any files when intent is null --- .../InAppWebView/InAppWebViewChromeClient.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java index 53b4babc9..34761ca44 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java @@ -843,12 +843,8 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { } private Uri[] getSelectedFiles(Intent data, int resultCode) { - if (data == null) { - return null; - } - // we have one file selected - if (data.getData() != null) { + if (data != null && data.getData() != null) { if (resultCode == RESULT_OK && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return WebChromeClient.FileChooserParams.parseResult(resultCode, data); } else { @@ -857,7 +853,7 @@ private Uri[] getSelectedFiles(Intent data, int resultCode) { } // we have multiple files selected - if (data.getClipData() != null) { + if (data != null && data.getClipData() != null) { final int numSelectedFiles = data.getClipData().getItemCount(); Uri[] result = new Uri[numSelectedFiles]; for (int i = 0; i < numSelectedFiles; i++) { From 14e3e8c40c82fd766e6633326778845d8adf8e06 Mon Sep 17 00:00:00 2001 From: Christofer Bodin Date: Thu, 10 Dec 2020 20:41:17 +0100 Subject: [PATCH 4/4] fix captured media filename having multiple suffixes --- .../InAppWebView/InAppWebViewChromeClient.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java index 34761ca44..b0e09bb42 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java @@ -1106,31 +1106,29 @@ private File getCapturedFile(String intentType) throws IOException { String prefix = ""; String suffix = ""; String dir = ""; - String filename = ""; if (intentType.equals(MediaStore.ACTION_IMAGE_CAPTURE)) { - prefix = "image-"; + prefix = "image"; suffix = ".jpg"; dir = Environment.DIRECTORY_PICTURES; } else if (intentType.equals(MediaStore.ACTION_VIDEO_CAPTURE)) { - prefix = "video-"; + prefix = "video"; suffix = ".mp4"; dir = Environment.DIRECTORY_MOVIES; } - filename = prefix + String.valueOf(System.currentTimeMillis()) + suffix; - // for versions below 6.0 (23) we use the old File creation & permissions model if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // only this Directory works on all tested Android versions // ctx.getExternalFilesDir(dir) was failing on Android 5.0 (sdk 21) File storageDir = Environment.getExternalStoragePublicDirectory(dir); + String filename = String.format("%s-%d%s", prefix, System.currentTimeMillis(), suffix); return new File(storageDir, filename); } Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity; File storageDir = activity.getApplicationContext().getExternalFilesDir(null); - return File.createTempFile(filename, suffix, storageDir); + return File.createTempFile(prefix, suffix, storageDir); } private Boolean isArrayEmpty(String[] arr) {