Android – Camera not working/saving when using Cache Uri as MediaStore.EXTRA_OUTPUT

androidandroid-cameraandroid-intent

I am trying to get the full image after taking a picture from a Fragment.

If I use the Uri from the file (Uri.fromFile(file)), the camera won't exit after taking the photo and tapping on the 'ok' button (looks like can't write to the Uri or who knows what).

Using the File String, in the form of '/data/data/com.package.bla/cache/img198346262jpg', it's not working as well (The file is there, but it's empty because the camera is not saving anything on it).

What I tried so far:

  • Deleting the file after creating it, as this example does. However, the file doesn't exist after the camera exits.
  • Added External Storage READ permission, just in case

So I have no idea why the image is not being saved and already spent/wasted a lot of time testing and figuring why it's not working.

Fragment:

private void launchCamera() {
    Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    File outputDir = getActivity().getCacheDir();
    File file = null;
    try {
        file = File.createTempFile("img", "jpg", outputDir);
    } catch (IOException e) {
        e.printStackTrace();
    }
    if (file != null) {
        mImageUri = Uri.fromFile(file);   //using Uri is not even exiting the camera
        //mImageUri = File.toString();    //If I use String instead of an Uri, it works better (ie, can accept camera photo)
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
        startActivityForResult(cameraIntent, RESULT_TAKE_IMAGE);
    }
}


public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == Activity.RESULT_OK) {
        Bitmap original = BitmapFactory.decodeFile(mImageUri.toString(), bounds);
    }
}

Edited code, mImageUri. As explained, if I use Uri I can't even accept the photo in the camera app. Using a String will let me accept the photo, though the photo is not actually saved (ie the file has 0 bytes inside it).

EXPLANATION: The problem was related to saving into the cache directory. Maybe it's a bug, I am missing a permission or the camera app just can't save into your application private data directory. Adding Permission FLAG_GRANT_WRITE_URI_PERMISSION didn't solve it. Related posts: Store image from camera into private app cache directory AND Saving camera data to cache when launched via intent

UPDATE From Android 2.2 onwards getExternalCacheDir() method can be used instead of getCacheDir()

Best Answer

from android 26+ Uri.fromFile will not work, you should use File provider instead.

AndroidManifest.xml

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <application
        .........

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.mydomain.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>

res/xml/file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external"
        path="." />
</paths>

finally

final Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

// output file
File path = new File(Environment.getExternalStorageDirectory(), "tmp.mp4");

// com.mydomain.fileprovider is authorities (manifest)
// getUri from file
Uri uri = FileProvider.getUriForFile(this, "com.mydomain.fileprovider", path);

takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(takeVideoIntent, 99);

tested on android 8.0 and 5.1.1

Update: on some device built-in camera would not support for EXTRA_OUTPUT, so if you want to work on all devices, build your own camera module.

Related Topic