- FileProvider
- Class Overview
- Defining a FileProvider
- Specifying Available Files
- Generating the Content URI for a File
- Granting Temporary Permissions to a URI
- Serving a Content URI to Another App
- More Information
- Classes
- FileProvider
- Subclasses:
- Gradle dependencies
- Androidx artifact mapping:
- Androidx class mapping:
- Overview
- Defining a FileProvider
- Specifying Available Files
- Generating the Content URI for a File
- Granting Temporary Permissions to a URI
- Grant Permission to a Specific Package
- Include the Permission in an Intent
- Serving a Content URI to Another App
- More Information
- Summary
- Constructors
- Methods
- Parameters:
- Parameters:
- Returns:
- Parameters:
- Returns:
- Parameters:
- Returns:
- Parameters:
- Returns:
- Parameters:
- Returns:
- Parameters:
- Returns:
- Source
- Specifying Available Files
- Generating the Content URI for a File
- Granting Temporary Permissions to a URI
- Grant Permission to a Specific Package
- Include the Permission in an Intent
- Serving a Content URI to Another App
- More Information
FileProvider
java.lang.Object | ||
↳ | android.content.ContentProvider | |
↳ | android.support.v4.content.FileProvider |
Class Overview
FileProvider is a special subclass of ContentProvider that facilitates secure sharing of files associated with an app by creating a content:// Uri for a file instead of a file:/// Uri .
A content URI allows you to grant read and write access using temporary access permissions. When you create an Intent containing a content URI, in order to send the content URI to a client app, you can also call Intent.setFlags() to add permissions. These permissions are available to the client app for as long as the stack for a receiving Activity is active. For an Intent going to a Service , the permissions are available as long as the Service is running.
In comparison, to control access to a file:/// Uri you have to modify the file system permissions of the underlying file. The permissions you provide become available to any app, and remain in effect until you change them. This level of access is fundamentally insecure.
The increased level of file access security offered by a content URI makes FileProvider a key part of Android’s security infrastructure.
This overview of FileProvider includes the following topics:
Defining a FileProvider
Since the default functionality of FileProvider includes content URI generation for files, you don’t need to define a subclass in code. Instead, you can include a FileProvider in your app by specifying it entirely in XML. To specify the FileProvider component itself, add a
element to your app manifest. Set the android:name attribute to android.support.v4.content.FileProvider . Set the android:authorities attribute to a URI authority based on a domain you control; for example, if you control the domain mydomain.com you should use the authority com.mydomain.fileprovider . Set the android:exported attribute to false ; the FileProvider does not need to be public. Set the android:grantUriPermissions attribute to true , to allow you to grant temporary access to files. For example:
If you want to override any of the default behavior of FileProvider methods, extend the FileProvider class and use the fully-qualified class name in the android:name attribute of the
Specifying Available Files
element. For example, the following paths element tells FileProvider that you intend to request content URIs for the images/ subdirectory of your private file area.
element must contain one or more of the following child elements:
Represents files in the files/ subdirectory of your app’s internal storage area. This subdirectory is the same as the value returned by Context.getFilesDir() . Represents files in the root of your app’s external storage area. The path Context.getExternalFilesDir() returns the files/ subdirectory of this this root. Represents files in the cache subdirectory of your app’s internal storage area. The root path of this subdirectory is the same as the value returned by getCacheDir() .
These child elements all use the same attributes:
name=»name» A URI path segment. To enforce security, this value hides the name of the subdirectory you’re sharing. The subdirectory name for this value is contained in the path attribute. path=»path» The subdirectory you’re sharing. While the name attribute is a URI path segment, the path value is an actual subdirectory name. Notice that the value refers to a subdirectory, not an individual file or files. You can’t share a single file by its file name, nor can you specify a subset of files using wildcards.
You must specify a child element of
for each directory that contains files for which you want content URIs. For example, these XML elements specify two directories:
element and its children in an XML file in your project. For example, you can add them to a new file called res/xml/file_paths.xml . To link this file to the FileProvider, add a element as a child of the
element that defines the FileProvider. Set the element’s «android:name» attribute to android.support.FILE_PROVIDER_PATHS . Set the element’s «android:resource» attribute to @xml/file_paths (notice that you don’t specify the .xml extension). For example:
Generating the Content URI for a File
To share a file with another app using a content URI, your app has to generate the content URI. To generate the content URI, create a new File for the file, then pass the File to getUriForFile() . You can send the content URI returned by getUriForFile() to another app in an Intent . The client app that receives the content URI can open the file and access its contents by calling ContentResolver.openFileDescriptor to get a ParcelFileDescriptor .
For example, suppose your app is offering files to other apps with a FileProvider that has the authority com.mydomain.fileprovider . To get a content URI for the file default_image.jpg in the images/ subdirectory of your internal storage add the following code: As a result of the previous snippet, getUriForFile() returns the content URI content://com.mydomain.fileprovider/my_images/default_image.jpg .
Granting Temporary Permissions to a URI
Permissions granted in an Intent remain in effect while the stack of the receiving Activity is active. When the stack finishes, the permissions are automatically removed. Permissions granted to one Activity in a client app are automatically extended to other components of that app.
Serving a Content URI to Another App
There are a variety of ways to serve the content URI for a file to a client app. One common way is for the client app to start your app by calling startActivityResult() , which sends an Intent to your app to start an Activity in your app. In response, your app can immediately return a content URI to the client app or present a user interface that allows the user to pick a file. In the latter case, once the user picks the file your app can return its content URI. In both cases, your app returns the content URI in an Intent sent via setResult() .
You can also put the content URI in a ClipData object and then add the object to an Intent you send to a client app. To do this, call Intent.setClipData() . When you use this approach, you can add multiple ClipData objects to the Intent , each with its own content URI. When you call Intent.setFlags() on the Intent to set temporary access permissions, the same permissions are applied to all of the content URIs.
Note: The Intent.setClipData() method is only available in platform version 16 (Android 4.1) and later. If you want to maintain compatibility with previous versions, you should send one content URI at a time in the Intent . Set the action to ACTION_SEND and put the URI in data by calling setData() .
More Information
To learn more about FileProvider, see the Android training class Sharing Files Securely with URIs.
Источник
Classes
FileProvider
Subclasses:
Gradle dependencies
compile group: ‘androidx.core’, name: ‘core’, version: ‘1.5.0-alpha05’
- groupId: androidx.core
- artifactId: core
- version: 1.5.0-alpha05
Artifact androidx.core:core:1.5.0-alpha05 it located at Google repository (https://maven.google.com/)
Androidx artifact mapping:
Androidx class mapping:
Overview
FileProvider is a special subclass of that facilitates secure sharing of files associated with an app by creating a content:// for a file instead of a file:/// .
A content URI allows you to grant read and write access using temporary access permissions. When you create an containing a content URI, in order to send the content URI to a client app, you can also call to add permissions. These permissions are available to the client app for as long as the stack for a receiving is active. For an going to a , the permissions are available as long as the is running.
In comparison, to control access to a file:/// you have to modify the file system permissions of the underlying file. The permissions you provide become available to any app, and remain in effect until you change them. This level of access is fundamentally insecure.
The increased level of file access security offered by a content URI makes FileProvider a key part of Android’s security infrastructure.
This overview of FileProvider includes the following topics:
Defining a FileProvider
Since the default functionality of FileProvider includes content URI generation for files, you don’t need to define a subclass in code. Instead, you can include a FileProvider in your app by specifying it entirely in XML. To specify the FileProvider component itself, add a
element to your app manifest. Set the android:name attribute to androidx.core.content.FileProvider . Set the android:authorities attribute to a URI authority based on a domain you control; for example, if you control the domain mydomain.com you should use the authority com.mydomain.fileprovider . Set the android:exported attribute to false ; the FileProvider does not need to be public. Set the android:grantUriPermissions attribute to true , to allow you to grant temporary access to files. For example:
If you want to override any of the default behavior of FileProvider methods, extend the FileProvider class and use the fully-qualified class name in the android:name attribute of the
Specifying Available Files
element. For example, the following paths element tells FileProvider that you intend to request content URIs for the images/ subdirectory of your private file area.
element must contain one or more of the following child elements:
Represents files in the files/ subdirectory of your app’s internal storage area. This subdirectory is the same as the value returned by . Represents files in the cache subdirectory of your app’s internal storage area. The root path of this subdirectory is the same as the value returned by . Represents files in the root of the external storage area. The root path of this subdirectory is the same as the value returned by . Represents files in the root of your app’s external storage area. The root path of this subdirectory is the same as the value returned by Context#getExternalFilesDir(String) Context.getExternalFilesDir(null). Represents files in the root of your app’s external cache area. The root path of this subdirectory is the same as the value returned by . Represents files in the root of your app’s external media area. The root path of this subdirectory is the same as the value returned by the first result of .
Note: this directory is only available on API 21+ devices.
These child elements all use the same attributes:
name=»name» A URI path segment. To enforce security, this value hides the name of the subdirectory you’re sharing. The subdirectory name for this value is contained in the path attribute. path=»path» The subdirectory you’re sharing. While the name attribute is a URI path segment, the path value is an actual subdirectory name. Notice that the value refers to a subdirectory, not an individual file or files. You can’t share a single file by its file name, nor can you specify a subset of files using wildcards.
You must specify a child element of
for each directory that contains files for which you want content URIs. For example, these XML elements specify two directories:
element and its children in an XML file in your project. For example, you can add them to a new file called res/xml/file_paths.xml . To link this file to the FileProvider, add a element as a child of the
element that defines the FileProvider. Set the element’s «android:name» attribute to android.support.FILE_PROVIDER_PATHS . Set the element’s «android:resource» attribute to @xml/file_paths (notice that you don’t specify the .xml extension). For example:
Generating the Content URI for a File
To share a file with another app using a content URI, your app has to generate the content URI. To generate the content URI, create a new java.io.File for the file, then pass the java.io.File to getUriForFile(). You can send the content URI returned by getUriForFile() to another app in an . The client app that receives the content URI can open the file and access its contents by calling to get a .
For example, suppose your app is offering files to other apps with a FileProvider that has the authority com.mydomain.fileprovider . To get a content URI for the file default_image.jpg in the images/ subdirectory of your internal storage add the following code: As a result of the previous snippet, getUriForFile() returns the content URI content://com.mydomain.fileprovider/my_images/default_image.jpg .
Granting Temporary Permissions to a URI
Grant Permission to a Specific Package
Call the method for the content:// , using the desired mode flags. This grants temporary access permission for the content URI to the specified package, according to the value of the the mode_flags parameter, which you can set to , or both. The permission remains in effect until you revoke it by calling or until the device reboots.
Include the Permission in an Intent
To allow the user to choose which app receives the intent, and the permission to access the content, do the following:
- Put the content URI in an by calling .
Call the method with either or or both.
To support devices that run a version between Android 4.1 (API level 16) and Android 5.1 (API level 22) inclusive, create a object from the content URI, and set the access permissions on the ClipData object:
Permissions granted in an remain in effect while the stack of the receiving is active. When the stack finishes, the permissions are automatically removed. Permissions granted to one in a client app are automatically extended to other components of that app.
Serving a Content URI to Another App
There are a variety of ways to serve the content URI for a file to a client app. One common way is for the client app to start your app by calling , which sends an to your app to start an in your app. In response, your app can immediately return a content URI to the client app or present a user interface that allows the user to pick a file. In the latter case, once the user picks the file your app can return its content URI. In both cases, your app returns the content URI in an sent via .
You can also put the content URI in a object and then add the object to an you send to a client app. To do this, call . When you use this approach, you can add multiple objects to the , each with its own content URI. When you call on the to set temporary access permissions, the same permissions are applied to all of the content URIs.
Note: The method is only available in platform version 16 (Android 4.1) and later. If you want to maintain compatibility with previous versions, you should send one content URI at a time in the . Set the action to and put the URI in data by calling .
More Information
To learn more about FileProvider, see the Android training class Sharing Files Securely with URIs.
Summary
Methods | |
---|---|
public void | attachInfo(Context context, ProviderInfo info) After the FileProvider is instantiated, this method is called to provide the system with information about the provider. |
public int | delete(Uri uri, java.lang.String selection, java.lang.String selectionArgs[]) Deletes the file associated with the specified content URI, as returned by getUriForFile(). |
public java.lang.String | getType(Uri uri) Returns the MIME type of a content URI returned by getUriForFile(). |
public static Uri | getUriForFile(Context context, java.lang.String authority, java.io.File file) Return a content URI for a given java.io.File . |
public static Uri | getUriForFile(Context context, java.lang.String authority, java.io.File file, java.lang.String displayName) Return a content URI for a given java.io.File . |
public Uri | insert(Uri uri, ContentValues values) By default, this method throws an java.lang.UnsupportedOperationException . |
public boolean | onCreate() The default FileProvider implementation does not need to be initialized. |
public ParcelFileDescriptor | openFile(Uri uri, java.lang.String mode) By default, FileProvider automatically returns the for a file associated with a content:// . |
public Cursor | query(Uri uri, java.lang.String projection[], java.lang.String selection, java.lang.String selectionArgs[], java.lang.String sortOrder) Use a content URI returned by getUriForFile() to get information about a file managed by the FileProvider. |
public int | update(Uri uri, ContentValues values, java.lang.String selection, java.lang.String selectionArgs[]) By default, this method throws an java.lang.UnsupportedOperationException . |
from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructors
Methods
The default FileProvider implementation does not need to be initialized. If you want to override this method, you must provide your own subclass of FileProvider.
After the FileProvider is instantiated, this method is called to provide the system with information about the provider.
Parameters:
context: A for the current component.
info: A for the new provider.
Return a content URI for a given java.io.File . Specific temporary permissions for the content URI can be set with , or added to an by calling and then ; in both cases, the applicable flags are and . A FileProvider can only return a content for file paths defined in their
meta-data element. See the Class Overview for more information.
Parameters:
context: A for the current component.
authority: The authority of a FileProvider defined in a
element in your app’s manifest.
file: A java.io.File pointing to the filename for which you want a content .
Returns:
A content URI for the file.
Return a content URI for a given java.io.File . Specific temporary permissions for the content URI can be set with , or added to an by calling and then ; in both cases, the applicable flags are and . A FileProvider can only return a content for file paths defined in their
meta-data element. See the Class Overview for more information.
Parameters:
context: A for the current component.
authority: The authority of a FileProvider defined in a
element in your app’s manifest.
file: A java.io.File pointing to the filename for which you want a content .
displayName: The filename to be displayed. This can be used if the original filename is undesirable.
Returns:
A content URI for the file.
Use a content URI returned by getUriForFile() to get information about a file managed by the FileProvider. FileProvider reports the column names defined in : For more information, see .
Parameters:
uri: A content URI returned by FileProvider.getUriForFile(Context, String, File).
projection: The list of columns to put into the . If null all columns are included.
selection: Selection criteria to apply. If null then all data that matches the content URI is returned.
selectionArgs: An array of java.lang.String , containing arguments to bind to the selection parameter. The query method scans selection from left to right and iterates through selectionArgs, replacing the current «?» character in selection with the value at the current position in selectionArgs. The values are bound to selection as java.lang.String values.
sortOrder: A java.lang.String containing the column name(s) on which to sort the resulting .
Returns:
A containing the results of the query.
Returns the MIME type of a content URI returned by getUriForFile().
Parameters:
uri: A content URI returned by getUriForFile().
Returns:
If the associated file has an extension, the MIME type associated with that extension; otherwise application/octet-stream .
By default, this method throws an java.lang.UnsupportedOperationException . You must subclass FileProvider if you want to provide different functionality.
By default, this method throws an java.lang.UnsupportedOperationException . You must subclass FileProvider if you want to provide different functionality.
Deletes the file associated with the specified content URI, as returned by getUriForFile(). Notice that this method does not throw an java.io.IOException ; you must check its return value.
Parameters:
uri: A content URI for a file, as returned by getUriForFile().
selection: Ignored. Set to null.
selectionArgs: Ignored. Set to null.
Returns:
1 if the delete succeeds; otherwise, 0.
By default, FileProvider automatically returns the for a file associated with a content:// . To get the , call . To override this method, you must provide your own subclass of FileProvider.
Parameters:
uri: A content URI associated with a file, as returned by getUriForFile().
mode: Access mode for the file. May be «r» for read-only access, «rw» for read and write access, or «rwt» for read and write access that truncates any existing file.
Returns:
A new with which you can access the file.
Source
* If you want to override any of the default behavior of FileProvider methods, extend * the FileProvider class and use the fully-qualified class name in the android:name * attribute of the
Specifying Available Files
element. * For example, the following paths element tells FileProvider that you intend to * request content URIs for the images/ subdirectory of your private file area. * *
element must contain one or more of the following child elements: *
* * * * * * Represents files in the files/ subdirectory of your app’s internal storage * area. This subdirectory is the same as the value returned by <@link Context#getFilesDir() * Context.getFilesDir()>. * * * * * * Represents files in the cache subdirectory of your app’s internal storage area. The root path * of this subdirectory is the same as the value returned by <@link Context#getCacheDir() * getCacheDir()>. * * * * * * Represents files in the root of the external storage area. The root path of this subdirectory * is the same as the value returned by * <@link Environment#getExternalStorageDirectory() Environment.getExternalStorageDirectory()>. * * * * * * Represents files in the root of your app’s external storage area. The root path of this * subdirectory is the same as the value returned by * <@code Context#getExternalFilesDir(String) Context.getExternalFilesDir(null)>. * * * * * * Represents files in the root of your app’s external cache area. The root path of this * subdirectory is the same as the value returned by * <@link Context#getExternalCacheDir() Context.getExternalCacheDir()>. * * * * * * Represents files in the root of your app’s external media area. The root path of this * subdirectory is the same as the value returned by the first result of * <@link Context#getExternalMediaDirs() Context.getExternalMediaDirs()>. *
Note: this directory is only available on API 21+ devices.
* These child elements all use the same attributes: *
* * * name=»name» * * * A URI path segment. To enforce security, this value hides the name of the subdirectory * you’re sharing. The subdirectory name for this value is contained in the * path attribute. * * * path=»path» * * * The subdirectory you’re sharing. While the name attribute is a URI path * segment, the path value is an actual subdirectory name. Notice that the * value refers to a subdirectory, not an individual file or files. You can’t * share a single file by its file name, nor can you specify a subset of files using * wildcards. * * *
* You must specify a child element of
for each directory that contains * files for which you want content URIs. For example, these XML elements specify two directories: * *
element and its children in an XML file in your project. * For example, you can add them to a new file called res/xml/file_paths.xml . * To link this file to the FileProvider, add a * element * as a child of the
element that defines the FileProvider. Set the * element’s «android:name» attribute to * android.support.FILE_PROVIDER_PATHS . Set the element’s «android:resource» attribute * to @xml/file_paths (notice that you don’t specify the .xml * extension). For example: * *
Generating the Content URI for a File
* To share a file with another app using a content URI, your app has to generate the content URI. * To generate the content URI, create a new <@link File>for the file, then pass the <@link File>* to <@link #getUriForFile(Context, String, File) getUriForFile()>. You can send the content URI * returned by <@link #getUriForFile(Context, String, File) getUriForFile()>to another app in an * <@link android.content.Intent>. The client app that receives the content URI can open the file * and access its contents by calling * <@link android.content.ContentResolver#openFileDescriptor(Uri, String) * ContentResolver.openFileDescriptor>to get a <@link ParcelFileDescriptor>. *
* For example, suppose your app is offering files to other apps with a FileProvider that has the * authority com.mydomain.fileprovider . To get a content URI for the file * default_image.jpg in the images/ subdirectory of your internal storage * add the following code: * * As a result of the previous snippet, * <@link #getUriForFile(Context, String, File) getUriForFile()>returns the content URI * content://com.mydomain.fileprovider/my_images/default_image.jpg . *
Granting Temporary Permissions to a URI
Grant Permission to a Specific Package
* Call the method * <@link Context#grantUriPermission(String, Uri, int) * Context.grantUriPermission(package, Uri, mode_flags)>for the content:// * <@link Uri>, using the desired mode flags. This grants temporary access permission for the * content URI to the specified package, according to the value of the * the mode_flags parameter, which you can set to * <@link Intent#FLAG_GRANT_READ_URI_PERMISSION>, <@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION>* or both. The permission remains in effect until you revoke it by calling * <@link Context#revokeUriPermission(Uri, int) revokeUriPermission()>or until the device * reboots. *
Include the Permission in an Intent
* To allow the user to choose which app receives the intent, and the permission to access the * content, do the following: *
* To support devices that run a version between Android 4.1 (API level 16) and Android 5.1 * (API level 22) inclusive, create a <@link android.content.ClipData>object from the content * URI, and set the access permissions on the ClipData object: *
* Permissions granted in an <@link Intent>remain in effect while the stack of the receiving * <@link android.app.Activity>is active. When the stack finishes, the permissions are * automatically removed. Permissions granted to one <@link android.app.Activity>in a client * app are automatically extended to other components of that app. *
Serving a Content URI to Another App
* There are a variety of ways to serve the content URI for a file to a client app. One common way * is for the client app to start your app by calling * <@link android.app.Activity#startActivityForResult(Intent, int, Bundle) startActivityResult()>, * which sends an <@link Intent>to your app to start an <@link android.app.Activity>in your app. * In response, your app can immediately return a content URI to the client app or present a user * interface that allows the user to pick a file. In the latter case, once the user picks the file * your app can return its content URI. In both cases, your app returns the content URI in an * <@link Intent>sent via <@link android.app.Activity#setResult(int, Intent) setResult()>. *
* You can also put the content URI in a <@link android.content.ClipData>object and then add the * object to an <@link Intent>you send to a client app. To do this, call * <@link Intent#setClipData(ClipData) Intent.setClipData()>. When you use this approach, you can * add multiple <@link android.content.ClipData>objects to the <@link Intent>, each with its own * content URI. When you call <@link Intent#setFlags(int) Intent.setFlags()>on the <@link Intent>* to set temporary access permissions, the same permissions are applied to all of the content * URIs. *
* Note: The <@link Intent#setClipData(ClipData) Intent.setClipData()>method is * only available in platform version 16 (Android 4.1) and later. If you want to maintain * compatibility with previous versions, you should send one content URI at a time in the * <@link Intent>. Set the action to <@link Intent#ACTION_SEND>and put the URI in data by calling * <@link Intent#setData setData()>. *
More Information
* To learn more about FileProvider, see the Android training class * Sharing Files Securely with URIs. *
*/ public class FileProvider extends ContentProvider < private static final String[] COLUMNS = < OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE >; private static final String META_DATA_FILE_PROVIDER_PATHS = «android.support.FILE_PROVIDER_PATHS»; private static final String TAG_ROOT_PATH = «root-path»; private static final String TAG_FILES_PATH = «files-path»; private static final String TAG_CACHE_PATH = «cache-path»; private static final String TAG_EXTERNAL = «external-path»; private static final String TAG_EXTERNAL_FILES = «external-files-path»; private static final String TAG_EXTERNAL_CACHE = «external-cache-path»; private static final String TAG_EXTERNAL_MEDIA = «external-media-path»; private static final String ATTR_NAME = «name»; private static final String ATTR_PATH = «path»; private static final String DISPLAYNAME_FIELD = «displayName»; private static final File DEVICE_ROOT = new File(«/»); @GuardedBy(«sCache») private static HashMap sCache = new HashMap (); private PathStrategy mStrategy; /** * The default FileProvider implementation does not need to be initialized. If you want to * override this method, you must provide your own subclass of FileProvider. */ @Override public boolean onCreate() < return true; >/** * After the FileProvider is instantiated, this method is called to provide the system with * information about the provider. * * @param context A <@link Context>for the current component. * @param info A <@link ProviderInfo>for the new provider. */ @SuppressWarnings(«StringSplitter») @Override public void attachInfo(@NonNull Context context, @NonNull ProviderInfo info) < super.attachInfo(context, info); // Check our security attributes if (info.exported) < throw new SecurityException("Provider must not be exported"); >if (!info.grantUriPermissions) < throw new SecurityException("Provider must grant uri permissions"); >mStrategy = getPathStrategy(context, info.authority.split(«;»)[0]); > /** * Return a content URI for a given <@link File>. Specific temporary * permissions for the content URI can be set with * <@link Context#grantUriPermission(String, Uri, int)>, or added * to an <@link Intent>by calling <@link Intent#setData(Uri) setData()>and then * <@link Intent#setFlags(int) setFlags()>; in both cases, the applicable flags are * <@link Intent#FLAG_GRANT_READ_URI_PERMISSION>and * <@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION>. A FileProvider can only return a * content <@link Uri>for file paths defined in their
* meta-data element. See the Class Overview for more information. * * @param context A <@link Context>for the current component. * @param authority The authority of a <@link FileProvider>defined in a * <@code
> element in your app’s manifest. * @param file A <@link File>pointing to the filename for which you want a * content <@link Uri>. * @return A content URI for the file. * @throws IllegalArgumentException When the given <@link File>is outside * the paths supported by the provider. */ public static Uri getUriForFile(@NonNull Context context, @NonNull String authority, @NonNull File file) < final PathStrategy strategy = getPathStrategy(context, authority); return strategy.getUriForFile(file); >/** * Return a content URI for a given <@link File>. Specific temporary * permissions for the content URI can be set with * <@link Context#grantUriPermission(String, Uri, int)>, or added * to an <@link Intent>by calling <@link Intent#setData(Uri) setData()>and then * <@link Intent#setFlags(int) setFlags()>; in both cases, the applicable flags are * <@link Intent#FLAG_GRANT_READ_URI_PERMISSION>and * <@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION>. A FileProvider can only return a * content <@link Uri>for file paths defined in their
* meta-data element. See the Class Overview for more information. * * @param context A <@link Context>for the current component. * @param authority The authority of a <@link FileProvider>defined in a * <@code
> element in your app’s manifest. * @param file A <@link File>pointing to the filename for which you want a * content <@link Uri>. * @param displayName The filename to be displayed. This can be used if the original filename * is undesirable. * @return A content URI for the file. * @throws IllegalArgumentException When the given <@link File>is outside * the paths supported by the provider. */ @SuppressLint(«StreamFiles») @NonNull public static Uri getUriForFile(@NonNull Context context, @NonNull String authority, @NonNull File file, @NonNull String displayName) < Uri uri = getUriForFile(context, authority, file); return uri.buildUpon().appendQueryParameter(DISPLAYNAME_FIELD, displayName).build(); >/** * Use a content URI returned by * <@link #getUriForFile(Context, String, File) getUriForFile()>to get information about a file * managed by the FileProvider. * FileProvider reports the column names defined in <@link android.provider.OpenableColumns>: *
- *
- *
- *
* For more information, see * <@link ContentProvider#query(Uri, String[], String, String[], String) * ContentProvider.query()>. * * @param uri A content URI returned by <@link #getUriForFile>. * @param projection The list of columns to put into the <@link Cursor>. If null all columns are * included. * @param selection Selection criteria to apply. If null then all data that matches the content * URI is returned. * @param selectionArgs An array of <@link java.lang.String>, containing arguments to bind to * the selection parameter. The query method scans selection from left to * right and iterates through selectionArgs, replacing the current «?» character in * selection with the value at the current position in selectionArgs. The * values are bound to selection as <@link java.lang.String>values. * @param sortOrder A <@link java.lang.String>containing the column name(s) on which to sort * the resulting <@link Cursor>. * @return A <@link Cursor>containing the results of the query. * */ @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) < // ContentProvider has already checked granted permissions final File file = mStrategy.getFileForUri(uri); String displayName = uri.getQueryParameter(DISPLAYNAME_FIELD); if (projection == null) < projection = COLUMNS; >String[] cols = new String[projection.length]; Object[] values = new Object[projection.length]; int i = 0; for (String col : projection) < if (OpenableColumns.DISPLAY_NAME.equals(col)) < cols[i] = OpenableColumns.DISPLAY_NAME; values[i++] = (displayName == null) ? file.getName() : displayName; >else if (OpenableColumns.SIZE.equals(col)) < cols[i] = OpenableColumns.SIZE; values[i++] = file.length(); >> cols = copyOf(cols, i); values = copyOf(values, i); final MatrixCursor cursor = new MatrixCursor(cols, 1); cursor.addRow(values); return cursor; > /** * Returns the MIME type of a content URI returned by * <@link #getUriForFile(Context, String, File) getUriForFile()>. * * @param uri A content URI returned by * <@link #getUriForFile(Context, String, File) getUriForFile()>. * @return If the associated file has an extension, the MIME type associated with that * extension; otherwise application/octet-stream . */ @Override public String getType(@NonNull Uri uri) < // ContentProvider has already checked granted permissions final File file = mStrategy.getFileForUri(uri); final int lastDot = file.getName().lastIndexOf('.'); if (lastDot >= 0) < final String extension = file.getName().substring(lastDot + 1); final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); if (mime != null) < return mime; >> return «application/octet-stream»; > /** * By default, this method throws an <@link java.lang.UnsupportedOperationException>. You must * subclass FileProvider if you want to provide different functionality. */ @Override public Uri insert(@NonNull Uri uri, ContentValues values) < throw new UnsupportedOperationException("No external inserts"); >/** * By default, this method throws an <@link java.lang.UnsupportedOperationException>. You must * subclass FileProvider if you want to provide different functionality. */ @Override public int update(@NonNull Uri uri, ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) < throw new UnsupportedOperationException("No external updates"); >/** * Deletes the file associated with the specified content URI, as * returned by <@link #getUriForFile(Context, String, File) getUriForFile()>. Notice that this * method does not throw an <@link java.io.IOException>; you must check its return value. * * @param uri A content URI for a file, as returned by * <@link #getUriForFile(Context, String, File) getUriForFile()>. * @param selection Ignored. Set to <@code null>. * @param selectionArgs Ignored. Set to <@code null>. * @return 1 if the delete succeeds; otherwise, 0. */ @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) < // ContentProvider has already checked granted permissions final File file = mStrategy.getFileForUri(uri); return file.delete() ? 1 : 0; >/** * By default, FileProvider automatically returns the * <@link ParcelFileDescriptor>for a file associated with a content:// * <@link Uri>. To get the <@link ParcelFileDescriptor>, call * <@link android.content.ContentResolver#openFileDescriptor(Uri, String) * ContentResolver.openFileDescriptor>. * * To override this method, you must provide your own subclass of FileProvider. * * @param uri A content URI associated with a file, as returned by * <@link #getUriForFile(Context, String, File) getUriForFile()>. * @param mode Access mode for the file. May be «r» for read-only access, «rw» for read and * write access, or «rwt» for read and write access that truncates any existing file. * @return A new <@link ParcelFileDescriptor>with which you can access the file. */ @SuppressLint(«UnknownNullness») // b/171012356 @Override public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException < // ContentProvider has already checked granted permissions final File file = mStrategy.getFileForUri(uri); final int fileMode = modeToMode(mode); return ParcelFileDescriptor.open(file, fileMode); >/** * Return <@link PathStrategy>for given authority, either by parsing or * returning from cache. */ private static PathStrategy getPathStrategy(Context context, String authority) < PathStrategy strat; synchronized (sCache) < strat = sCache.get(authority); if (strat == null) < try < strat = parsePathStrategy(context, authority); >catch (IOException e) < throw new IllegalArgumentException( "Failed to parse " + META_DATA_FILE_PROVIDER_PATHS + " meta-data", e); >catch (XmlPullParserException e) < throw new IllegalArgumentException( "Failed to parse " + META_DATA_FILE_PROVIDER_PATHS + " meta-data", e); >sCache.put(authority, strat); > > return strat; > /** * Parse and return <@link PathStrategy>for given authority as defined in * <@link #META_DATA_FILE_PROVIDER_PATHS><@code >. * * @see #getPathStrategy(Context, String) */ private static PathStrategy parsePathStrategy(Context context, String authority) throws IOException, XmlPullParserException < final SimplePathStrategy strat = new SimplePathStrategy(authority); final ProviderInfo info = context.getPackageManager() .resolveContentProvider(authority, PackageManager.GET_META_DATA); if (info == null) < throw new IllegalArgumentException( "Couldn't find meta-data for provider with authority " + authority); >final XmlResourceParser in = info.loadXmlMetaData( context.getPackageManager(), META_DATA_FILE_PROVIDER_PATHS); if (in == null) < throw new IllegalArgumentException( "Missing " + META_DATA_FILE_PROVIDER_PATHS + " meta-data"); >int type; while ((type = in.next()) != END_DOCUMENT) < if (type == START_TAG) < final String tag = in.getName(); final String name = in.getAttributeValue(null, ATTR_NAME); String path = in.getAttributeValue(null, ATTR_PATH); File target = null; if (TAG_ROOT_PATH.equals(tag)) < target = DEVICE_ROOT; >else if (TAG_FILES_PATH.equals(tag)) < target = context.getFilesDir(); >else if (TAG_CACHE_PATH.equals(tag)) < target = context.getCacheDir(); >else if (TAG_EXTERNAL.equals(tag)) < target = Environment.getExternalStorageDirectory(); >else if (TAG_EXTERNAL_FILES.equals(tag)) < File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null); if (externalFilesDirs.length >0) < target = externalFilesDirs[0]; >> else if (TAG_EXTERNAL_CACHE.equals(tag)) < File[] externalCacheDirs = ContextCompat.getExternalCacheDirs(context); if (externalCacheDirs.length >0) < target = externalCacheDirs[0]; >> else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && TAG_EXTERNAL_MEDIA.equals(tag)) < File[] externalMediaDirs = context.getExternalMediaDirs(); if (externalMediaDirs.length >0) < target = externalMediaDirs[0]; >> if (target != null) < strat.addRoot(name, buildPath(target, path)); >> > return strat; > /** * Strategy for mapping between <@link File>and <@link Uri>. *
* Strategies must be symmetric so that mapping a <@link File>to a * <@link Uri>and then back to a <@link File>points at the original * target. *
* Strategies must remain consistent across app launches, and not rely on * dynamic state. This ensures that any generated <@link Uri>can still be * resolved if your process is killed and later restarted. * * @see SimplePathStrategy */ interface PathStrategy < /** * Return a <@link Uri>that represents the given <@link File>. */ Uri getUriForFile(File file); /** * Return a <@link File>that represents the given <@link Uri>. */ File getFileForUri(Uri uri); > /** * Strategy that provides access to files living under a narrow allowed list * of filesystem roots. It will throw <@link SecurityException>if callers try * accessing files outside the configured roots. *
Источник