Whether or not you get the image is dependent on the manufacturer of the phone unfortunately. Every Android version and every Manufacturer seems to have a slightly different behavior. Sometimes the URL is provided in the result as "data" parameter (that's what you're doing), but sometimes it's just empty. I even got a phone once that returned RESULT_CANCEL although it worked perfectly.
As it seems there's no way around implementing all kind of different fallbacks. Here's my code I'm using currently in one of our projects. The member variable mTargetUri
needs to be set to the output file name you provided as Intent parameter MediaStore.EXTRA_OUTPUT
, mCaptureTime
should be set to Sytem.currentTimeMillis()
right before launching the Intent.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Log.v(LOG_TAG, "Camera intent succeeded");
}
else if (resultCode == RESULT_CANCELED) {
Log.i(LOG_TAG, "Camera intent aborted");
}
else {
Log.e(LOG_TAG, "Camera intent failed with result code: " + resultCode);
}
// Regardless of the resultCode we're going to check if a new photo has been
// created on the phone. At least on the Samsung Galaxy S3 the behavior
// could be observed that although the result code was "0" the camera app
// created two (!) files on the SD card.
// Image captured and saved to fileUri specified in the Intent
Uri targetUri = (data != null) ? data.getData() : null;
if (targetUri == null) {
Log.w(LOG_TAG, "Camera intent returned empty result.");
targetUri = mTargetUri;
}
if (targetUri != null) {
String targetFilePath = targetUri.getPath();
File targetFile = new File(targetFilePath);
if (targetFile.exists()) {
Log.i(LOG_TAG, "Image saved to: " + targetUri.toString());
// Fix for issue reported here: http://code.google.com/p/android/issues/detail?id=22822
// and here: http://code.google.com/p/android/issues/detail?id=19268
// We're following the proposed solution from https://stackoverflow.com/questions/8450539/
int rotation = -1;
long fileSize = targetFile.length();
Cursor mediaCursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[] {
MediaStore.Images.ImageColumns.ORIENTATION,
MediaStore.MediaColumns.SIZE,
MediaStore.MediaColumns.DATA },
MediaStore.MediaColumns.DATE_ADDED + ">=?",
new String[] { String.valueOf(mCaptureTime/1000 - 1)},
MediaStore.MediaColumns.DATE_ADDED + " desc");
if ((mediaCursor != null) && (mCaptureTime != 0)) {
if (mediaCursor.moveToFirst()) {
do {
long size = mediaCursor.getLong(1);
Uri uri = Uri.parse(mediaCursor.getString(2));
// Extra check to make sure that we are getting the orientation from the proper file
if (size == fileSize && !uri.equals(targetUri.toString())) {
rotation = mediaCursor.getInt(0);
break;
}
} while (mediaCursor.moveToNext());
}
mediaCursor.close();
}
if (rotation == -1) {
// It seems that there has been no duplication and no rotation issue so far. This means we can
// add our newly created file to the media library.
// TODO
}
else {
// Looks like the picture already exists in the media library. This indicates we got a duplicate.
Log.w(LOG_TAG, "Duplicate image found for " + targetUri.toString() + " in media library. Deleting the copy.");
if (!targetFile.delete()) {
Log.e(LOG_TAG, "Failed to delete duplicate image.");
}
}
}
}
}
}
The code originates from different sources here on Stackoverflow and other sites. The basic idea is that we
- disregard the result code (
RESULT_OK
or RESULT_CANCELED
) as they are no indication whether a photo was taken and stored on the SD card or not. The code above just logs the value but continues in any case.
- Then we check if there was an URI provided by the intent result. If we get an URI then it's safe to assume that it will actually point to the newly taken photo. However, we won't get such an URI although everything succeeded perfectly. To handle that case we simply use the URI we've originally provided to the camera activity (
mTargetUri
) hoping that we'll find the new file there.
- On some newer devices the camera app automatically adds a new photo to the media library and then creates a second copy names in the way we originally specified in
targetUri
. The problem with this approach is that we end up with duplicate images. To address this we follow a logic that is derived from the following Stackoverflow question: Images taken with ACTION_IMAGE_CAPTURE always returns 1 for ExifInterface.TAG_ORIENTATION on some newer devices. I won't go into many details here (just follow the link to get a better understanding) but the basic idea is that we query the Android media store and check if it already contains our new photo by comparing timestamps (mCaptureTime
is set to System.currentTimeMillis()
when the capture intent was originally started).
- In case we have found an entry in the media store we simply delete the duplicate.
This logic should work in all cases with virtually any Android device out there. We have tested it on a dozen of different devices and Android versions without additional issues so far.