From 672b052115c1979520a9c3d5598039a595b9a42c Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Fri, 22 Apr 2016 13:34:20 +0100 Subject: [PATCH] Updates training/camera/photobasics.jd with FileProvider details As of Android N, passing file:// URIs across package boundaries throws a FileUriExposedException. This has caused frustration among app developers trying to use our example as boilerplate code. This patch replaces the "take picture" example with one that uses content:// URIs and FileProvider instead. Bug: 27636012 Change-Id: I9f0b4d9bbcd6b4bfa770dd1e4ad37f321e22195f --- docs/html/training/camera/photobasics.jd | 62 ++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/docs/html/training/camera/photobasics.jd b/docs/html/training/camera/photobasics.jd index efac54834676d..bfea0f7463e2e 100644 --- a/docs/html/training/camera/photobasics.jd +++ b/docs/html/training/camera/photobasics.jd @@ -175,7 +175,8 @@ attribute:

Note: Files you save in the directories provided by -{@link android.content.Context#getExternalFilesDir getExternalFilesDir()} are deleted +{@link android.content.Context#getExternalFilesDir getExternalFilesDir()} or +{@link android.content.Context#getFilesDir getFilesDir()} are deleted when the user uninstalls your app.

Once you decide the directory for the file, you need to create a @@ -190,8 +191,7 @@ private File createImageFile() throws IOException { // Create an image file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; - File storageDir = Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_PICTURES); + File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File image = File.createTempFile( imageFileName, /* prefix */ ".jpg", /* suffix */ @@ -225,14 +225,66 @@ private void dispatchTakePictureIntent() { } // Continue only if the File was successfully created if (photoFile != null) { - takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, - Uri.fromFile(photoFile)); + Uri photoURI = FileProvider.getUriForFile(this, + "com.example.android.fileprovider", + photoFile); + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); } } } +

Note: We are using {@link +android.support.v4.content.FileProvider#getUriForFile} which returns a content:// +URI. For more recent apps targeting Android N and higher, passing a file:// URI +across a package boundary causes a {@link android.os.FileUriExposedException +FileUriExposedException}. +Therefore, we now present a more generic way of storing images using a +{@link android.support.v4.content.FileProvider FileProvider}. +

+ +Now, you need to configure the {@link android.support.v4.content.FileProvider +FileProvider}. In your app's manifest, add a provider to your application: + +
+<application>
+   ...
+   <provider
+        android:name="android.support.v4.content.FileProvider"
+        android:authorities="com.example.android.fileprovider"
+        android:exported="false"
+        android:grantUriPermissions="true">
+        <meta-data
+            android:name="android.support.FILE_PROVIDER_PATHS"
+            android:resource="@xml/file_paths"></meta-data>
+    </provider>
+    ...
+</application>
+
+ +Make sure that the authorities string matches the second argument to {@link +android.support.v4.content.FileProvider#getUriForFile}. +In the meta-data section of the provider definition, you can see that +the provider expects eligible paths to be configured in a dedicated resource file, +res/xml/file_paths.xml. Here is the content required for this particular +example: + +
+<?xml version="1.0" encoding="utf-8"?>
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />
+</paths>
+
+ +The path component corresponds to the path that is returned by +{@link android.content.Context#getExternalFilesDir getExternalFilesDir()} +when called with {@link android.os.Environment#DIRECTORY_PICTURES +Environment.DIRECTORY_PICTURES}. Make sure that you replace +com.example.package.name with the actual package name of your +app. Also, checkout the documentation of {@link android.support.v4.content.FileProvider} for +an extensive description of path specifiers that you can use besides +external-path.

Add the Photo to a Gallery