diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 070bdcd27..f0ed84683 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -186,20 +186,20 @@
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:taskAffinity=""
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ android:theme="@android:style/Theme.Translucent.NoTitleBar" />
content:// {@link Uri} for a file
- * instead of a file:/// {@link Uri}.
- *
- * A content URI allows you to grant read and write access using - * temporary access permissions. When you create an {@link Intent} containing - * a content URI, in order to send the content URI - * to a client app, you can also call {@link Intent#setFlags(int) Intent.setFlags()} to add - * permissions. These permissions are available to the client app for as long as the stack for - * a receiving {@link android.app.Activity} is active. For an {@link Intent} going to a - * {@link android.app.Service}, the permissions are available as long as the - * {@link android.app.Service} is running. - *
- * In comparison, to control access to a file:/// {@link 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: - *
- *
- * 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
- * <provider>
- * 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:
- *
- * <manifest> - * ... - * <application> - * ... - * <provider - * android:name="android.support.v4.content.FileProvider" - * android:authorities="com.mydomain.fileprovider" - * android:exported="false" - * android:grantUriPermissions="true"> - * ... - * </provider> - * ... - * </application> - * </manifest>- *
- * 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 <provider> element.
- *
<paths> 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.
- * - * <paths xmlns:android="http://schemas.android.com/apk/res/android"> - * <files-path name="my_images" path="images/"/> - * ... - * </paths> - *- *
- * The <paths> element must contain one or more of the following child elements:
- *
- * <files-path name="name" path="path" /> - *- *
files/ subdirectory of your app's internal storage
- * area. This subdirectory is the same as the value returned by {@link Context#getFilesDir()
- * Context.getFilesDir()}.
- * - * <cache-path name="name" path="path" /> - *- *
- * <external-path name="name" path="path" /> - *- *
- * <external-files-path name="name" path="path" /> - *- *
- * <external-cache-path name="name" path="path" /> - *- *
- * These child elements all use the same attributes: - *
- *name="name"
- * path attribute.
- * path="path"
- * 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 <paths> for each directory that contains
- * files for which you want content URIs. For example, these XML elements specify two directories:
- *
- * <paths xmlns:android="http://schemas.android.com/apk/res/android"> - * <files-path name="my_images" path="images/"/> - * <files-path name="my_docs" path="docs/"/> - * </paths> - *- *
- * Put the <paths> 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
- * <meta-data> element
- * as a child of the <provider> element that defines the FileProvider. Set the
- * <meta-data> 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:
- *
- * <provider - * android:name="android.support.v4.content.FileProvider" - * android:authorities="com.mydomain.fileprovider" - * android:exported="false" - * android:grantUriPermissions="true"> - * <meta-data - * android:name="android.support.FILE_PROVIDER_PATHS" - * android:resource="@xml/file_paths" /> - * </provider> - *- *
- * 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:
- *
- * File imagePath = new File(Context.getFilesDir(), "images"); - * File newFile = new File(imagePath, "default_image.jpg"); - * Uri contentUri = getUriForFile(getContext(), "com.mydomain.fileprovider", newFile); - *- * 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.
- * 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.
- * - * 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. - *
- *- * 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()}. - *
- *- * 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 = { - MediaStore.MediaColumns.DISPLAY_NAME, - MediaStore.MediaColumns.SIZE, - MediaStore.MediaColumns.DATA - }; - - private static final String - META_DATA_FILE_PROVIDER_PATHS = "com.hippo.content.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 ATTR_NAME = "name"; - private static final String ATTR_PATH = "path"; - - private static final File DEVICE_ROOT = new File("/"); - - // @GuardedBy("sCache") - private static HashMapcontent {@link Uri} for file paths defined in their <paths>
- * 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 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(Context context, String authority, File file) {
- final PathStrategy strategy = getPathStrategy(context, authority);
- return strategy.getUriForFile(file);
- }
-
- /**
- * 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 application/octet-stream.
- */
- @Override
- public String getType(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(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(Uri uri, ContentValues values, String selection, 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(Uri uri, String selection, 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. - */ - @Override - public ParcelFileDescriptor openFile(Uri uri, 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); - } - - /** - * 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 whitelist of - * filesystem roots. It will throw {@link SecurityException} if callers try - * accessing files outside the configured roots. - *
- * For example, if configured with
- * {@code addRoot("myfiles", context.getFilesDir())}, then
- * {@code context.getFileStreamPath("foo.txt")} would map to
- * {@code content://myauthority/myfiles/foo.txt}.
- */
- static class SimplePathStrategy implements PathStrategy {
- private final String mAuthority;
- private final HashMap