Android ACTION_IMAGE_CAPTURE Intent Android ACTION_IMAGE_CAPTURE Intent android android

Android ACTION_IMAGE_CAPTURE Intent


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

  1. you never get full sized images fromthe devices with the bug. you getpictures that are 512px wide thatare inserted into the image contentprovider. on devices without thebug, everything works as document,you get a big normal picture.

  2. you have to maintain the list. aswritten, it is possible for devicesto be flashed with a version ofandroid (say cyanogenmod'sbuilds) that has the bug fixed.if that happens, your code willcrash. the fix is to use the entiredevice fingerprint.


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.


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