@@ -18,18 +18,22 @@ Licensed to the Apache Software Foundation (ASF) under one
18
18
*/
19
19
package org .apache .cordova .engine ;
20
20
21
+ import java .io .IOException ;
22
+ import java .io .File ;
21
23
import java .util .Arrays ;
22
- import android .annotation .TargetApi ;
24
+ import java .util .ArrayList ;
25
+ import java .util .List ;
23
26
import android .app .Activity ;
27
+ import android .content .ClipData ;
24
28
import android .content .Context ;
25
29
import android .content .ActivityNotFoundException ;
26
30
import android .content .Intent ;
31
+ import android .content .pm .PackageManager ;
27
32
import android .net .Uri ;
28
- import android .os . Build ;
33
+ import android .provider . MediaStore ;
29
34
import android .view .Gravity ;
30
35
import android .view .View ;
31
36
import android .view .ViewGroup .LayoutParams ;
32
- import android .webkit .ConsoleMessage ;
33
37
import android .webkit .GeolocationPermissions .Callback ;
34
38
import android .webkit .JsPromptResult ;
35
39
import android .webkit .JsResult ;
@@ -41,6 +45,7 @@ Licensed to the Apache Software Foundation (ASF) under one
41
45
import android .widget .LinearLayout ;
42
46
import android .widget .ProgressBar ;
43
47
import android .widget .RelativeLayout ;
48
+ import androidx .core .content .FileProvider ;
44
49
45
50
import org .apache .cordova .CordovaDialogsHelper ;
46
51
import org .apache .cordova .CordovaPlugin ;
@@ -212,53 +217,110 @@ public View getVideoLoadingProgressView() {
212
217
}
213
218
214
219
@ Override
215
- public boolean onShowFileChooser (WebView webView , final ValueCallback <Uri []> filePathsCallback , final WebChromeClient .FileChooserParams fileChooserParams ) {
220
+ public boolean onShowFileChooser (WebView webView , final ValueCallback <Uri []> filePathsCallback ,
221
+ final WebChromeClient .FileChooserParams fileChooserParams ) {
222
+ Intent fileIntent = fileChooserParams .createIntent ();
223
+
216
224
// Check if multiple-select is specified
217
225
Boolean selectMultiple = false ;
218
226
if (fileChooserParams .getMode () == WebChromeClient .FileChooserParams .MODE_OPEN_MULTIPLE ) {
219
227
selectMultiple = true ;
220
228
}
221
- Intent intent = fileChooserParams .createIntent ();
222
- intent .putExtra (Intent .EXTRA_ALLOW_MULTIPLE , selectMultiple );
223
-
229
+ fileIntent .putExtra (Intent .EXTRA_ALLOW_MULTIPLE , selectMultiple );
230
+
224
231
// Uses Intent.EXTRA_MIME_TYPES to pass multiple mime types.
225
232
String [] acceptTypes = fileChooserParams .getAcceptTypes ();
226
233
if (acceptTypes .length > 1 ) {
227
- intent .setType ("*/*" ); // Accept all, filter mime types by Intent.EXTRA_MIME_TYPES.
228
- intent .putExtra (Intent .EXTRA_MIME_TYPES , acceptTypes );
234
+ fileIntent .setType ("*/*" ); // Accept all, filter mime types by Intent.EXTRA_MIME_TYPES.
235
+ fileIntent .putExtra (Intent .EXTRA_MIME_TYPES , acceptTypes );
236
+ }
237
+
238
+ // Image from camera intent
239
+ Uri tempUri = null ;
240
+ Intent captureIntent = null ;
241
+ if (fileChooserParams .isCaptureEnabled ()) {
242
+ captureIntent = new Intent (MediaStore .ACTION_IMAGE_CAPTURE );
243
+ Context context = parentEngine .getView ().getContext ();
244
+ if (context .getPackageManager ().hasSystemFeature (PackageManager .FEATURE_CAMERA_ANY )
245
+ && captureIntent .resolveActivity (context .getPackageManager ()) != null ) {
246
+ try {
247
+ File tempFile = createTempFile (context );
248
+ LOG .d (LOG_TAG , "Temporary photo capture file: " + tempFile );
249
+ tempUri = createUriForFile (context , tempFile );
250
+ LOG .d (LOG_TAG , "Temporary photo capture URI: " + tempUri );
251
+ captureIntent .putExtra (MediaStore .EXTRA_OUTPUT , tempUri );
252
+ } catch (IOException e ) {
253
+ LOG .e (LOG_TAG , "Unable to create temporary file for photo capture" , e );
254
+ captureIntent = null ;
255
+ }
256
+ } else {
257
+ LOG .w (LOG_TAG , "Device does not support photo capture" );
258
+ captureIntent = null ;
259
+ }
260
+ }
261
+ final Uri captureUri = tempUri ;
262
+
263
+ // Chooser intent
264
+ Intent chooserIntent = Intent .createChooser (fileIntent , null );
265
+ if (captureIntent != null ) {
266
+ chooserIntent .putExtra (Intent .EXTRA_INITIAL_INTENTS , new Intent [] { captureIntent });
229
267
}
268
+
230
269
try {
270
+ LOG .i (LOG_TAG , "Starting intent for file chooser" );
231
271
parentEngine .cordova .startActivityForResult (new CordovaPlugin () {
232
272
@ Override
233
273
public void onActivityResult (int requestCode , int resultCode , Intent intent ) {
274
+ // Handle result
234
275
Uri [] result = null ;
235
- if (resultCode == Activity .RESULT_OK && intent != null ) {
236
- if (intent .getClipData () != null ) {
237
- // handle multiple-selected files
238
- final int numSelectedFiles = intent .getClipData ().getItemCount ();
239
- result = new Uri [numSelectedFiles ];
240
- for (int i = 0 ; i < numSelectedFiles ; i ++) {
241
- result [i ] = intent .getClipData ().getItemAt (i ).getUri ();
242
- LOG .d (LOG_TAG , "Receive file chooser URL: " + result [i ]);
276
+ if (resultCode == Activity .RESULT_OK ) {
277
+ List <Uri > uris = new ArrayList <Uri >();
278
+
279
+ if (intent != null && intent .getData () != null ) { // single file
280
+ LOG .v (LOG_TAG , "Adding file (single): " + intent .getData ());
281
+ uris .add (intent .getData ());
282
+ } else if (captureUri != null ) { // camera
283
+ LOG .v (LOG_TAG , "Adding camera capture: " + captureUri );
284
+ uris .add (captureUri );
285
+ } else if (intent != null && intent .getClipData () != null ) { // multiple files
286
+ ClipData clipData = intent .getClipData ();
287
+ int count = clipData .getItemCount ();
288
+ for (int i = 0 ; i < count ; i ++) {
289
+ Uri uri = clipData .getItemAt (i ).getUri ();
290
+ LOG .v (LOG_TAG , "Adding file (multiple): " + uri );
291
+ if (uri != null ) {
292
+ uris .add (uri );
293
+ }
243
294
}
244
295
}
245
- else if ( intent . getData () != null ) {
246
- // handle single-selected file
247
- result = WebChromeClient . FileChooserParams . parseResult ( resultCode , intent );
248
- LOG . d ( LOG_TAG , "Receive file chooser URL: " + result );
296
+
297
+ if (! uris . isEmpty ()) {
298
+ LOG . d ( LOG_TAG , "Receive file chooser URL: " + uris . toString () );
299
+ result = uris . toArray ( new Uri [ uris . size ()] );
249
300
}
250
301
}
251
302
filePathsCallback .onReceiveValue (result );
252
303
}
253
- }, intent , FILECHOOSER_RESULTCODE );
304
+ }, chooserIntent , FILECHOOSER_RESULTCODE );
254
305
} catch (ActivityNotFoundException e ) {
255
- LOG .w ("No activity found to handle file chooser intent." , e );
306
+ LOG .w (LOG_TAG , "No activity found to handle file chooser intent." , e );
256
307
filePathsCallback .onReceiveValue (null );
257
308
}
258
309
return true ;
259
310
}
260
311
261
- @ Override
312
+ private File createTempFile (Context context ) throws IOException {
313
+ // Create an image file name
314
+ File tempFile = File .createTempFile ("temp" , ".jpg" , context .getCacheDir ());
315
+ return tempFile ;
316
+ }
317
+
318
+ private Uri createUriForFile (Context context , File tempFile ) throws IOException {
319
+ String appId = context .getPackageName ();
320
+ Uri uri = FileProvider .getUriForFile (context , appId + ".cdv.core.file.provider" , tempFile );
321
+ return uri ;
322
+ }
323
+
262
324
public void onPermissionRequest (final PermissionRequest request ) {
263
325
LOG .d (LOG_TAG , "onPermissionRequest: " + Arrays .toString (request .getResources ()));
264
326
request .grant (request .getResources ());
0 commit comments