summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Android Build Merger (Role) <noreply-android-build-merger@google.com> 2019-04-10 19:27:46 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-04-10 19:27:46 +0000
commitf83e9ddb632a1e4df90b4d0af32c9424b204285c (patch)
treece54e0b54165106f110949b73467c755f31193f4
parent162620a17fa90e7f2e339e661e73e824786c8744 (diff)
parent0614c4414fd4bd06711eb05cb962fb4f29f8c855 (diff)
Merge "Merge "Split VOLUME_EXTERNAL and VOLUME_PRIMARY." into qt-dev am: 457296a084 am: 9949446935"
-rw-r--r--api/current.txt4
-rw-r--r--api/removed.txt1
-rw-r--r--core/java/android/os/storage/StorageManager.java2
-rw-r--r--core/java/android/os/storage/StorageVolume.java7
-rw-r--r--core/java/android/provider/MediaStore.java122
5 files changed, 98 insertions, 38 deletions
diff --git a/api/current.txt b/api/current.txt
index 62715ce60ec4..a6919bb5e0b5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38478,8 +38478,8 @@ package android.provider {
public final class MediaStore {
ctor public MediaStore();
- method @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
method @Nullable public static android.net.Uri getDocumentUri(@NonNull android.content.Context, @NonNull android.net.Uri);
+ method @NonNull public static java.util.Set<java.lang.String> getExternalVolumeNames(@NonNull android.content.Context);
method public static android.net.Uri getMediaScannerUri();
method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri);
method @NonNull public static String getVersion(@NonNull android.content.Context);
@@ -38523,6 +38523,7 @@ package android.provider {
field public static final String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE = "android.media.still_image_camera_preview_service";
field public static final String UNKNOWN_STRING = "<unknown>";
field public static final String VOLUME_EXTERNAL = "external";
+ field public static final String VOLUME_EXTERNAL_PRIMARY = "external_primary";
field public static final String VOLUME_INTERNAL = "internal";
}
@@ -38771,6 +38772,7 @@ package android.provider {
field public static final String RELATIVE_PATH = "relative_path";
field public static final String SIZE = "_size";
field public static final String TITLE = "title";
+ field public static final String VOLUME_NAME = "volume_name";
field public static final String WIDTH = "width";
}
diff --git a/api/removed.txt b/api/removed.txt
index fe3e866de682..70ff50ed40a6 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -514,6 +514,7 @@ package android.provider {
public final class MediaStore {
method @Deprecated @NonNull public static android.net.Uri createPending(@NonNull android.content.Context, @NonNull android.provider.MediaStore.PendingParams);
+ method @Deprecated @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
method @Deprecated @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri);
method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 075b650ed8f4..080ff7301ed2 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1130,7 +1130,7 @@ public class StorageManager {
public @NonNull StorageVolume getStorageVolume(@NonNull Uri uri) {
final String volumeName = MediaStore.getVolumeName(uri);
switch (volumeName) {
- case MediaStore.VOLUME_EXTERNAL:
+ case MediaStore.VOLUME_EXTERNAL_PRIMARY:
return getPrimaryStorageVolume();
default:
for (StorageVolume vol : getStorageVolumes()) {
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 225ecfa315aa..6280600823d7 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -265,8 +265,13 @@ public final class StorageVolume implements Parcelable {
}
/** {@hide} */
+ public static @Nullable String normalizeUuid(@Nullable String fsUuid) {
+ return fsUuid != null ? fsUuid.toLowerCase(Locale.US) : null;
+ }
+
+ /** {@hide} */
public @Nullable String getNormalizedUuid() {
- return mFsUuid != null ? mFsUuid.toLowerCase(Locale.US) : null;
+ return normalizeUuid(mFsUuid);
}
/**
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 0b1647d05ef4..da19d59367a0 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -102,20 +102,40 @@ public final class MediaStore {
public static final @NonNull Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
/**
- * Volume name used for content on "internal" storage of device. This
- * volume contains media distributed with the device, such as built-in
- * ringtones and wallpapers.
+ * Synthetic volume name that provides a view of all content across the
+ * "internal" storage of the device.
+ * <p>
+ * This synthetic volume provides a merged view of all media distributed
+ * with the device, such as built-in ringtones and wallpapers.
+ * <p>
+ * Because this is a synthetic volume, you can't insert new content into
+ * this volume.
*/
public static final String VOLUME_INTERNAL = "internal";
/**
- * Volume name used for content on "external" storage of device. This only
- * includes media on the primary shared storage device; the contents of any
- * secondary storage devices can be obtained using
- * {@link #getAllVolumeNames(Context)}.
+ * Synthetic volume name that provides a view of all content across the
+ * "external" storage of the device.
+ * <p>
+ * This synthetic volume provides a merged view of all media across all
+ * currently attached external storage devices.
+ * <p>
+ * Because this is a synthetic volume, you can't insert new content into
+ * this volume. Instead, you can insert content into a specific storage
+ * volume obtained from {@link #getExternalVolumeNames(Context)}.
*/
public static final String VOLUME_EXTERNAL = "external";
+ /**
+ * Specific volume name that represents the primary external storage device
+ * at {@link Environment#getExternalStorageDirectory()}.
+ * <p>
+ * This volume may not always be available, such as when the user has
+ * ejected the device. You can find a list of all specific volume names
+ * using {@link #getExternalVolumeNames(Context)}.
+ */
+ public static final String VOLUME_EXTERNAL_PRIMARY = "external_primary";
+
/** {@hide} */
public static final String SCAN_FILE_CALL = "scan_file";
/** {@hide} */
@@ -1037,6 +1057,16 @@ public final class MediaStore {
public static final String OWNER_PACKAGE_NAME = "owner_package_name";
/**
+ * Volume name of the specific storage device where this media item is
+ * persisted. The value is typically one of the volume names returned
+ * from {@link MediaStore#getExternalVolumeNames(Context)}.
+ * <p>
+ * This is a read-only column that is automatically computed.
+ */
+ @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+ public static final String VOLUME_NAME = "volume_name";
+
+ /**
* Relative path of this media item within the storage device where it
* is persisted. For example, an item stored at
* {@code /storage/0000-0000/DCIM/Vacation/IMG1024.JPG} would have a
@@ -1408,7 +1438,7 @@ public final class MediaStore {
final StorageVolume sv = sm.getStorageVolume(path);
if (sv != null) {
if (sv.isPrimary()) {
- return VOLUME_EXTERNAL;
+ return VOLUME_EXTERNAL_PRIMARY;
} else {
return checkArgumentVolumeName(sv.getNormalizedUuid());
}
@@ -1710,7 +1740,7 @@ public final class MediaStore {
String stringUrl = null; /* value to be returned */
try {
- url = cr.insert(EXTERNAL_CONTENT_URI, values);
+ url = cr.insert(getContentUri(VOLUME_EXTERNAL_PRIMARY), values);
if (source != null) {
try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(
@@ -3224,22 +3254,29 @@ public final class MediaStore {
}
}
+ /** @removed */
+ @Deprecated
+ public static @NonNull Set<String> getAllVolumeNames(@NonNull Context context) {
+ return getExternalVolumeNames(context);
+ }
+
/**
- * Return list of all volume names currently available. This includes a
- * unique name for each shared storage device that is currently mounted.
+ * Return list of all specific volume names that make up
+ * {@link #VOLUME_EXTERNAL}. This includes a unique volume name for each
+ * shared storage device that is currently attached, which typically
+ * includes {@link MediaStore#VOLUME_EXTERNAL_PRIMARY}.
* <p>
- * Each name can be passed to APIs like
- * {@link MediaStore.Images.Media#getContentUri(String)} to query media at
- * that location.
+ * Each specific volume name can be passed to APIs like
+ * {@link MediaStore.Images.Media#getContentUri(String)} to interact with
+ * media on that storage device.
*/
- public static @NonNull Set<String> getAllVolumeNames(@NonNull Context context) {
+ public static @NonNull Set<String> getExternalVolumeNames(@NonNull Context context) {
final StorageManager sm = context.getSystemService(StorageManager.class);
final Set<String> volumeNames = new ArraySet<>();
- volumeNames.add(VOLUME_INTERNAL);
for (VolumeInfo vi : sm.getVolumes()) {
if (vi.isVisibleForUser(UserHandle.myUserId()) && vi.isMountedReadable()) {
if (vi.isPrimary()) {
- volumeNames.add(VOLUME_EXTERNAL);
+ volumeNames.add(VOLUME_EXTERNAL_PRIMARY);
} else {
volumeNames.add(vi.getNormalizedFsUuid());
}
@@ -3270,6 +3307,8 @@ public final class MediaStore {
return volumeName;
} else if (VOLUME_EXTERNAL.equals(volumeName)) {
return volumeName;
+ } else if (VOLUME_EXTERNAL_PRIMARY.equals(volumeName)) {
+ return volumeName;
}
// When not one of the well-known values above, it must be a hex UUID
@@ -3285,8 +3324,9 @@ public final class MediaStore {
}
/**
- * Return path where the given volume is mounted. Not valid for
- * {@link #VOLUME_INTERNAL}.
+ * Return path where the given specific volume is mounted. Not valid for
+ * {@link #VOLUME_INTERNAL} or {@link #VOLUME_EXTERNAL}, since those are
+ * broad collections that cover many paths.
*
* @hide
*/
@@ -3297,8 +3337,12 @@ public final class MediaStore {
throw new IllegalArgumentException();
}
- if (VOLUME_EXTERNAL.equals(volumeName)) {
- return Environment.getExternalStorageDirectory();
+ switch (volumeName) {
+ case VOLUME_INTERNAL:
+ case VOLUME_EXTERNAL:
+ throw new FileNotFoundException(volumeName + " has no associated path");
+ case VOLUME_EXTERNAL_PRIMARY:
+ return Environment.getExternalStorageDirectory();
}
final StorageManager sm = AppGlobals.getInitialApplication()
@@ -3328,23 +3372,31 @@ public final class MediaStore {
throw new IllegalArgumentException();
}
+ final Context context = AppGlobals.getInitialApplication();
+ final UserManager um = context.getSystemService(UserManager.class);
+
final ArrayList<File> res = new ArrayList<>();
if (VOLUME_INTERNAL.equals(volumeName)) {
- addCanoncialFile(res, new File(Environment.getRootDirectory(), "media"));
- addCanoncialFile(res, new File(Environment.getOemDirectory(), "media"));
- addCanoncialFile(res, new File(Environment.getProductDirectory(), "media"));
+ addCanonicalFile(res, new File(Environment.getRootDirectory(), "media"));
+ addCanonicalFile(res, new File(Environment.getOemDirectory(), "media"));
+ addCanonicalFile(res, new File(Environment.getProductDirectory(), "media"));
+ } else if (VOLUME_EXTERNAL.equals(volumeName)) {
+ for (String exactVolume : getExternalVolumeNames(context)) {
+ addCanonicalFile(res, getVolumePath(exactVolume));
+ }
+ if (um.isDemoUser()) {
+ addCanonicalFile(res, Environment.getDataPreloadsMediaDirectory());
+ }
} else {
- addCanoncialFile(res, getVolumePath(volumeName));
- final UserManager um = AppGlobals.getInitialApplication()
- .getSystemService(UserManager.class);
- if (VOLUME_EXTERNAL.equals(volumeName) && um.isDemoUser()) {
- addCanoncialFile(res, Environment.getDataPreloadsMediaDirectory());
+ addCanonicalFile(res, getVolumePath(volumeName));
+ if (VOLUME_EXTERNAL_PRIMARY.equals(volumeName) && um.isDemoUser()) {
+ addCanonicalFile(res, Environment.getDataPreloadsMediaDirectory());
}
}
return res;
}
- private static void addCanoncialFile(List<File> list, File file) {
+ private static void addCanonicalFile(List<File> list, File file) {
try {
list.add(file.getCanonicalFile());
} catch (IOException e) {
@@ -3382,12 +3434,12 @@ public final class MediaStore {
* <p>
* No other assumptions should be made about the meaning of the version.
* <p>
- * This method returns the version for {@link MediaStore#VOLUME_EXTERNAL};
- * to obtain a version for a different volume, use
- * {@link #getVersion(Context, String)}.
+ * This method returns the version for
+ * {@link MediaStore#VOLUME_EXTERNAL_PRIMARY}; to obtain a version for a
+ * different volume, use {@link #getVersion(Context, String)}.
*/
public static @NonNull String getVersion(@NonNull Context context) {
- return getVersion(context, VOLUME_EXTERNAL);
+ return getVersion(context, VOLUME_EXTERNAL_PRIMARY);
}
/**
@@ -3401,7 +3453,7 @@ public final class MediaStore {
*
* @param volumeName specific volume to obtain an opaque version string for.
* Must be one of the values returned from
- * {@link #getAllVolumeNames(Context)}.
+ * {@link #getExternalVolumeNames(Context)}.
*/
public static @NonNull String getVersion(@NonNull Context context, @NonNull String volumeName) {
final ContentResolver resolver = context.getContentResolver();