Android ACTION_IMAGE_CAPTURE Intent
Solution 1
this is a well documented bug in some versions of android. that is, on google experience builds of android, image capture doesn't work as documented. what i've generally used is something like this in a utilities class.
public boolean hasImageCaptureBug() {
// list of known devices that have the bug
ArrayList<String> devices = new ArrayList<String>();
devices.add("android-devphone1/dream_devphone/dream");
devices.add("generic/sdk/generic");
devices.add("vodafone/vfpioneer/sapphire");
devices.add("tmobile/kila/dream");
devices.add("verizon/voles/sholes");
devices.add("google_ion/google_ion/sapphire");
return devices.contains(android.os.Build.BRAND + "/" + android.os.Build.PRODUCT + "/"
+ android.os.Build.DEVICE);
}
then when i launch image capture, i create an intent that checks for the bug.
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
if (hasImageCaptureBug()) {
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File("/sdcard/tmp")));
} else {
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
}
startActivityForResult(i, mRequestCode);
then in activity that i return to, i do different things based on the device.
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (requestCode) {
case GlobalConstants.IMAGE_CAPTURE:
Uri u;
if (hasImageCaptureBug()) {
File fi = new File("/sdcard/tmp");
try {
u = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), fi.getAbsolutePath(), null, null));
if (!fi.delete()) {
Log.i("logMarker", "Failed to delete " + fi);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
} else {
u = intent.getData();
}
}
this saves you having to write a new camera app, but this code isn't great either. the big problems are
you never get full sized images from the devices with the bug. you get pictures that are 512px wide that are inserted into the image content provider. on devices without the bug, everything works as document, you get a big normal picture.
you have to maintain the list. as written, it is possible for devices to be flashed with a version of android (say cyanogenmod's builds) that has the bug fixed. if that happens, your code will crash. the fix is to use the entire device fingerprint.
Solution 2
I know this has been answered before but I know a lot of people get tripped up on this, so I'm going to add a comment.
I had this exact same problem happen on my Nexus One. This was from the file not existing on the disk before the camera app started. Therefore, I made sure that the file existing before started the camera app. Here's some sample code that I used:
String storageState = Environment.getExternalStorageState();
if(storageState.equals(Environment.MEDIA_MOUNTED)) {
String path = Environment.getExternalStorageDirectory().getName() + File.separatorChar + "Android/data/" + MainActivity.this.getPackageName() + "/files/" + md5(upc) + ".jpg";
_photoFile = new File(path);
try {
if(_photoFile.exists() == false) {
_photoFile.getParentFile().mkdirs();
_photoFile.createNewFile();
}
} catch (IOException e) {
Log.e(TAG, "Could not create file.", e);
}
Log.i(TAG, path);
_fileUri = Uri.fromFile(_photoFile);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE );
intent.putExtra( MediaStore.EXTRA_OUTPUT, _fileUri);
startActivityForResult(intent, TAKE_PICTURE);
} else {
new AlertDialog.Builder(MainActivity.this)
.setMessage("External Storeage (SD Card) is required.\n\nCurrent state: " + storageState)
.setCancelable(true).create().show();
}
I first create a unique (somewhat) file name using an MD5 hash and put it into the appropriate folder. I then check to see if it exists (shouldn't, but its good practice to check anyway). If it does not exist, I get the parent dir (a folder) and create the folder hierarchy up to it (therefore if the folders leading up to the location of the file don't exist, they will after this line. Then after that I create the file. Once the file is created I get the Uri and pass it to the intent and then the OK button works as expected and all is golden.
Now,when the Ok button is pressed on the camera app, the file will be present in the given location. In this example it would be /sdcard/Android/data/com.example.myapp/files/234asdioue23498ad.jpg
There is no need to copy the file in the "onActivityResult" as posted above.
Solution 3
I've been through a number of photo capture strategies, and there always seems to be a case, a platform or certain devices, where some or all of the above strategies will fail in unexpected ways. I was able to find a strategy that uses the URI generation code below which seems to work in most if not all cases.
mPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new ContentValues());
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri);
startActivityForResult(intent,CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE_CONTENT_RESOLVER);
To contribute further to the discussion and help out newcomers I've created a sample/test app that shows several different strategies for photo capture implementation. Contributions of other implementations are definitely encouraged to add to the discussion.
https://github.com/deepwinter/AndroidCameraTester
Solution 4
I had the same problem where the OK button in camera app did nothing, both on emulator and on nexus one.
The problem went away after specifying a safe filename that is without white spaces, without special characters, in MediaStore.EXTRA_OUTPUT
Also, if you are specifying a file that resides in a directory that has not yet been created, you have to create it first. Camera app doesn't do mkdir for you.
Solution 5
The workflow you describe should work as you've described it. It might help if you could show us the code around the creation of the Intent. In general, the following pattern should let you do what you're trying.
private void saveFullImage() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file = new File(Environment.getExternalStorageDirectory(), "test.jpg");
outputFileUri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, TAKE_PICTURE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if ((requestCode == TAKE_PICTURE) && (resultCode == Activity.RESULT_OK)) {
// Check if the result includes a thumbnail Bitmap
if (data == null) {
// TODO Do something with the full image stored
// in outputFileUri. Perhaps copying it to the app folder
}
}
}
Note that it is the Camera Activity that will be creating and saving the file, and it's not actually part of your application, so it won't have write permission to your application folder. To save a file to your app folder, create a temporary file on the SD card and move it to your app folder in the onActivityResult
handler.
Related videos on Youtube
Drew
Updated on December 26, 2020Comments
-
Drew over 3 years
We are trying to use the native camera app to let the user take a new picture. It works just fine if we leave out the
EXTRA_OUTPUT extra
and returns the small Bitmap image. However, if weputExtra(EXTRA_OUTPUT,...)
on the intent before starting it, everything works until you try to hit the "Ok" button in the camera app. The "Ok" button just does nothing. The camera app stays open and nothing locks up. We can cancel out of it, but the file never gets written. What exactly do we have to do to getACTION_IMAGE_CAPTURE
to write the picture taken to a file?Edit: This is done via the
MediaStore.ACTION_IMAGE_CAPTURE
intent, just to be clear -
Drew over 14 yearsThis /should/ work, but the camera app's ok button just does nothing. We did get it working writing to the SD card, so I suspect this is a file permissions problem (though I thought that an application automatically had write permissions to it's personal directory). thanks for the help!
-
Reto Meier over 14 yearsYour app has write permission to it's personal directory -- the camera app (which is taking the picture) does not. You could move the file in the onActivityResult though, as that's within your app. Alternatively you could implement a camera Activity yourself, but that seems overkill.
-
Drew over 14 yearsRedoing the camera app seems to be a common but tedious approach... When we use getDir("images",MODE_WORLD_WRITEABLE), does that permission not apply to any file we tell it to create in that directory?
-
Reto Meier over 14 yearsNot necessarily. The permission is for the folder, not necessarily for the files within it.
-
Matthias about 13 yearswhere does the "_data" column come from? is there no constant for it?
-
Matthias about 13 yearsah, it's developer.android.com/reference/android/provider/… You really shouldn't use magic strings in code.
-
jwadsack about 13 yearsAndroidRuntime (2.1 emulator) throws NoSuchMethodError: java.io.File.setWritable
-
Arseniy almost 13 yearson Galaxy S: intent.getData() returns null, and moreover, camera app on Galaxy s inserts new photo into gallery by itself, but no uri returned. So if you insert photo from file into gallery, there will be duplicated photo.
-
Geetanjali almost 13 yearshey my device is not listed here and i have implemented by ur way.but my application still crashes i don knw the reason.please help me
-
swanson over 12 yearsMake sure you have
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
in your manifest if you are using newer than Android 1.5 -- spent a few hours debugging the camera stuff and this wasn't included so my saves would always fail. -
rOrlig over 12 yearsusing this code on droid-x and sony xpheria devices. Both devices return intent value as null. also droidx returns resultcode as 0 whereas xpheria returns resultcode as -1. Anyone know why that should be the case.
-
joey_g216 over 12 yearsThis works good for me, but every about 10 images or so, the blank file is not overwritten and I end up with a 0 byte file where the image should be. It's very annoying and has been tough to track down.
-
FM2020 about 12 yearsThe link to the "well documented bug" which is at the beginning of yanokwa's answer is incorrect. That bug is about calling the camera app without putExtra(EXTRA_OUTPUT,...)
-
Keith almost 12 yearson some devices, such as the nexus 7 with jelly bean, you need to change Environment.getExternalStorageDirectory().getName() to use .getAbsolutePath() instead of .getName()
-
Mohammad Ersan over 11 yearsyour link is not working anymore!! why, i saw it 2 weeks ago, and i wanted to use it :(
-
SHRISH M about 11 yearsI tested the code with Android devices with Android 2.2 and newer and all of them saved the image to the supplied path. So I guess that this should be standard behaviour to get images.
-
Pencilcheck about 11 yearscode.google.com/p/android/issues/detail?id=1480 Well, how do you explain this then?
-
Rose Perrone almost 11 yearsHas this bug been fixed yet?
-
Diana over 10 yearsAnd make sure you use
mkdirs()
instead ofmkdir()
if your path has more than one directory level and you want all of them created (mkdir
only creates the last one, the 'leaf' directory). I had some problems with that, and this answer helped me. -
Rakeeb Rajbhandari over 10 yearscan we use simple timestamps ?? or can the also make some errors ?? pleas do tag me when replied :)
-
Yenchi over 10 years@user2247689 I am not sure about the file name you created by "simple timestamps" but as long as they don't contain special characters not allowed by FAT format on SD card it should be ok I think.
-
Rich over 10 yearsThis was great. I've yet to test this across all my devices, but I'm assuming you have done so quite a bit already. There's so much noise on this topic, and this particular answer is so simple and clean. Works on Nexus 5 so far, which is where I first got a lot of reports that ACTION_IMAGE_CAPTURE wasn't working without EXTRA_OUTPUT. I do hope this works all across the board, but so far so good. Thx
-
Billy Coover over 10 years@deepwinter - Thank you sir. I was pulling my hair out but your content resolver solution works well on all the problematic scenarios I had.
-
StackJP over 9 yearsKind of late to this party but this has been the only solution to work for me. Thanks a bunch!
-
G_V over 9 yearsI have this right now, so it doesn't appear to be but WHO CAN TELL because this camera stuff has so little exposed while having so much complexity. I just want a Camera.OnPictureSnapListener that gives a bitmap, not all this intent generation, bugged bundles, camera not taking pictures crap. Their own code examples don't even work for this, it's ridiculous.
-
Standaa - Remember Monica over 8 yearsThanks a lot for the input I have been tearing my hairs over this. Well, here we are now, four years later. The bug still isn't fixed in Android 6.0 & Nexus 5.
-
prom85 over 8 yearscan I somehow retrieve the MediaStore.EXTRA_OUTPUT in
onActivityResult
or do I really have to remember it myself? I would have to persistantly save it so that my app even remembers it if it gets destroyed while a photo is taken... -
Renaud Favier about 8 years@Stanislasdrg I think I have the same problem right now, did you add anything to the list ? I have too a nexus 5 android 6.0 and the code here doen't seem to do it, even if I force to true the hasImageCaptureBug();
-
Renaud Favier about 8 years@Stanislasdrg to be specific the uri gave me by this fix is content://media/external/images/media/40192 but I found the pic in /pictures/145613944835.jpg
-
Standaa - Remember Monica about 8 years@RenaudFavier Did you properly add the nexus 5 in the list before ? Proper name is " devices.add("google/hammerhead/hammerhead") "
-
Renaud Favier about 8 years@Stanislasdrg yes but I still got the problem, I finaly decided to use CommonsWare library, for now it works way better
-
Igor Janković almost 8 yearsIt doesn't work on samsung galaxy note 3 with lolipop: ava.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getScheme()' on a null object reference
-
truthadjustr about 4 yearsThe above incomplete snippet does not merit the simplicity that it claimed. Surely, there are hidden complexities for the unfamiliar traveller. Such as scanning for presence or absence of the file. Such as wither it is publicly available or private to the app. Such as the need for a provider or getting a thumbnail only size. These are information gaps for the unwary traveller needs to be aware of.
-
julo over 3 yearsThis seems to be working for the set of devices I have been working with, which is good. One downside is that, if the user cancels the camera activity, then we will have inserted an empty item into the media store that doesn't get cleaned up. So if you do a media store query, you'll get back a uri that will throw a file not found exception when you try to read its contents. I am currently working around that by making sure my media store query filters for size > 0.