Per-app media directories on external storage.
This change defines per-app directories on external storage that will be scanned and included in MediaStore. This gives apps a way to write content to secondary shared storage in a way that can easily be surfaced to other apps. Bug: 14382377 Change-Id: I4cb367c870509e76f0c2c598f01e2f699780030a
This commit is contained in:
@ -6902,6 +6902,7 @@ package android.content {
|
||||
method public abstract java.io.File[] getExternalCacheDirs();
|
||||
method public abstract java.io.File getExternalFilesDir(java.lang.String);
|
||||
method public abstract java.io.File[] getExternalFilesDirs(java.lang.String);
|
||||
method public abstract java.io.File[] getExternalMediaDirs();
|
||||
method public abstract java.io.File getFileStreamPath(java.lang.String);
|
||||
method public abstract java.io.File getFilesDir();
|
||||
method public abstract android.os.Looper getMainLooper();
|
||||
@ -7070,6 +7071,7 @@ package android.content {
|
||||
method public java.io.File[] getExternalCacheDirs();
|
||||
method public java.io.File getExternalFilesDir(java.lang.String);
|
||||
method public java.io.File[] getExternalFilesDirs(java.lang.String);
|
||||
method public java.io.File[] getExternalMediaDirs();
|
||||
method public java.io.File getFileStreamPath(java.lang.String);
|
||||
method public java.io.File getFilesDir();
|
||||
method public android.os.Looper getMainLooper();
|
||||
@ -28323,6 +28325,7 @@ package android.test.mock {
|
||||
method public java.io.File[] getExternalCacheDirs();
|
||||
method public java.io.File getExternalFilesDir(java.lang.String);
|
||||
method public java.io.File[] getExternalFilesDirs(java.lang.String);
|
||||
method public java.io.File[] getExternalMediaDirs();
|
||||
method public java.io.File getFileStreamPath(java.lang.String);
|
||||
method public java.io.File getFilesDir();
|
||||
method public android.os.Looper getMainLooper();
|
||||
|
@ -249,6 +249,8 @@ class ContextImpl extends Context {
|
||||
private File[] mExternalFilesDirs;
|
||||
@GuardedBy("mSync")
|
||||
private File[] mExternalCacheDirs;
|
||||
@GuardedBy("mSync")
|
||||
private File[] mExternalMediaDirs;
|
||||
|
||||
private static final String[] EMPTY_FILE_LIST = {};
|
||||
|
||||
@ -1031,6 +1033,18 @@ class ContextImpl extends Context {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File[] getExternalMediaDirs() {
|
||||
synchronized (mSync) {
|
||||
if (mExternalMediaDirs == null) {
|
||||
mExternalMediaDirs = Environment.buildExternalStorageAppMediaDirs(getPackageName());
|
||||
}
|
||||
|
||||
// Create dirs if needed
|
||||
return ensureDirsExistOrFilter(mExternalMediaDirs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getFileStreamPath(String name) {
|
||||
return makeFilename(getFilesDir(), name);
|
||||
|
@ -40,6 +40,7 @@ import android.os.Looper;
|
||||
import android.os.StatFs;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.DisplayAdjustments;
|
||||
import android.view.Display;
|
||||
@ -928,6 +929,40 @@ public abstract class Context {
|
||||
*/
|
||||
public abstract File[] getExternalCacheDirs();
|
||||
|
||||
/**
|
||||
* Returns absolute paths to application-specific directories on all
|
||||
* external storage devices where the application can place media files.
|
||||
* These files are scanned and made available to other apps through
|
||||
* {@link MediaStore}.
|
||||
* <p>
|
||||
* This is like {@link #getExternalFilesDirs} in that these files will be
|
||||
* deleted when the application is uninstalled, however there are some
|
||||
* important differences:
|
||||
* <ul>
|
||||
* <li>External files are not always available: they will disappear if the
|
||||
* user mounts the external storage on a computer or removes it.
|
||||
* <li>There is no security enforced with these files.
|
||||
* </ul>
|
||||
* <p>
|
||||
* External storage devices returned here are considered a permanent part of
|
||||
* the device, including both emulated external storage and physical media
|
||||
* slots, such as SD cards in a battery compartment. The returned paths do
|
||||
* not include transient devices, such as USB flash drives.
|
||||
* <p>
|
||||
* An application may store data on any or all of the returned devices. For
|
||||
* example, an app may choose to store large files on the device with the
|
||||
* most available space, as measured by {@link StatFs}.
|
||||
* <p>
|
||||
* No permissions are required to read or write to the returned paths; they
|
||||
* are always accessible to the calling app. Write access outside of these
|
||||
* paths on secondary external storage devices is not available.
|
||||
* <p>
|
||||
* Returned paths may be {@code null} if a storage device is unavailable.
|
||||
*
|
||||
* @see Environment#getExternalStorageState(File)
|
||||
*/
|
||||
public abstract File[] getExternalMediaDirs();
|
||||
|
||||
/**
|
||||
* Returns an array of strings naming the private files associated with
|
||||
* this Context's application package.
|
||||
|
@ -236,6 +236,11 @@ public class ContextWrapper extends Context {
|
||||
return mBase.getExternalCacheDirs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File[] getExternalMediaDirs() {
|
||||
return mBase.getExternalMediaDirs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDir(String name, int mode) {
|
||||
return mBase.getDir(name, mode);
|
||||
|
@ -191,6 +191,10 @@ public class Environment {
|
||||
return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_MEDIA, packageName);
|
||||
}
|
||||
|
||||
public File[] buildExternalStorageAppMediaDirsForVold(String packageName) {
|
||||
return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_MEDIA, packageName);
|
||||
}
|
||||
|
||||
public File[] buildExternalStorageAppObbDirs(String packageName) {
|
||||
return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB, packageName);
|
||||
}
|
||||
|
@ -2372,6 +2372,18 @@ class MountService extends IMountService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
voldPath = maybeTranslatePathForVold(appPath,
|
||||
userEnv.buildExternalStorageAppMediaDirs(callingPkg),
|
||||
userEnv.buildExternalStorageAppMediaDirsForVold(callingPkg));
|
||||
if (voldPath != null) {
|
||||
try {
|
||||
mConnector.execute("volume", "mkdirs", voldPath);
|
||||
return 0;
|
||||
} catch (NativeDaemonConnectorException e) {
|
||||
return e.getCode();
|
||||
}
|
||||
}
|
||||
|
||||
throw new SecurityException("Invalid mkdirs path: " + appPath);
|
||||
}
|
||||
|
||||
|
@ -608,4 +608,9 @@ public class MockContext extends Context {
|
||||
public File[] getExternalCacheDirs() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File[] getExternalMediaDirs() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
@ -1466,4 +1466,10 @@ public final class BridgeContext extends Context {
|
||||
// pass
|
||||
return new File[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public File[] getExternalMediaDirs() {
|
||||
// pass
|
||||
return new File[0];
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user