Save image from Camera take picture intent to application private storage

3k views Asked by At

There is a lot of information here about how to create a file on external storage in android, pass the uri to ACTION_IMAGE_CAPTURE and then save the image there.

However, I want to create a file in Application's private storage (sometimes referred to as internal storage) and pass that file uri to ACTION_IMAGE_CAPTURE but Camera intent returns RESULT_CANCELED in onActivityResult.

What do I do?

private void checkWhetherCameraIsAvailableAndTakeAPicture() {
    // Check wether this device is able to take pictures
    if (PhotoHandler.isIntentAvailable(a, MediaStore.ACTION_IMAGE_CAPTURE)) {
        System.gc();
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File imageFile = null;

        try {
                if(a.application.user.isPublishImagesToGallery()){
                imageFile = a.application.photoHandler.createImageFileOnExternalStorage();
            } else {
                imageFile = a.application.photoHandler.createImageFileOnInternalStorage();
            }

            imagePath = imageFile.getAbsolutePath();
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile));
        } catch (IOException e) {
            e.printStackTrace();
            imageFile = null;
            imagePath = null;
        }
        startActivityForResult(takePictureIntent, Preferences.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA);
    } else { // Notify the user that their device is unable to take photos
        a.application.toastMaker.toastLong(ErrorMessages.DEVICE_UNABLE_TO_TAKE_PHOTOS);
    }
} // End of checkWhetherCameraIsAvailableAndTakeAPicture

public File createImageFileOnInternalStorage() throws IOException {
        return createTempFileOnGivenLocation();
    }

    private String imageFilename() {
        return filenamePrefix + Calendar.getInstance().getTimeInMillis();
    }

    private File createTempFileOnGivenLocation() throws IOException {
        File imageFile = File.createTempFile(imageFilename(), filenameSuffix, context.getFilesDir());
        setImagePathTemporary(imageFile.toString());

        return imageFile;
    }


@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == Preferences.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA) {
        if (resultCode != Activity.RESULT_CANCELED) {
            handlePhotoTakenWithCamera();
        } else {
            // ONACTIVITYRESULT Returns Here!
            new File(imagePath).delete())
        }
    } else if (requestCode == Preferences.REQUEST_CODE_PICK_IMAGES_FROM_GALLERY) {
        if (resultCode != Activity.RESULT_CANCELED) {
            handlePhotosPickedFromGallery(data);
        }
    }
} // End of onActivityResult
2

There are 2 answers

1
Ahmad Nawaz On

Internal storage is private for each app. Camera App can't access the internal storage of your application. Best way to get image in you internal storage is.

1) take image using your own camera inside of app

or

2) Take image using camera intent to capture a picture which will save image to external storage. onActivityResult copy image to your app's internal storage and delete from external storage. Code for Copying file can be found in this answer. https://stackoverflow.com/a/4770586/4811470

1
simekadam On

As is stated in this answer, the Camera app can't directly write to your app's internal storage.

However, you can write a Content Provider which will be able to consume data from Camera app as a stream and save it yourself.

This is how to make the Camera app know where to put your file.

Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
Uri uri = Uri.withAppendedPath(CONTENT_URI_OF_YOUR_CONTENT_PROVIDER, "id_of_your_image");
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(takePictureIntent, CAMERA_REQUEST);  

How to build the actual content provider is IMHO little bit out of the scope of this question. Read the docs linked above and search SO for related questions. One hint, you have to implement the insert method in order to do it. It might look like this.

public Uri insert(Uri uri, ContentValues values) {
    String name = uri.getPath();
    File file = new File(name);     
    OutputStream stream = new FileOutputStream(file);
    byte[] data = (byte[]) values.get(KEY_FILE_CONTENT);
    try {
        stream.write(data);
        stream.flush();
        stream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return uri;
}

But since how much are content providers complicated the code above wouldn't probably work for you out of the box.