diff --git a/README.md b/README.md
index e2acdd40..04b5dbc1 100644
--- a/README.md
+++ b/README.md
@@ -21,9 +21,9 @@ description: Capture audio, video, and images.
# under the License.
-->
-|AppVeyor|Travis CI|
-|:-:|:-:|
-|[](https://ci.appveyor.com/project/ApacheSoftwareFoundation/cordova-plugin-media-capture)|[](https://travis-ci.org/apache/cordova-plugin-media-capture)|
+| AppVeyor | Travis CI |
+| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| [](https://ci.appveyor.com/project/ApacheSoftwareFoundation/cordova-plugin-media-capture) | [](https://travis-ci.org/apache/cordova-plugin-media-capture) |
# cordova-plugin-media-capture
@@ -332,10 +332,12 @@ capturing a video clip, the `CaptureErrorCB` callback executes with a
- __limit__: The maximum number of images the user can capture in a single capture operation. The value must be greater than or equal to 1 (defaults to 1).
+- __cameraDirection__: Pick camera direction. Accepted values are 1 (for front camera) and 0 (for back camera). Or you can use the constants (window.MediaCapture.CAMERA_FRONT or window.MediaCapture.CAMERA_BACK)
+
### Example
// limit capture operation to 3 images
- var options = { limit: 3 };
+ var options = { limit: 3, cameraDirection: window.MediaCapture.CAMERA_FRONT };
navigator.device.capture.captureImage(captureSuccess, captureError, options);
@@ -354,10 +356,12 @@ capturing a video clip, the `CaptureErrorCB` callback executes with a
- __duration__: The maximum duration of a video clip, in seconds.
+- __cameraDirection__: Pick camera direction. Accepted values are 1 (for front camera) and 0 (for back camera). Or you can use the constants (window.MediaCapture.CAMERA_FRONT or window.MediaCapture.CAMERA_BACK)
+
### Example
// limit capture operation to 3 video clips
- var options = { limit: 3 };
+ var options = { limit: 3, cameraDirection: window.MediaCapture.CAMERA_FRONT };
navigator.device.capture.captureVideo(captureSuccess, captureError, options);
diff --git a/plugin.xml b/plugin.xml
index e50e8e59..30014d91 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -35,6 +35,10 @@ xmlns:android="http://schemas.android.com/apk/res/android"
+
+
+
+
diff --git a/src/android/Capture.java b/src/android/Capture.java
index 317d0ebc..53bb4bc3 100644
--- a/src/android/Capture.java
+++ b/src/android/Capture.java
@@ -63,48 +63,55 @@ public class Capture extends CordovaPlugin {
private static final String VIDEO_3GPP = "video/3gpp";
private static final String VIDEO_MP4 = "video/mp4";
private static final String AUDIO_3GPP = "audio/3gpp";
- private static final String[] AUDIO_TYPES = new String[] {"audio/3gpp", "audio/aac", "audio/amr", "audio/wav"};
+ private static final String[] AUDIO_TYPES = new String[] { "audio/3gpp", "audio/aac", "audio/amr", "audio/wav" };
private static final String IMAGE_JPEG = "image/jpeg";
- private static final int CAPTURE_AUDIO = 0; // Constant for capture audio
- private static final int CAPTURE_IMAGE = 1; // Constant for capture image
- private static final int CAPTURE_VIDEO = 2; // Constant for capture video
+ private static final int CAPTURE_AUDIO = 0; // Constant for capture audio
+ private static final int CAPTURE_IMAGE = 1; // Constant for capture image
+ private static final int CAPTURE_VIDEO = 2; // Constant for capture video
private static final String LOG_TAG = "Capture";
private static final int CAPTURE_INTERNAL_ERR = 0;
-// private static final int CAPTURE_APPLICATION_BUSY = 1;
-// private static final int CAPTURE_INVALID_ARGUMENT = 2;
+ // private static final int CAPTURE_APPLICATION_BUSY = 1;
+ // private static final int CAPTURE_INVALID_ARGUMENT = 2;
private static final int CAPTURE_NO_MEDIA_FILES = 3;
private static final int CAPTURE_PERMISSION_DENIED = 4;
private static final int CAPTURE_NOT_SUPPORTED = 20;
- private boolean cameraPermissionInManifest; // Whether or not the CAMERA permission is declared in AndroidManifest.xml
+ private boolean cameraPermissionInManifest; // Whether or not the CAMERA permission is declared in
+ // AndroidManifest.xml
private final PendingRequests pendingRequests = new PendingRequests();
- private int numPics; // Number of pictures before capture activity
+ private int numPics; // Number of pictures before capture activity
private Uri imageUri;
-// public void setContext(Context mCtx)
-// {
-// if (CordovaInterface.class.isInstance(mCtx))
-// cordova = (CordovaInterface) mCtx;
-// else
-// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
-// }
+ private boolean useFrontEndCamera = false;
+
+ // public void setContext(Context mCtx)
+ // {
+ // if (CordovaInterface.class.isInstance(mCtx))
+ // cordova = (CordovaInterface) mCtx;
+ // else
+ // LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work
+ // correctly. Please implement it in your activity");
+ // }
@Override
protected void pluginInitialize() {
super.pluginInitialize();
- // CB-10670: The CAMERA permission does not need to be requested unless it is declared
- // in AndroidManifest.xml. This plugin does not declare it, but others may and so we must
+ // CB-10670: The CAMERA permission does not need to be requested unless it is
+ // declared
+ // in AndroidManifest.xml. This plugin does not declare it, but others may and
+ // so we must
// check the package info to determine if the permission is present.
cameraPermissionInManifest = false;
try {
PackageManager packageManager = this.cordova.getActivity().getPackageManager();
- String[] permissionsInPackage = packageManager.getPackageInfo(this.cordova.getActivity().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions;
+ String[] permissionsInPackage = packageManager.getPackageInfo(this.cordova.getActivity().getPackageName(),
+ PackageManager.GET_PERMISSIONS).requestedPermissions;
if (permissionsInPackage != null) {
for (String permission : permissionsInPackage) {
if (permission.equals(Manifest.permission.CAMERA)) {
@@ -130,16 +137,19 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
JSONObject options = args.optJSONObject(0);
+ // check if use front end camera == 1
+ // if that is the case then we are going to use the camera
+ if (options != null && options.has("cameraDirection")) {
+ this.useFrontEndCamera = options.getInt("cameraDirection") == 1 ? true : false;
+ }
+
if (action.equals("captureAudio")) {
this.captureAudio(pendingRequests.createRequest(CAPTURE_AUDIO, options, callbackContext));
- }
- else if (action.equals("captureImage")) {
+ } else if (action.equals("captureImage")) {
this.captureImage(pendingRequests.createRequest(CAPTURE_IMAGE, options, callbackContext));
- }
- else if (action.equals("captureVideo")) {
+ } else if (action.equals("captureVideo")) {
this.captureVideo(pendingRequests.createRequest(CAPTURE_VIDEO, options, callbackContext));
- }
- else {
+ } else {
return false;
}
@@ -172,11 +182,9 @@ private JSONObject getFormatData(String filePath, String mimeType) throws JSONEx
if (mimeType.equals(IMAGE_JPEG) || filePath.endsWith(".jpg")) {
obj = getImageData(fileUrl, obj);
- }
- else if (Arrays.asList(AUDIO_TYPES).contains(mimeType)) {
+ } else if (Arrays.asList(AUDIO_TYPES).contains(mimeType)) {
obj = getAudioVideoData(filePath, obj, false);
- }
- else if (mimeType.equals(VIDEO_3GPP) || mimeType.equals(VIDEO_MP4)) {
+ } else if (mimeType.equals(VIDEO_3GPP) || mimeType.equals(VIDEO_MP4)) {
obj = getAudioVideoData(filePath, obj, true);
}
return obj;
@@ -203,8 +211,8 @@ private JSONObject getImageData(Uri fileUrl, JSONObject obj) throws JSONExceptio
* Get the Image specific attributes
*
* @param filePath path to the file
- * @param obj represents the Media File Data
- * @param video if true get video attributes as well
+ * @param obj represents the Media File Data
+ * @param video if true get video attributes as well
* @return a JSONObject that represents the Media File Data
* @throws JSONException
*/
@@ -225,20 +233,21 @@ private JSONObject getAudioVideoData(String filePath, JSONObject obj, boolean vi
}
/**
- * Sets up an intent to capture audio. Result handled by onActivityResult()
+ * Sets up an intent to capture audio. Result handled by onActivityResult()
*/
private void captureAudio(Request req) {
- if (!PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
- PermissionHelper.requestPermission(this, req.requestCode, Manifest.permission.READ_EXTERNAL_STORAGE);
- } else {
- try {
- Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
-
- this.cordova.startActivityForResult((CordovaPlugin) this, intent, req.requestCode);
- } catch (ActivityNotFoundException ex) {
- pendingRequests.resolveWithFailure(req, createErrorObject(CAPTURE_NOT_SUPPORTED, "No Activity found to handle Audio Capture."));
- }
- }
+ if (!PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
+ PermissionHelper.requestPermission(this, req.requestCode, Manifest.permission.READ_EXTERNAL_STORAGE);
+ } else {
+ try {
+ Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
+
+ this.cordova.startActivityForResult((CordovaPlugin) this, intent, req.requestCode);
+ } catch (ActivityNotFoundException ex) {
+ pendingRequests.resolveWithFailure(req,
+ createErrorObject(CAPTURE_NOT_SUPPORTED, "No Activity found to handle Audio Capture."));
+ }
+ }
}
private String getTempDirectoryPath() {
@@ -249,22 +258,26 @@ private String getTempDirectoryPath() {
// Create the cache directory if it doesn't exist
cache.mkdirs();
+
+
+
return cache.getAbsolutePath();
}
/**
- * Sets up an intent to capture images. Result handled by onActivityResult()
+ * Sets up an intent to capture images. Result handled by onActivityResult()
*/
private void captureImage(Request req) {
- boolean needExternalStoragePermission =
- !PermissionHelper.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ boolean needExternalStoragePermission = !PermissionHelper.hasPermission(this,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE);
- boolean needCameraPermission = cameraPermissionInManifest &&
- !PermissionHelper.hasPermission(this, Manifest.permission.CAMERA);
+ boolean needCameraPermission = cameraPermissionInManifest
+ && !PermissionHelper.hasPermission(this, Manifest.permission.CAMERA);
if (needExternalStoragePermission || needCameraPermission) {
if (needExternalStoragePermission && needCameraPermission) {
- PermissionHelper.requestPermissions(this, req.requestCode, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA});
+ PermissionHelper.requestPermissions(this, req.requestCode,
+ new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA });
} else if (needExternalStoragePermission) {
PermissionHelper.requestPermission(this, req.requestCode, Manifest.permission.WRITE_EXTERNAL_STORAGE);
} else {
@@ -284,6 +297,11 @@ private void captureImage(Request req) {
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageUri);
+ if (this.useFrontEndCamera) {
+ intent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
+ intent.putExtra("android.intent.extras.CAMERA_FACING", 1);
+ }
+
this.cordova.startActivityForResult((CordovaPlugin) this, intent, req.requestCode);
}
}
@@ -294,18 +312,24 @@ private static void createWritableFile(File file) throws IOException {
}
/**
- * Sets up an intent to capture video. Result handled by onActivityResult()
+ * Sets up an intent to capture video. Result handled by onActivityResult()
*/
private void captureVideo(Request req) {
- if(cameraPermissionInManifest && !PermissionHelper.hasPermission(this, Manifest.permission.CAMERA)) {
+ if (cameraPermissionInManifest && !PermissionHelper.hasPermission(this, Manifest.permission.CAMERA)) {
PermissionHelper.requestPermission(this, req.requestCode, Manifest.permission.CAMERA);
} else {
Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
- if(Build.VERSION.SDK_INT > 7){
+ if (Build.VERSION.SDK_INT > 7) {
intent.putExtra("android.intent.extra.durationLimit", req.duration);
intent.putExtra("android.intent.extra.videoQuality", req.quality);
}
+
+ if (this.useFrontEndCamera) {
+ intent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
+ intent.putExtra("android.intent.extras.CAMERA_FACING", 1);
+ }
+
this.cordova.startActivityForResult((CordovaPlugin) this, intent, req.requestCode);
}
}
@@ -313,10 +337,13 @@ private void captureVideo(Request req) {
/**
* Called when the video view exits.
*
- * @param requestCode The request code originally supplied to startActivityForResult(),
- * allowing you to identify who this result came from.
- * @param resultCode The integer result code returned by the child activity through its setResult().
- * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
+ * @param requestCode The request code originally supplied to
+ * startActivityForResult(), allowing you to identify who
+ * this result came from.
+ * @param resultCode The integer result code returned by the child activity
+ * through its setResult().
+ * @param intent An Intent, which can return result data to the caller
+ * (various data can be attached to Intent "extras").
* @throws JSONException
*/
public void onActivityResult(int requestCode, int resultCode, final Intent intent) {
@@ -327,16 +354,16 @@ public void onActivityResult(int requestCode, int resultCode, final Intent inten
Runnable processActivityResult = new Runnable() {
@Override
public void run() {
- switch(req.action) {
- case CAPTURE_AUDIO:
- onAudioActivityResult(req, intent);
- break;
- case CAPTURE_IMAGE:
- onImageActivityResult(req);
- break;
- case CAPTURE_VIDEO:
- onVideoActivityResult(req, intent);
- break;
+ switch (req.action) {
+ case CAPTURE_AUDIO:
+ onAudioActivityResult(req, intent);
+ break;
+ case CAPTURE_IMAGE:
+ onImageActivityResult(req);
+ break;
+ case CAPTURE_VIDEO:
+ onVideoActivityResult(req, intent);
+ break;
}
}
};
@@ -367,7 +394,6 @@ else if (resultCode == Activity.RESULT_CANCELED) {
}
}
-
public void onAudioActivityResult(Request req, Intent intent) {
// Get the uri of the audio clip
Uri data = intent.getData();
@@ -401,21 +427,20 @@ public void onImageActivityResult(Request req) {
public void onVideoActivityResult(Request req, Intent intent) {
Uri data = null;
- if (intent != null){
+ if (intent != null) {
// Get the uri of the video clip
data = intent.getData();
}
- if( data == null){
+ if (data == null) {
File movie = new File(getTempDirectoryPath(), "Capture.avi");
data = Uri.fromFile(movie);
}
// create a file object from the uri
- if(data == null) {
+ if (data == null) {
pendingRequests.resolveWithFailure(req, createErrorObject(CAPTURE_NO_MEDIA_FILES, "Error: data is null"));
- }
- else {
+ } else {
req.results.put(createMediaFile(data));
if (req.results.length() >= req.limit) {
@@ -451,7 +476,7 @@ private JSONObject createMediaFile(Uri data) {
if (pm == null) {
try {
Field pmf = webViewClass.getField("pluginManager");
- pm = (PluginManager)pmf.get(webView);
+ pm = (PluginManager) pmf.get(webView);
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
}
@@ -466,8 +491,10 @@ private JSONObject createMediaFile(Uri data) {
if (url != null) {
obj.put("localURL", url.toString());
}
- // Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp files
- // are reported as video/3gpp. I'm doing this hacky check of the URI to see if it
+ // Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp
+ // files
+ // are reported as video/3gpp. I'm doing this hacky check of the URI to see if
+ // it
// is stored in the audio or video content store.
if (fp.getAbsoluteFile().toString().endsWith(".3gp") || fp.getAbsoluteFile().toString().endsWith(".3gpp")) {
if (data.toString().contains("/audio/")) {
@@ -505,17 +532,13 @@ private JSONObject createErrorObject(int code, String message) {
* @return a cursor
*/
private Cursor queryImgDB(Uri contentStore) {
- return this.cordova.getActivity().getContentResolver().query(
- contentStore,
- new String[] { MediaStore.Images.Media._ID },
- null,
- null,
- null);
+ return this.cordova.getActivity().getContentResolver().query(contentStore,
+ new String[] { MediaStore.Images.Media._ID }, null, null, null);
}
/**
- * Used to find out if we are in a situation where the Camera Intent adds to images
- * to the content store.
+ * Used to find out if we are in a situation where the Camera Intent adds to
+ * images to the content store.
*/
private void checkForDuplicateImage() {
Uri contentStore = whichContentStore();
@@ -533,6 +556,7 @@ private void checkForDuplicateImage() {
/**
* Determine if we are storing the images in internal or external storage
+ *
* @return Uri
*/
private Uri whichContentStore() {
@@ -545,25 +569,25 @@ private Uri whichContentStore() {
private void executeRequest(Request req) {
switch (req.action) {
- case CAPTURE_AUDIO:
- this.captureAudio(req);
- break;
- case CAPTURE_IMAGE:
- this.captureImage(req);
- break;
- case CAPTURE_VIDEO:
- this.captureVideo(req);
- break;
+ case CAPTURE_AUDIO:
+ this.captureAudio(req);
+ break;
+ case CAPTURE_IMAGE:
+ this.captureImage(req);
+ break;
+ case CAPTURE_VIDEO:
+ this.captureVideo(req);
+ break;
}
}
- public void onRequestPermissionResult(int requestCode, String[] permissions,
- int[] grantResults) throws JSONException {
+ public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults)
+ throws JSONException {
Request req = pendingRequests.get(requestCode);
if (req != null) {
boolean success = true;
- for(int r:grantResults) {
+ for (int r : grantResults) {
if (r == PackageManager.PERMISSION_DENIED) {
success = false;
break;
@@ -573,7 +597,8 @@ public void onRequestPermissionResult(int requestCode, String[] permissions,
if (success) {
executeRequest(req);
} else {
- pendingRequests.resolveWithFailure(req, createErrorObject(CAPTURE_PERMISSION_DENIED, "Permission denied."));
+ pendingRequests.resolveWithFailure(req,
+ createErrorObject(CAPTURE_PERMISSION_DENIED, "Permission denied."));
}
}
}
diff --git a/src/ios/CDVCapture.m b/src/ios/CDVCapture.m
index f2fe258c..2ee3e02c 100644
--- a/src/ios/CDVCapture.m
+++ b/src/ios/CDVCapture.m
@@ -269,6 +269,14 @@ - (void)captureVideo:(CDVInvokedUrlCommand*)command
// pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
// pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear;
// pickerController.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;
+
+ NSNumber* cameraDirection = [options objectForKey:@"cameraDirection"];
+
+ // check if the value of camera direction is 1
+ // if that is the case use the front face camera
+ if([cameraDirection intValue] == 1) {
+ pickerController.cameraDevice = UIImagePickerControllerCameraDeviceFront;
+ }
}
// CDVImagePicker specific property
pickerController.callbackId = callbackId;
diff --git a/www/CameraConstants.js b/www/CameraConstants.js
new file mode 100644
index 00000000..43750602
--- /dev/null
+++ b/www/CameraConstants.js
@@ -0,0 +1,10 @@
+/**
+ * @module MediaCapture
+ */
+module.exports = {
+ /**
+ * Camera direction constants
+ */
+ CAMERA_BACK: 0,
+ CAMERA_FRONT: 1
+};