From d899d7a4b814c7a0bcbadba42f9d93ff2f26fab4 Mon Sep 17 00:00:00 2001 From: Andrew Grieve Date: Tue, 29 Apr 2014 00:51:09 -0400 Subject: [PATCH] CB-6546 android: Fix a couple bugs with allowEdit pull request - Don't set width/height when they are not specified - photolibrary returns null from getData when image is cropped --- src/android/CameraLauncher.java | 232 +++++++++++++++++--------------- 1 file changed, 127 insertions(+), 105 deletions(-) diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java index aa0ef1e..96c15da 100755 --- a/src/android/CameraLauncher.java +++ b/src/android/CameraLauncher.java @@ -60,7 +60,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect private static final int DATA_URL = 0; // Return base64 encoded string private static final int FILE_URI = 1; // Return file uri (content://media/external/images/media/2 for Android) - private static final int NATIVE_URI = 2; // On Android, this is the same as FILE_URI + private static final int NATIVE_URI = 2; // On Android, this is the same as FILE_URI private static final int PHOTOLIBRARY = 0; // Choose image from picture library (same as SAVEDPHOTOALBUM for Android) private static final int CAMERA = 1; // Take picture from camera @@ -95,14 +95,15 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect private MediaScannerConnection conn; // Used to update gallery app with newly-written files private Uri scanMe; // Uri of image to be added to content store + private Uri croppedUri; /** * Executes the request and returns PluginResult. * - * @param action The action to execute. - * @param args JSONArry of arguments for the plugin. + * @param action The action to execute. + * @param args JSONArry of arguments for the plugin. * @param callbackContext The callback id used when calling back into JavaScript. - * @return A PluginResult object with a status and message. + * @return A PluginResult object with a status and message. */ public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { this.callbackContext = callbackContext; @@ -248,76 +249,85 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect public void getImage(int srcType, int returnType, int encodingType) { Intent intent = new Intent(); String title = GET_PICTURE; + croppedUri = null; if (this.mediaType == PICTURE) { intent.setType("image/*"); - if (this.allowEdit) { - intent.setAction(Intent.ACTION_PICK); - intent.putExtra("crop", "true"); - if (this.targetHeight == this.targetWidth) { - intent.putExtra("aspectX", 1); - intent.putExtra("aspectY", 1); - } - intent.putExtra("outputX", this.targetWidth); - intent.putExtra("outputY", this.targetHeight); - File photo = createCaptureFile(encodingType); - intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, - Uri.fromFile(photo)); - } else { - intent.setAction(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - } - } else if (this.mediaType == VIDEO) { - intent.setType("video/*"); - title = GET_VIDEO; - intent.setAction(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - } else if (this.mediaType == ALLMEDIA) { - // I wanted to make the type 'image/*, video/*' but this does not work on all versions - // of android so I had to go with the wildcard search. - intent.setType("*/*"); - title = GET_All; - intent.setAction(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - } + if (this.allowEdit) { + intent.setAction(Intent.ACTION_PICK); + intent.putExtra("crop", "true"); + if (targetWidth > 0) { + intent.putExtra("outputX", targetWidth); + } + if (targetHeight > 0) { + intent.putExtra("outputY", targetHeight); + } + if (targetHeight > 0 && targetWidth > 0 && targetWidth == targetHeight) { + intent.putExtra("aspectX", 1); + intent.putExtra("aspectY", 1); + } + File photo = createCaptureFile(encodingType); + croppedUri = Uri.fromFile(photo); + intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, croppedUri); + } else { + intent.setAction(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + } + } else if (this.mediaType == VIDEO) { + intent.setType("video/*"); + title = GET_VIDEO; + intent.setAction(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + } else if (this.mediaType == ALLMEDIA) { + // I wanted to make the type 'image/*, video/*' but this does not work on all versions + // of android so I had to go with the wildcard search. + intent.setType("*/*"); + title = GET_All; + intent.setAction(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + } if (this.cordova != null) { this.cordova.startActivityForResult((CordovaPlugin) this, Intent.createChooser(intent, new String(title)), (srcType + 1) * 16 + returnType + 1); } } - /** - * Brings up the UI to perform crop on passed image URI - * - * @param picUri - */ - private void performCrop(Uri picUri) { - try { - Intent cropIntent = new Intent("com.android.camera.action.CROP"); - // indicate image type and Uri - cropIntent.setDataAndType(picUri, "image/*"); - // set crop properties - cropIntent.putExtra("crop", "true"); - if (this.targetHeight == this.targetWidth) { - cropIntent.putExtra("aspectX", 1); - cropIntent.putExtra("aspectY", 1); - } - // indicate output X and Y - cropIntent.putExtra("outputX", this.targetWidth); - cropIntent.putExtra("outputY", this.targetHeight); - // retrieve data on return - cropIntent.putExtra("return-data", true); - // start the activity - we handle returning in onActivityResult + /** + * Brings up the UI to perform crop on passed image URI + * + * @param picUri + */ + private void performCrop(Uri picUri) { + try { + Intent cropIntent = new Intent("com.android.camera.action.CROP"); + // indicate image type and Uri + cropIntent.setDataAndType(picUri, "image/*"); + // set crop properties + cropIntent.putExtra("crop", "true"); + // indicate output X and Y + if (targetWidth > 0) { + cropIntent.putExtra("outputX", targetWidth); + } + if (targetHeight > 0) { + cropIntent.putExtra("outputY", targetHeight); + } + if (targetHeight > 0 && targetWidth > 0 && targetWidth == targetHeight) { + cropIntent.putExtra("aspectX", 1); + cropIntent.putExtra("aspectY", 1); + } + // retrieve data on return + cropIntent.putExtra("return-data", true); + // start the activity - we handle returning in onActivityResult - if (this.cordova != null) { - this.cordova.startActivityForResult((CordovaPlugin) this, - cropIntent, CROP_CAMERA); - } - } catch (ActivityNotFoundException anfe) { - Log.e(LOG_TAG, "Crop operation not supported on this device"); - // Send Uri back to JavaScript for viewing image - this.callbackContext.success(picUri.toString()); - } - } + if (this.cordova != null) { + this.cordova.startActivityForResult((CordovaPlugin) this, + cropIntent, CROP_CAMERA); + } + } catch (ActivityNotFoundException anfe) { + Log.e(LOG_TAG, "Crop operation not supported on this device"); + // Send Uri back to JavaScript for viewing image + this.callbackContext.success(picUri.toString()); + } + } /** * Applies all needed transformation to the image received from the camera. @@ -410,11 +420,11 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect exif.writeExifData(); } if (this.allowEdit) { - performCrop(uri); - } else { - // Send Uri back to JavaScript for viewing image - this.callbackContext.success(uri.toString()); - } + performCrop(uri); + } else { + // Send Uri back to JavaScript for viewing image + this.callbackContext.success(uri.toString()); + } } // Send Uri back to JavaScript for viewing image this.callbackContext.success(uri.toString()); @@ -459,6 +469,14 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException { */ private void processResultFromGallery(int destType, Intent intent) { Uri uri = intent.getData(); + if (uri == null) { + if (croppedUri != null) { + uri = croppedUri; + } else { + this.failPicture("null data from photo library"); + return; + } + } int rotate = 0; // If you ask for video or all media type you will automatically get back a file URI @@ -555,45 +573,49 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException { int srcType = (requestCode / 16) - 1; int destType = (requestCode % 16) - 1; // if camera crop - if (requestCode == CROP_CAMERA) { - if (resultCode == Activity.RESULT_OK) { - // // get the returned data - Bundle extras = intent.getExtras(); - // get the cropped bitmap - Bitmap thePic = extras.getParcelable("data"); + if (requestCode == CROP_CAMERA) { + if (resultCode == Activity.RESULT_OK) { + // // get the returned data + Bundle extras = intent.getExtras(); + // get the cropped bitmap + Bitmap thePic = extras.getParcelable("data"); + if (thePic == null) { + this.failPicture("Crop returned no data."); + return; + } - // now save the bitmap to a file - OutputStream fOut = null; - File temp_file = new File(getTempDirectoryPath(), - System.currentTimeMillis() + ".jpg"); - try { - temp_file.createNewFile(); - fOut = new FileOutputStream(temp_file); - thePic.compress(Bitmap.CompressFormat.JPEG, this.mQuality, - fOut); - fOut.flush(); - fOut.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } + // now save the bitmap to a file + OutputStream fOut = null; + File temp_file = new File(getTempDirectoryPath(), + System.currentTimeMillis() + ".jpg"); + try { + temp_file.createNewFile(); + fOut = new FileOutputStream(temp_file); + thePic.compress(Bitmap.CompressFormat.JPEG, this.mQuality, + fOut); + fOut.flush(); + fOut.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } - // // Send Uri back to JavaScript for viewing image - this.callbackContext - .success(Uri.fromFile(temp_file).toString()); + // // Send Uri back to JavaScript for viewing image + this.callbackContext + .success(Uri.fromFile(temp_file).toString()); - }// If cancelled - else if (resultCode == Activity.RESULT_CANCELED) { - this.failPicture("Camera cancelled."); - } + }// If cancelled + else if (resultCode == Activity.RESULT_CANCELED) { + this.failPicture("Camera cancelled."); + } - // If something else - else { - this.failPicture("Did not complete!"); - } + // If something else + else { + this.failPicture("Did not complete!"); + } - } + } // If CAMERA if (srcType == CAMERA) { // If image available @@ -961,4 +983,4 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException { public void onScanCompleted(String path, Uri uri) { this.conn.disconnect(); } -} \ No newline at end of file +}