4

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
Sandeep Singh
  • 1,117
  • 2
  • 11
  • 29
Kaloyan Roussev
  • 14,515
  • 21
  • 98
  • 180

2 Answers2

1

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

Community
  • 1
  • 1
Ahmad Nawaz
  • 1,129
  • 7
  • 26
1

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.

Community
  • 1
  • 1
simekadam
  • 7,334
  • 11
  • 56
  • 79
  • @J.K. I've edited the question with some further info. BTW. Mine approach is IMHO superior to the one from the previous answer. You don't have to copy the file yourself, the camera writes it directly to the internal storage through the content provider. (Also it means that the image probably won't be ever stored in a public directory - security:) - but this actually depends on the camera app itself) – simekadam Jun 09 '15 at 09:26
  • Thank you a lot. I will try that if I can – Kaloyan Roussev Jun 09 '15 at 09:29