Merge "Expose external app files/cache dir from FileProvider."
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 6117cba..35314ae 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -17,21 +17,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.support.tests">
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
<application>
<uses-library android:name="android.test.runner" />
- <provider
- android:name="android.support.v4.content.FileProvider"
- android:authorities="moocow"
- android:grantUriPermissions="true">
- <meta-data
- android:name="android.support.FILE_PROVIDER_PATHS"
- android:resource="@xml/paths" />
- </provider>
-
<activity android:name="android.support.tests.GrantActivity" android:label="_GrantActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/v4/java/android/support/v4/content/FileProvider.java b/v4/java/android/support/v4/content/FileProvider.java
index 9d6d803..9e82d63 100644
--- a/v4/java/android/support/v4/content/FileProvider.java
+++ b/v4/java/android/support/v4/content/FileProvider.java
@@ -133,15 +133,6 @@
* Represents files in the <code>files/</code> subdirectory of your app's internal storage
* area. This subdirectory is the same as the value returned by {@link Context#getFilesDir()
* Context.getFilesDir()}.
- * <dt>
- * <pre class="prettyprint">
- *<external-path name="<i>name</i>" path="<i>path</i>" />
- *</pre>
- * </dt>
- * <dd>
- * Represents files in the root of your app's external storage area. The path
- * {@link Context#getExternalFilesDir(String) Context.getExternalFilesDir()} returns the
- * <code>files/</code> subdirectory of this this root.
* </dd>
* <dt>
* <pre>
@@ -153,6 +144,36 @@
* of this subdirectory is the same as the value returned by {@link Context#getCacheDir()
* getCacheDir()}.
* </dd>
+ * <dt>
+ * <pre class="prettyprint">
+ *<external-path name="<i>name</i>" path="<i>path</i>" />
+ *</pre>
+ * </dt>
+ * <dd>
+ * 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()}.
+ * </dd>
+ * <dt>
+ * <pre class="prettyprint">
+ *<external-files-path name="<i>name</i>" path="<i>path</i>" />
+ *</pre>
+ * </dt>
+ * <dd>
+ * 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)}.
+ * </dd>
+ * <dt>
+ * <pre class="prettyprint">
+ *<external-cache-path name="<i>name</i>" path="<i>path</i>" />
+ *</pre>
+ * </dt>
+ * <dd>
+ * 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()}.
+ * </dd>
* </dl>
* <p>
* These child elements all use the same attributes:
@@ -310,6 +331,8 @@
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";
@@ -574,17 +597,27 @@
File target = null;
if (TAG_ROOT_PATH.equals(tag)) {
- target = buildPath(DEVICE_ROOT, path);
+ target = DEVICE_ROOT;
} else if (TAG_FILES_PATH.equals(tag)) {
- target = buildPath(context.getFilesDir(), path);
+ target = context.getFilesDir();
} else if (TAG_CACHE_PATH.equals(tag)) {
- target = buildPath(context.getCacheDir(), path);
+ target = context.getCacheDir();
} else if (TAG_EXTERNAL.equals(tag)) {
- target = buildPath(Environment.getExternalStorageDirectory(), path);
+ 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];
+ }
}
if (target != null) {
- strat.addRoot(name, target);
+ strat.addRoot(name, buildPath(target, path));
}
}
}
diff --git a/v4/tests/AndroidManifest.xml b/v4/tests/AndroidManifest.xml
index 556c885..466bfb8 100644
--- a/v4/tests/AndroidManifest.xml
+++ b/v4/tests/AndroidManifest.xml
@@ -20,10 +20,23 @@
<uses-sdk android:minSdkVersion="4" tools:overrideLibrary="android.support.test,
android.support.test.espresso, android.support.test.espresso.idling"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="android.support.v4.widget.test.TextViewTestActivity"/>
<activity android:name="android.support.v4.widget.TestActivity"/>
+
+ <provider
+ android:name="android.support.v4.content.FileProvider"
+ android:authorities="moocow"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/paths" />
+ </provider>
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/tests/java/android/support/v4/content/FileProviderTest.java b/v4/tests/java/android/support/v4/content/FileProviderTest.java
similarity index 86%
rename from tests/java/android/support/v4/content/FileProviderTest.java
rename to v4/tests/java/android/support/v4/content/FileProviderTest.java
index f8122fa..c446d85 100644
--- a/tests/java/android/support/v4/content/FileProviderTest.java
+++ b/v4/tests/java/android/support/v4/content/FileProviderTest.java
@@ -26,21 +26,19 @@
import android.support.v4.content.FileProvider.SimplePathStrategy;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.Suppress;
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Tests for {@link FileProvider}
*/
-@Suppress
public class FileProviderTest extends AndroidTestCase {
private static final String TEST_AUTHORITY = "moocow";
@@ -111,11 +109,12 @@
final SimplePathStrategy strat = new SimplePathStrategy("authority");
strat.addRoot("tag", mContext.getFilesDir());
- File file = buildPath(mContext.getFilesDir(), "file.test");
+ File expectedRoot = mContext.getFilesDir().getCanonicalFile();
+ File file = buildPath(expectedRoot, "file.test");
assertEquals(file.getPath(),
strat.getFileForUri(Uri.parse("content://authority/tag/file.test")).getPath());
- file = buildPath(mContext.getFilesDir(), "subdir", "file.test");
+ file = buildPath(expectedRoot, "subdir", "file.test");
assertEquals(file.getPath(), strat.getFileForUri(
Uri.parse("content://authority/tag/subdir/file.test")).getPath());
}
@@ -135,7 +134,8 @@
final SimplePathStrategy strat = new SimplePathStrategy("authority");
strat.addRoot("t/g", mContext.getFilesDir());
- File file = buildPath(mContext.getFilesDir(), "lol\"wat?foo&bar", "wat.txt");
+ File expectedRoot = mContext.getFilesDir().getCanonicalFile();
+ File file = buildPath(expectedRoot, "lol\"wat?foo&bar", "wat.txt");
final String expected = "content://authority/t%2Fg/lol%22wat%3Ffoo%26bar/wat.txt";
assertEquals(expected,
@@ -148,7 +148,8 @@
final SimplePathStrategy strat = new SimplePathStrategy("authority");
strat.addRoot("tag", mContext.getFilesDir());
- File file = buildPath(mContext.getFilesDir(), "file.txt");
+ File expectedRoot = mContext.getFilesDir().getCanonicalFile();
+ File file = buildPath(expectedRoot, "file.txt");
assertEquals(file.getPath(), strat.getFileForUri(
Uri.parse("content://authority/tag/file.txt?extra=foo")).getPath());
}
@@ -159,7 +160,8 @@
// When canonicalized, the path separators are trimmed
File inFile = new File(mContext.getFilesDir(), "//foo//bar//");
- File outFile = new File(mContext.getFilesDir(), "/foo/bar");
+ File expectedRoot = mContext.getFilesDir().getCanonicalFile();
+ File outFile = new File(expectedRoot, "/foo/bar");
final String expected = "content://authority/tag/foo/bar";
assertEquals(expected,
@@ -246,7 +248,7 @@
try {
out.write(TEST_DATA_ALT);
} finally {
- IoUtils.closeQuietly(out);
+ closeQuietly(out);
}
assertContentsEquals(TEST_DATA_ALT, uri);
@@ -266,7 +268,7 @@
try {
out.write(TEST_DATA_ALT);
} finally {
- IoUtils.closeQuietly(out);
+ closeQuietly(out);
}
assertContentsEquals(TEST_DATA_ALT, uri);
@@ -314,14 +316,24 @@
actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY,
buildPath(Environment.getExternalStorageDirectory(), "Android", "obb", "foobar"));
assertEquals("content://moocow/test_external/Android/obb/foobar", actual.toString());
+
+ File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(mContext, null);
+ actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY,
+ buildPath(externalFilesDirs[0], "foo", "bar"));
+ assertEquals("content://moocow/test_external_files/foo/bar", actual.toString());
+
+ File[] externalCacheDirs = ContextCompat.getExternalCacheDirs(mContext);
+ actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY,
+ buildPath(externalCacheDirs[0], "foo", "bar"));
+ assertEquals("content://moocow/test_external_cache/foo/bar", actual.toString());
}
private void assertContentsEquals(byte[] expected, Uri actual) throws Exception {
final InputStream in = mResolver.openInputStream(actual);
try {
- MoreAsserts.assertEquals(expected, Streams.readFully(in));
+ MoreAsserts.assertEquals(expected, readFully(in));
} finally {
- IoUtils.closeQuietly(in);
+ closeQuietly(in);
}
}
@@ -350,4 +362,21 @@
}
return cur;
}
+
+ private static void closeQuietly(Closeable c) {
+ try {
+ c.close();
+ } catch (IOException ignored) {
+ }
+ }
+
+ private static byte[] readFully(InputStream is) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buffer = new byte[4096];
+ int read;
+ while ((read = is.read(buffer)) != -1) {
+ out.write(buffer, 0, read);
+ }
+ return out.toByteArray();
+ }
}
diff --git a/tests/res/xml/paths.xml b/v4/tests/res/xml/paths.xml
similarity index 73%
rename from tests/res/xml/paths.xml
rename to v4/tests/res/xml/paths.xml
index baa2908..7f04099 100644
--- a/tests/res/xml/paths.xml
+++ b/v4/tests/res/xml/paths.xml
@@ -9,6 +9,10 @@
<files-path name="test_thumbs" path="thumbs/" />
<!-- /data/data/com.example/cache -->
<cache-path name="test_cache" />
- <!-- /storage/emulated/0/Android/com.example/files -->
+ <!-- /storage/emulated/0 -->
<external-path name="test_external" />
+ <!-- /storage/emulated/0/Android/com.example/files -->
+ <external-files-path name="test_external_files" />
+ <!-- /storage/emulated/0/Android/com.example/cache -->
+ <external-cache-path name="test_external_cache" />
</paths>