7

I am trying to get an image from the camera and save it directly to my app's private files directory. For security concerns, the image should not be publicly accessible at any time.

In general, the way you grant temporary access to a private file is to use a ContentProvider and set the GRANT_WRITE_URI_PERMISSION flag in the Intent. Following the documentation in FileProvider, I have done the following:

AndroidManfiest.xml

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

res/xml/file_paths.xml

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_images" path="images/"/>
</paths>

When launching the camera activity, I execute the following from an activity:

File imageFile = getInternalImageFile();
Uri captureUri = FileProvider.getUriForFile(this, "com.my.domain", imageFile);

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

// grant temporary access to the file
intent.setData(captureUri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

// tell the camera where to save the file
intent.putExtra(MediaStore.EXTRA_OUTPUT, captureUri);

startActivityForResult(intent, IMAGE_CAPTURE_REQUEST_CODE);

This however results in the camera app returning immediately without doing anything. I suspect because it's not expecting there to be any data set on intent (Intent.setData()).

The above strategy isn't working out so well. So, how can I securely save an image captured from the camera directly to my app's private files directory?

Nathan Taylor
  • 879
  • 1
  • 9
  • 16
  • the thing is that the grant access to private file thing only works if the app actually uses it. In you case, I would save anywhere, then move it to private storage. – njzk2 Nov 18 '13 at 22:08
  • @njzk2 that is actually what my app does currently, but it was determined that saving the file to external storage (or anything publicly accessible) for any period of time is a security risk. Hence the need to save it _directly_ to internal storage. – Nathan Taylor Nov 18 '13 at 22:48
  • you can always reimplement the camera activity in your app. – njzk2 Nov 18 '13 at 22:49

2 Answers2

10

i had same issue, but i solved it using clipData.

Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setClipData(ClipData.newRawUri(null, contentUri));
intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);

http://developer.android.com/reference/android/content/Intent.html#setClipData(android.content.ClipData)

The ClipData in an intent is not used for Intent matching or other such operations. Semantically it is like extras, used to transmit additional data with the Intent. The main feature of using this over the extras for data is that FLAG_GRANT_READ_URI_PERMISSION and FLAG_GRANT_WRITE_URI_PERMISSION will operate on any URI items included in the clip data. This is useful, in particular, if you want to transmit an Intent containing multiple content: URIs for which the recipient may not have global permission to access the content provider.

i hope this help you.

Pd: Sorry for my english. :)

julioyg
  • 101
  • 1
  • 4
  • 4
    Hi, I am having difficulty with setting *contentURI*, is it similar to *captureUri* as in the question ? A bit of code about defining *contectURI* would really be a great help. – Deepak Negi Aug 11 '14 at 11:28
  • This is a great answer. I have searched for hours, and I haven't seen any documentation or example mentioning setClipData(). Without it, I always got a SecurityException ("Permission Denial: opening provider..."). I still have to figure out how to access the file stored through my camera, but at least it seems like it has been stored _somewhere_ ;) – TheOperator Oct 09 '15 at 13:14
1

So, how can I securely save an image captured from the camera directly to my app's private files directory?

Take the picture yourself, using android.hardware.Camera. There is no guarantee that the user will have a camera app available that knows how to save data to content:// Uri paths. They are supposed to support them, but not all do. For example, the Google Camera app did not support a content:// Uri for ACTION_VIDEO_CAPTURE up through June 2016.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491