@@ -23,9 +23,11 @@ Licensed to the Apache Software Foundation (ASF) under one
23
23
import java .lang .reflect .Field ;
24
24
import java .lang .reflect .InvocationTargetException ;
25
25
import java .lang .reflect .Method ;
26
+ import java .text .SimpleDateFormat ;
26
27
import java .util .ArrayList ;
27
28
import java .util .Arrays ;
28
29
import java .util .List ;
30
+ import java .util .Date ;
29
31
30
32
import org .apache .cordova .CallbackContext ;
31
33
import org .apache .cordova .CordovaPlugin ;
@@ -93,15 +95,11 @@ public class Capture extends CordovaPlugin {
93
95
private final PendingRequests pendingRequests = new PendingRequests ();
94
96
95
97
private int numPics ; // Number of pictures before capture activity
96
- private Uri imageUri ;
98
+ private String audioAbsolutePath ;
99
+ private String imageAbsolutePath ;
100
+ private String videoAbsolutePath ;
97
101
98
- // public void setContext(Context mCtx)
99
- // {
100
- // if (CordovaInterface.class.isInstance(mCtx))
101
- // cordova = (CordovaInterface) mCtx;
102
- // else
103
- // LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
104
- // }
102
+ private String applicationId ;
105
103
106
104
@ Override
107
105
protected void pluginInitialize () {
@@ -132,6 +130,8 @@ protected void pluginInitialize() {
132
130
133
131
@ Override
134
132
public boolean execute (String action , JSONArray args , CallbackContext callbackContext ) throws JSONException {
133
+ this .applicationId = cordova .getContext ().getPackageName ();
134
+
135
135
if (action .equals ("getFormatData" )) {
136
136
JSONObject obj = getFormatData (args .getString (0 ), args .getString (1 ));
137
137
callbackContext .success (obj );
@@ -142,14 +142,11 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
142
142
143
143
if (action .equals ("captureAudio" )) {
144
144
this .captureAudio (pendingRequests .createRequest (CAPTURE_AUDIO , options , callbackContext ));
145
- }
146
- else if (action .equals ("captureImage" )) {
145
+ } else if (action .equals ("captureImage" )) {
147
146
this .captureImage (pendingRequests .createRequest (CAPTURE_IMAGE , options , callbackContext ));
148
- }
149
- else if (action .equals ("captureVideo" )) {
147
+ } else if (action .equals ("captureVideo" )) {
150
148
this .captureVideo (pendingRequests .createRequest (CAPTURE_VIDEO , options , callbackContext ));
151
- }
152
- else {
149
+ } else {
153
150
return false ;
154
151
}
155
152
@@ -175,18 +172,16 @@ private JSONObject getFormatData(String filePath, String mimeType) throws JSONEx
175
172
176
173
// If the mimeType isn't set the rest will fail
177
174
// so let's see if we can determine it.
178
- if (mimeType == null || mimeType .equals ( "" ) || "null" .equals (mimeType )) {
175
+ if (mimeType == null || mimeType .isEmpty ( ) || "null" .equals (mimeType )) {
179
176
mimeType = FileHelper .getMimeType (fileUrl , cordova );
180
177
}
181
178
LOG .d (LOG_TAG , "Mime type = " + mimeType );
182
179
183
180
if (mimeType .equals (IMAGE_JPEG ) || filePath .endsWith (".jpg" )) {
184
181
obj = getImageData (fileUrl , obj );
185
- }
186
- else if (Arrays .asList (AUDIO_TYPES ).contains (mimeType )) {
182
+ } else if (Arrays .asList (AUDIO_TYPES ).contains (mimeType )) {
187
183
obj = getAudioVideoData (filePath , obj , false );
188
- }
189
- else if (mimeType .equals (VIDEO_3GPP ) || mimeType .equals (VIDEO_MP4 )) {
184
+ } else if (mimeType .equals (VIDEO_3GPP ) || mimeType .equals (VIDEO_MP4 )) {
190
185
obj = getAudioVideoData (filePath , obj , true );
191
186
}
192
187
return obj ;
@@ -242,7 +237,7 @@ private boolean isMissingPermissions(Request req, List<String> permissions) {
242
237
}
243
238
}
244
239
245
- boolean isMissingPermissions = missingPermissions .size () > 0 ;
240
+ boolean isMissingPermissions = ! missingPermissions .isEmpty () ;
246
241
if (isMissingPermissions ) {
247
242
String [] missing = missingPermissions .toArray (new String [missingPermissions .size ()]);
248
243
PermissionHelper .requestPermissions (this , req .requestCode , missing );
@@ -262,6 +257,14 @@ private boolean isMissingCameraPermissions(Request req) {
262
257
return isMissingPermissions (req , cameraPermissions );
263
258
}
264
259
260
+ private String getTempDirectoryPath () {
261
+ File cache = new File (cordova .getActivity ().getCacheDir (), "org.apache.cordova.mediacapture" );
262
+
263
+ // Create the cache directory if it doesn't exist
264
+ cache .mkdirs ();
265
+ return cache .getAbsolutePath ();
266
+ }
267
+
265
268
/**
266
269
* Sets up an intent to capture audio. Result handled by onActivityResult()
267
270
*/
@@ -270,6 +273,16 @@ private void captureAudio(Request req) {
270
273
271
274
try {
272
275
Intent intent = new Intent (android .provider .MediaStore .Audio .Media .RECORD_SOUND_ACTION );
276
+ String timeStamp = new SimpleDateFormat ("yyyyMMddHHmmssSSS" ).format (new Date ());
277
+ String fileName = "cdv_media_capture_audio_" + timeStamp + ".m4a" ;
278
+ File audio = new File (getTempDirectoryPath (), fileName );
279
+ Uri audioUri = FileProvider .getUriForFile (this .cordova .getActivity (),
280
+ this .applicationId + ".cordova.plugin.mediacapture.provider" ,
281
+ audio );
282
+ this .audioAbsolutePath = audio .getAbsolutePath ();
283
+ intent .putExtra (android .provider .MediaStore .EXTRA_OUTPUT , audioUri );
284
+ LOG .d (LOG_TAG , "Recording an audio and saving to: " + this .audioAbsolutePath );
285
+
273
286
this .cordova .startActivityForResult ((CordovaPlugin ) this , intent , req .requestCode );
274
287
} catch (ActivityNotFoundException ex ) {
275
288
pendingRequests .resolveWithFailure (req , createErrorObject (CAPTURE_NOT_SUPPORTED , "No Activity found to handle Audio Capture." ));
@@ -287,11 +300,16 @@ private void captureImage(Request req) {
287
300
288
301
Intent intent = new Intent (android .provider .MediaStore .ACTION_IMAGE_CAPTURE );
289
302
290
- ContentResolver contentResolver = this .cordova .getActivity ().getContentResolver ();
291
- ContentValues cv = new ContentValues ();
292
- cv .put (MediaStore .Images .Media .MIME_TYPE , IMAGE_JPEG );
293
- imageUri = contentResolver .insert (MediaStore .Images .Media .EXTERNAL_CONTENT_URI , cv );
294
- LOG .d (LOG_TAG , "Taking a picture and saving to: " + imageUri .toString ());
303
+ String timeStamp = new SimpleDateFormat ("yyyyMMddHHmmssSSS" ).format (new Date ());
304
+ String fileName = "cdv_media_capture_image_" + timeStamp + ".jpg" ;
305
+ File image = new File (getTempDirectoryPath (), fileName );
306
+
307
+ Uri imageUri = FileProvider .getUriForFile (this .cordova .getActivity (),
308
+ this .applicationId + ".cordova.plugin.mediacapture.provider" ,
309
+ image );
310
+ this .imageAbsolutePath = image .getAbsolutePath ();
311
+ intent .putExtra (android .provider .MediaStore .EXTRA_OUTPUT , imageUri );
312
+ LOG .d (LOG_TAG , "Taking a picture and saving to: " + this .imageAbsolutePath );
295
313
296
314
intent .putExtra (android .provider .MediaStore .EXTRA_OUTPUT , imageUri );
297
315
@@ -305,6 +323,16 @@ private void captureVideo(Request req) {
305
323
if (isMissingCameraPermissions (req )) return ;
306
324
307
325
Intent intent = new Intent (android .provider .MediaStore .ACTION_VIDEO_CAPTURE );
326
+ String timeStamp = new SimpleDateFormat ("yyyyMMddHHmmssSSS" ).format (new Date ());
327
+ String fileName = "cdv_media_capture_video_" + timeStamp + ".mp4" ;
328
+ File movie = new File (getTempDirectoryPath (), fileName );
329
+
330
+ Uri videoUri = FileProvider .getUriForFile (this .cordova .getActivity (),
331
+ this .applicationId + ".cordova.plugin.mediacapture.provider" ,
332
+ movie );
333
+ this .videoAbsolutePath = movie .getAbsolutePath ();
334
+ intent .putExtra (android .provider .MediaStore .EXTRA_OUTPUT , videoUri );
335
+ LOG .d (LOG_TAG , "Recording a video and saving to: " + this .videoAbsolutePath );
308
336
309
337
if (Build .VERSION .SDK_INT > 7 ){
310
338
intent .putExtra ("android.intent.extra.durationLimit" , req .duration );
@@ -332,13 +360,13 @@ public void onActivityResult(int requestCode, int resultCode, final Intent inten
332
360
public void run () {
333
361
switch (req .action ) {
334
362
case CAPTURE_AUDIO :
335
- onAudioActivityResult (req , intent );
363
+ onAudioActivityResult (req );
336
364
break ;
337
365
case CAPTURE_IMAGE :
338
366
onImageActivityResult (req );
339
367
break ;
340
368
case CAPTURE_VIDEO :
341
- onVideoActivityResult (req , intent );
369
+ onVideoActivityResult (req );
342
370
break ;
343
371
}
344
372
}
@@ -371,18 +399,11 @@ else if (resultCode == Activity.RESULT_CANCELED) {
371
399
}
372
400
373
401
374
- public void onAudioActivityResult (Request req , Intent intent ) {
375
- // Get the uri of the audio clip
376
- Uri data = intent .getData ();
377
- if (data == null ) {
378
- pendingRequests .resolveWithFailure (req , createErrorObject (CAPTURE_NO_MEDIA_FILES , "Error: data is null" ));
379
- return ;
380
- }
381
-
382
- // Create a file object from the uri
383
- JSONObject mediaFile = createMediaFile (data );
402
+ public void onAudioActivityResult (Request req ) {
403
+ // create a file object from the audio absolute path
404
+ JSONObject mediaFile = createMediaFileWithAbsolutePath (this .audioAbsolutePath );
384
405
if (mediaFile == null ) {
385
- pendingRequests .resolveWithFailure (req , createErrorObject (CAPTURE_INTERNAL_ERR , "Error: no mediaFile created from " + data ));
406
+ pendingRequests .resolveWithFailure (req , createErrorObject (CAPTURE_INTERNAL_ERR , "Error: no mediaFile created from " + this . audioAbsolutePath ));
386
407
return ;
387
408
}
388
409
@@ -398,17 +419,10 @@ public void onAudioActivityResult(Request req, Intent intent) {
398
419
}
399
420
400
421
public void onImageActivityResult (Request req ) {
401
- // Get the uri of the image
402
- Uri data = imageUri ;
403
- if (data == null ) {
404
- pendingRequests .resolveWithFailure (req , createErrorObject (CAPTURE_NO_MEDIA_FILES , "Error: data is null" ));
405
- return ;
406
- }
407
-
408
- // Create a file object from the uri
409
- JSONObject mediaFile = createMediaFile (data );
422
+ // create a file object from the image absolute path
423
+ JSONObject mediaFile = createMediaFileWithAbsolutePath (this .imageAbsolutePath );
410
424
if (mediaFile == null ) {
411
- pendingRequests .resolveWithFailure (req , createErrorObject (CAPTURE_INTERNAL_ERR , "Error: no mediaFile created from " + data ));
425
+ pendingRequests .resolveWithFailure (req , createErrorObject (CAPTURE_INTERNAL_ERR , "Error: no mediaFile created from " + this . imageAbsolutePath ));
412
426
return ;
413
427
}
414
428
@@ -425,18 +439,11 @@ public void onImageActivityResult(Request req) {
425
439
}
426
440
}
427
441
428
- public void onVideoActivityResult (Request req , Intent intent ) {
429
- // Get the uri of the video clip
430
- Uri data = intent .getData ();
431
- if (data == null ) {
432
- pendingRequests .resolveWithFailure (req , createErrorObject (CAPTURE_NO_MEDIA_FILES , "Error: data is null" ));
433
- return ;
434
- }
435
-
436
- // Create a file object from the uri
437
- JSONObject mediaFile = createMediaFile (data );
442
+ public void onVideoActivityResult (Request req ) {
443
+ // create a file object from the video absolute path
444
+ JSONObject mediaFile = createMediaFileWithAbsolutePath (this .videoAbsolutePath );
438
445
if (mediaFile == null ) {
439
- pendingRequests .resolveWithFailure (req , createErrorObject (CAPTURE_INTERNAL_ERR , "Error: no mediaFile created from " + data ));
446
+ pendingRequests .resolveWithFailure (req , createErrorObject (CAPTURE_INTERNAL_ERR , "Error: no mediaFile created from " + this . videoAbsolutePath ));
440
447
return ;
441
448
}
442
449
@@ -452,35 +459,30 @@ public void onVideoActivityResult(Request req, Intent intent) {
452
459
}
453
460
454
461
/**
455
- * Creates a JSONObject that represents a File from the Uri
462
+ * Creates a JSONObject that represents a File from the absolute path
456
463
*
457
- * @param data the Uri of the audio/image/video
464
+ * @param path the absolute path saved in FileProvider of the audio/image/video
458
465
* @return a JSONObject that represents a File
459
466
* @throws IOException
460
467
*/
461
- private JSONObject createMediaFile (Uri data ) {
462
- File fp = webView .getResourceApi ().mapUriToFile (data );
463
- if (fp == null ) {
464
- return null ;
465
- }
466
-
468
+ private JSONObject createMediaFileWithAbsolutePath (String path ) {
469
+ File fp = new File (path );
467
470
JSONObject obj = new JSONObject ();
468
471
469
472
Class webViewClass = webView .getClass ();
470
473
PluginManager pm = null ;
471
474
try {
472
475
Method gpm = webViewClass .getMethod ("getPluginManager" );
473
476
pm = (PluginManager ) gpm .invoke (webView );
474
- } catch (NoSuchMethodException e ) {
475
- } catch (IllegalAccessException e ) {
476
- } catch (InvocationTargetException e ) {
477
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e ) {
478
+ // Do Nothing
477
479
}
478
480
if (pm == null ) {
479
481
try {
480
482
Field pmf = webViewClass .getField ("pluginManager" );
481
483
pm = (PluginManager )pmf .get (webView );
482
- } catch (NoSuchFieldException e ) {
483
- } catch ( IllegalAccessException e ) {
484
+ } catch (NoSuchFieldException | IllegalAccessException e ) {
485
+ // Do Nothing
484
486
}
485
487
}
486
488
FileUtils filePlugin = (FileUtils ) pm .getPlugin ("File" );
@@ -497,6 +499,7 @@ private JSONObject createMediaFile(Uri data) {
497
499
// are reported as video/3gpp. I'm doing this hacky check of the URI to see if it
498
500
// is stored in the audio or video content store.
499
501
if (fp .getAbsoluteFile ().toString ().endsWith (".3gp" ) || fp .getAbsoluteFile ().toString ().endsWith (".3gpp" )) {
502
+ Uri data = Uri .fromFile (fp );
500
503
if (data .toString ().contains ("/audio/" )) {
501
504
obj .put ("type" , AUDIO_3GPP );
502
505
} else {
0 commit comments