55import android .util .Log ;
66import android .annotation .TargetApi ;
77import android .app .Activity ;
8+ import android .content .Context ;
89import android .os .Build ;
910import android .view .KeyEvent ;
1011import android .view .View ;
1718import android .webkit .WebView ;
1819import android .webkit .WebViewClient ;
1920import android .widget .FrameLayout ;
21+ import android .provider .MediaStore ;
22+ import android .support .v4 .content .FileProvider ;
2023
24+ import java .util .List ;
25+ import java .util .ArrayList ;
2126import java .util .HashMap ;
2227import java .util .Map ;
28+ import java .io .File ;
29+ import java .util .Date ;
30+ import java .io .IOException ;
31+ import java .text .SimpleDateFormat ;
2332
2433import io .flutter .plugin .common .MethodCall ;
2534import io .flutter .plugin .common .MethodChannel ;
@@ -35,6 +44,7 @@ class WebviewManager {
3544 private ValueCallback <Uri > mUploadMessage ;
3645 private ValueCallback <Uri []> mUploadMessageArray ;
3746 private final static int FILECHOOSER_RESULTCODE =1 ;
47+ private Uri fileUri ;
3848
3949 @ TargetApi (7 )
4050 class ResultHandler {
@@ -47,6 +57,8 @@ public boolean handleResult(int requestCode, int resultCode, Intent intent){
4757 String dataString = intent .getDataString ();
4858 if (dataString != null ){
4959 results = new Uri []{ Uri .parse (dataString ) };
60+ }else if (fileUri != null ){
61+ results = new Uri []{ fileUri };
5062 }
5163 }
5264 if (mUploadMessageArray != null ){
@@ -76,10 +88,12 @@ public boolean handleResult(int requestCode, int resultCode, Intent intent){
7688 WebView webView ;
7789 Activity activity ;
7890 ResultHandler resultHandler ;
91+ Context context ;
7992
80- WebviewManager (final Activity activity ) {
93+ WebviewManager (final Activity activity , final Context context ) {
8194 this .webView = new ObservableWebView (activity );
8295 this .activity = activity ;
96+ this .context = context ;
8397 this .resultHandler = new ResultHandler ();
8498 WebViewClient webViewClient = new BrowserClient ();
8599 webView .setOnKeyListener (new View .OnKeyListener () {
@@ -158,11 +172,29 @@ public boolean onShowFileChooser(
158172 }
159173 mUploadMessageArray = filePathCallback ;
160174
161- Intent contentSelectionIntent = new Intent (Intent .ACTION_GET_CONTENT );
162- contentSelectionIntent .addCategory (Intent .CATEGORY_OPENABLE );
163- contentSelectionIntent .setType ("*/*" );
164- Intent [] intentArray ;
165- intentArray = new Intent [0 ];
175+ final String [] acceptTypes = getSafeAcceptedTypes (fileChooserParams );
176+ List <Intent > intentList = new ArrayList <Intent >();
177+ if (acceptsImages (acceptTypes )) {
178+ Intent takePhotoIntent = new Intent (MediaStore .ACTION_IMAGE_CAPTURE );
179+ fileUri = getOutputFilename (MediaStore .ACTION_IMAGE_CAPTURE );
180+ takePhotoIntent .putExtra (MediaStore .EXTRA_OUTPUT , fileUri );
181+ intentList .add (takePhotoIntent );
182+ }
183+ if (acceptsVideo (acceptTypes )) {
184+ Intent takeVideoIntent = new Intent (MediaStore .ACTION_VIDEO_CAPTURE );
185+ fileUri = getOutputFilename (MediaStore .ACTION_VIDEO_CAPTURE );
186+ takeVideoIntent .putExtra (MediaStore .EXTRA_OUTPUT , fileUri );
187+ intentList .add (takeVideoIntent );
188+ }
189+ Intent contentSelectionIntent ;
190+ if (Build .VERSION .SDK_INT >= 21 ) {
191+ contentSelectionIntent = fileChooserParams .createIntent ();
192+ } else {
193+ contentSelectionIntent = new Intent (Intent .ACTION_GET_CONTENT );
194+ contentSelectionIntent .addCategory (Intent .CATEGORY_OPENABLE );
195+ contentSelectionIntent .setType ("*/*" );
196+ }
197+ Intent [] intentArray = intentList .toArray (new Intent [intentList .size ()]);
166198
167199 Intent chooserIntent = new Intent (Intent .ACTION_CHOOSER );
168200 chooserIntent .putExtra (Intent .EXTRA_INTENT , contentSelectionIntent );
@@ -174,6 +206,73 @@ public boolean onShowFileChooser(
174206 });
175207 }
176208
209+ private Uri getOutputFilename (String intentType ) {
210+ String prefix = "" ;
211+ String suffix = "" ;
212+
213+ if (intentType == MediaStore .ACTION_IMAGE_CAPTURE ) {
214+ prefix = "image-" ;
215+ suffix = ".jpg" ;
216+ } else if (intentType == MediaStore .ACTION_VIDEO_CAPTURE ) {
217+ prefix = "video-" ;
218+ suffix = ".mp4" ;
219+ }
220+
221+ String packageName = context .getPackageName ();
222+ File capturedFile = null ;
223+ try {
224+ capturedFile = createCapturedFile (prefix , suffix );
225+ } catch (IOException e ) {
226+ Log .e ("CREATE FILE" , "Error occurred while creating the File" , e );
227+ e .printStackTrace ();
228+ }
229+ return FileProvider .getUriForFile (context , packageName + ".fileprovider" , capturedFile );
230+ }
231+
232+ private File createCapturedFile (String prefix , String suffix ) throws IOException {
233+ String timeStamp = new SimpleDateFormat ("yyyyMMdd_HHmmss" ).format (new Date ());
234+ String imageFileName = prefix + "_" + timeStamp ;
235+ File storageDir = context .getExternalFilesDir (null );
236+ return File .createTempFile (imageFileName , suffix , storageDir );
237+ }
238+
239+ private Boolean acceptsImages (String [] types ) {
240+ return isArrayEmpty (types ) || arrayContainsString (types , "image" );
241+ }
242+
243+ private Boolean acceptsVideo (String [] types ) {
244+ return isArrayEmpty (types ) || arrayContainsString (types , "video" );
245+ }
246+
247+ private Boolean arrayContainsString (String [] array , String pattern ) {
248+ for (String content : array ) {
249+ if (content .contains (pattern )) {
250+ return true ;
251+ }
252+ }
253+ return false ;
254+ }
255+
256+ private Boolean isArrayEmpty (String [] arr ) {
257+ // when our array returned from getAcceptTypes() has no values set from the
258+ // webview
259+ // i.e. <input type="file" />, without any "accept" attr
260+ // will be an array with one empty string element, afaik
261+ return arr .length == 0 || (arr .length == 1 && arr [0 ].length () == 0 );
262+ }
263+
264+ private String [] getSafeAcceptedTypes (WebChromeClient .FileChooserParams params ) {
265+
266+ // the getAcceptTypes() is available only in api 21+
267+ // for lower level, we ignore it
268+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .LOLLIPOP ) {
269+ return params .getAcceptTypes ();
270+ }
271+
272+ final String [] EMPTY = {};
273+ return EMPTY ;
274+ }
275+
177276 private void clearCookies () {
178277 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .LOLLIPOP ) {
179278 CookieManager .getInstance ().removeAllCookies (new ValueCallback <Boolean >() {
0 commit comments