Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cef52302 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "APIs for reviewing, listing volumes, hashes."

parents a2673444 b7634f49
Loading
Loading
Loading
Loading
+6 −1
Original line number Original line Diff line number Diff line
@@ -36900,6 +36900,7 @@ package android.provider {
  public final class MediaStore {
  public final class MediaStore {
    ctor public MediaStore();
    ctor public MediaStore();
    method public static java.util.Set<java.lang.String> getAllVolumeNames(android.content.Context);
    method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri);
    method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri);
    method public static android.net.Uri getMediaScannerUri();
    method public static android.net.Uri getMediaScannerUri();
    method public static android.net.Uri getMediaUri(android.content.Context, android.net.Uri);
    method public static android.net.Uri getMediaUri(android.content.Context, android.net.Uri);
@@ -36907,9 +36908,12 @@ package android.provider {
    method public static java.lang.String getVolumeName(android.net.Uri);
    method public static java.lang.String getVolumeName(android.net.Uri);
    field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
    field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
    field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
    field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
    field public static final java.lang.String ACTION_REVIEW = "android.provider.action.REVIEW";
    field public static final java.lang.String ACTION_REVIEW_SECURE = "android.provider.action.REVIEW_SECURE";
    field public static final java.lang.String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
    field public static final java.lang.String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
    field public static final java.lang.String AUTHORITY = "media";
    field public static final java.lang.String AUTHORITY = "media";
    field public static final android.net.Uri AUTHORITY_URI;
    field public static final android.net.Uri AUTHORITY_URI;
    field public static final java.lang.String EXTRA_BRIGHTNESS = "android.provider.extra.BRIGHTNESS";
    field public static final java.lang.String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
    field public static final java.lang.String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
    field public static final java.lang.String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
    field public static final java.lang.String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
    field public static final java.lang.String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen";
    field public static final java.lang.String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen";
@@ -37035,7 +37039,7 @@ package android.provider {
  public static final class MediaStore.Audio.Media implements android.provider.MediaStore.Audio.AudioColumns {
  public static final class MediaStore.Audio.Media implements android.provider.MediaStore.Audio.AudioColumns {
    ctor public MediaStore.Audio.Media();
    ctor public MediaStore.Audio.Media();
    method public static android.net.Uri getContentUri(java.lang.String);
    method public static android.net.Uri getContentUri(java.lang.String);
    method public static android.net.Uri getContentUriForPath(java.lang.String);
    method public static deprecated android.net.Uri getContentUriForPath(java.lang.String);
    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
    field public static final java.lang.String DEFAULT_SORT_ORDER = "title_key";
    field public static final java.lang.String DEFAULT_SORT_ORDER = "title_key";
    field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/audio";
    field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/audio";
@@ -37157,6 +37161,7 @@ package android.provider {
    field public static final java.lang.String DATE_ADDED = "date_added";
    field public static final java.lang.String DATE_ADDED = "date_added";
    field public static final java.lang.String DATE_MODIFIED = "date_modified";
    field public static final java.lang.String DATE_MODIFIED = "date_modified";
    field public static final java.lang.String DISPLAY_NAME = "_display_name";
    field public static final java.lang.String DISPLAY_NAME = "_display_name";
    field public static final java.lang.String HASH = "_hash";
    field public static final java.lang.String HEIGHT = "height";
    field public static final java.lang.String HEIGHT = "height";
    field public static final java.lang.String MIME_TYPE = "mime_type";
    field public static final java.lang.String MIME_TYPE = "mime_type";
    field public static final java.lang.String SIZE = "_size";
    field public static final java.lang.String SIZE = "_size";
+169 −65
Original line number Original line Diff line number Diff line
@@ -21,6 +21,8 @@ import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.UnsupportedAppUsage;
import android.annotation.UnsupportedAppUsage;
import android.app.Activity;
import android.app.AppGlobals;
import android.content.ClipData;
import android.content.ClipData;
import android.content.ContentProviderClient;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentResolver;
@@ -37,21 +39,27 @@ import android.graphics.Point;
import android.net.Uri;
import android.net.Uri;
import android.os.Bundle;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.CancellationSignal;
import android.os.Environment;
import android.os.OperationCanceledException;
import android.os.OperationCanceledException;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.service.media.CameraPrewarmService;
import android.service.media.CameraPrewarmService;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Log;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.List;
import java.util.Set;


/**
/**
 * The Media provider contains meta data for all available media on both internal
 * The Media provider contains meta data for all available media on both internal
@@ -65,7 +73,8 @@ public final class MediaStore {
    /** A content:// style uri to the authority for the media provider */
    /** A content:// style uri to the authority for the media provider */
    public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
    public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);


    private static final String CONTENT_AUTHORITY_SLASH = "content://" + AUTHORITY + "/";
    private static final String VOLUME_INTERNAL = "internal";
    private static final String VOLUME_EXTERNAL = "external";


    /**
    /**
     * The method name used by the media scanner and mtp to tell the media provider to
     * The method name used by the media scanner and mtp to tell the media provider to
@@ -266,7 +275,7 @@ public final class MediaStore {
     * any personal content like existing photos or videos on the device. The
     * any personal content like existing photos or videos on the device. The
     * applications should be careful not to share any photo or video with other
     * applications should be careful not to share any photo or video with other
     * applications or internet. The activity should use {@link
     * applications or internet. The activity should use {@link
     * android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} to display
     * Activity#setShowWhenLocked} to display
     * on top of the lock screen while secured. There is no activity stack when
     * on top of the lock screen while secured. There is no activity stack when
     * this flag is used, so launching more than one activity is strongly
     * this flag is used, so launching more than one activity is strongly
     * discouraged.
     * discouraged.
@@ -311,8 +320,8 @@ public final class MediaStore {
     * it when the device is secured (e.g. with a pin, password, pattern, or face unlock).
     * it when the device is secured (e.g. with a pin, password, pattern, or face unlock).
     * Applications responding to this intent must not expose any personal content like existing
     * Applications responding to this intent must not expose any personal content like existing
     * photos or videos on the device. The applications should be careful not to share any photo
     * photos or videos on the device. The applications should be careful not to share any photo
     * or video with other applications or internet. The activity should use {@link
     * or video with other applications or Internet. The activity should use {@link
     * android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} to display on top of the
     * Activity#setShowWhenLocked} to display on top of the
     * lock screen while secured. There is no activity stack when this flag is used, so
     * lock screen while secured. There is no activity stack when this flag is used, so
     * launching more than one activity is strongly discouraged.
     * launching more than one activity is strongly discouraged.
     * <p>
     * <p>
@@ -363,6 +372,55 @@ public final class MediaStore {
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
    public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";


    /**
     * Standard action that can be sent to review the given media file.
     * <p>
     * The launched application is expected to provide a large-scale view of the
     * given media file, while allowing the user to quickly access other
     * recently captured media files.
     * <p>
     * Input: {@link Intent#getData} is URI of the primary media item to
     * initially display.
     *
     * @see #ACTION_REVIEW_SECURE
     * @see #EXTRA_BRIGHTNESS
     */
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public final static String ACTION_REVIEW = "android.provider.action.REVIEW";

    /**
     * Standard action that can be sent to review the given media file when the
     * device is secured (e.g. with a pin, password, pattern, or face unlock).
     * The applications should be careful not to share any media with other
     * applications or Internet. The activity should use
     * {@link Activity#setShowWhenLocked} to display on top of the lock screen
     * while secured. There is no activity stack when this flag is used, so
     * launching more than one activity is strongly discouraged.
     * <p>
     * The launched application is expected to provide a large-scale view of the
     * given primary media file, while only allowing the user to quickly access
     * other media from an explicit secondary list.
     * <p>
     * Input: {@link Intent#getData} is URI of the primary media item to
     * initially display. {@link Intent#getClipData} is the limited list of
     * secondary media items that the user is allowed to review. If
     * {@link Intent#getClipData} is undefined, then no other media access
     * should be allowed.
     *
     * @see #EXTRA_BRIGHTNESS
     */
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public final static String ACTION_REVIEW_SECURE = "android.provider.action.REVIEW_SECURE";

    /**
     * When defined, the launched application is requested to set the given
     * brightness value via
     * {@link android.view.WindowManager.LayoutParams#screenBrightness} to help
     * ensure a smooth transition when launching {@Link #ACTION_REVIEW} or
     * {@link #ACTION_REVIEW_SECURE} intents.
     */
    public final static String EXTRA_BRIGHTNESS = "android.provider.extra.BRIGHTNESS";

    /**
    /**
     * The name of the Intent-extra used to control the quality of a recorded video. This is an
     * The name of the Intent-extra used to control the quality of a recorded video. This is an
     * integer property. Currently value 0 means low quality, suitable for MMS messages, and
     * integer property. Currently value 0 means low quality, suitable for MMS messages, and
@@ -419,6 +477,23 @@ public final class MediaStore {
        @Deprecated
        @Deprecated
        public static final String DATA = "_data";
        public static final String DATA = "_data";


        /**
         * Hash of the file on disk.
         * <p>
         * Contains a 20-byte binary blob which is the SHA-1 hash of the file as
         * persisted on disk. For performance reasons, the hash may not be
         * immediately available, in which case a {@code NULL} value will be
         * returned. If the underlying file is modified, this value will be
         * cleared and recalculated.
         * <p>
         * If you require the hash of a specific item, you can call
         * {@link ContentResolver#canonicalize(Uri)}, which will block until the
         * hash is calculated.
         * <p>
         * Type: BLOB
         */
        public static final String HASH = "_hash";

        /**
        /**
         * The size of the file in bytes
         * The size of the file in bytes
         * <P>Type: INTEGER (long)</P>
         * <P>Type: INTEGER (long)</P>
@@ -509,8 +584,7 @@ public final class MediaStore {
         * @return the URI to the files table on the given volume
         * @return the URI to the files table on the given volume
         */
         */
        public static Uri getContentUri(String volumeName) {
        public static Uri getContentUri(String volumeName) {
            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
            return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("file").build();
                    "/file");
        }
        }


        /**
        /**
@@ -523,8 +597,7 @@ public final class MediaStore {
         */
         */
        public static final Uri getContentUri(String volumeName,
        public static final Uri getContentUri(String volumeName,
                long rowId) {
                long rowId) {
            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
            return ContentUris.withAppendedId(getContentUri(volumeName), rowId);
                    + "/file/" + rowId);
        }
        }


        /**
        /**
@@ -533,8 +606,7 @@ public final class MediaStore {
         */
         */
        @UnsupportedAppUsage
        @UnsupportedAppUsage
        public static Uri getMtpObjectsUri(String volumeName) {
        public static Uri getMtpObjectsUri(String volumeName) {
            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
            return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("object").build();
                    "/object");
        }
        }


        /**
        /**
@@ -544,8 +616,7 @@ public final class MediaStore {
        @UnsupportedAppUsage
        @UnsupportedAppUsage
        public static final Uri getMtpObjectsUri(String volumeName,
        public static final Uri getMtpObjectsUri(String volumeName,
                long fileId) {
                long fileId) {
            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
            return ContentUris.withAppendedId(getMtpObjectsUri(volumeName), fileId);
                    + "/object/" + fileId);
        }
        }


        /**
        /**
@@ -555,8 +626,8 @@ public final class MediaStore {
        @UnsupportedAppUsage
        @UnsupportedAppUsage
        public static final Uri getMtpReferencesUri(String volumeName,
        public static final Uri getMtpReferencesUri(String volumeName,
                long fileId) {
                long fileId) {
            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
            return getMtpObjectsUri(volumeName, fileId).buildUpon().appendPath("references")
                    + "/object/" + fileId + "/references");
                    .build();
        }
        }


        /**
        /**
@@ -564,7 +635,7 @@ public final class MediaStore {
         * @hide
         * @hide
         */
         */
        public static final Uri getDirectoryUri(String volumeName) {
        public static final Uri getDirectoryUri(String volumeName) {
            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + "/dir");
            return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("dir").build();
        }
        }


        /**
        /**
@@ -777,7 +848,7 @@ public final class MediaStore {
             * <P>Type: INTEGER</P>
             * <P>Type: INTEGER</P>
             *
             *
             * @deprecated all thumbnails should be obtained via
             * @deprecated all thumbnails should be obtained via
             *             {@link Images.Thumbnails#getThumbnail}, as this
             *             {@link MediaStore.Images.Thumbnails#getThumbnail}, as this
             *             value is no longer supported.
             *             value is no longer supported.
             */
             */
            @Deprecated
            @Deprecated
@@ -921,8 +992,8 @@ public final class MediaStore {
             * @return the URI to the image media table on the given volume
             * @return the URI to the image media table on the given volume
             */
             */
            public static Uri getContentUri(String volumeName) {
            public static Uri getContentUri(String volumeName) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("images")
                        "/images/media");
                        .appendPath("media").build();
            }
            }


            /**
            /**
@@ -1063,8 +1134,8 @@ public final class MediaStore {
             * @return the URI to the image media table on the given volume
             * @return the URI to the image media table on the given volume
             */
             */
            public static Uri getContentUri(String volumeName) {
            public static Uri getContentUri(String volumeName) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("images")
                        "/images/thumbnails");
                        .appendPath("thumbnails").build();
            }
            }


            /**
            /**
@@ -1371,14 +1442,29 @@ public final class MediaStore {
             * @return the URI to the audio media table on the given volume
             * @return the URI to the audio media table on the given volume
             */
             */
            public static Uri getContentUri(String volumeName) {
            public static Uri getContentUri(String volumeName) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
                        "/audio/media");
                        .appendPath("media").build();
            }
            }


            public static Uri getContentUriForPath(String path) {
            /**
                return (path.startsWith(
             * Get the content:// style URI for the given audio media file.
                        Environment.getStorageDirectory().getAbsolutePath() + "/")
             *
                        ? EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI);
             * @deprecated Apps may not have filesystem permissions to directly
             *             access this path.
             */
            public static @Nullable Uri getContentUriForPath(@NonNull String path) {
                final StorageManager sm = AppGlobals.getInitialApplication()
                        .getSystemService(StorageManager.class);
                final StorageVolume sv = sm.getStorageVolume(new File(path));
                if (sv != null) {
                    if (sv.isPrimary()) {
                        return EXTERNAL_CONTENT_URI;
                    } else {
                        return getContentUri(sv.getUuid());
                    }
                } else {
                    return INTERNAL_CONTENT_URI;
                }
            }
            }


            /**
            /**
@@ -1454,8 +1540,8 @@ public final class MediaStore {
             * @return the URI to the audio genres table on the given volume
             * @return the URI to the audio genres table on the given volume
             */
             */
            public static Uri getContentUri(String volumeName) {
            public static Uri getContentUri(String volumeName) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
                        "/audio/genres");
                        .appendPath("genres").build();
            }
            }


            /**
            /**
@@ -1467,8 +1553,8 @@ public final class MediaStore {
             * with the given the volume and audioID
             * with the given the volume and audioID
             */
             */
            public static Uri getContentUriForAudioId(String volumeName, int audioId) {
            public static Uri getContentUriForAudioId(String volumeName, int audioId) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                return ContentUris.withAppendedId(Audio.Media.getContentUri(volumeName), audioId)
                        "/audio/media/" + audioId + "/genres");
                        .buildUpon().appendPath("genres").build();
            }
            }


            /**
            /**
@@ -1504,10 +1590,10 @@ public final class MediaStore {
             */
             */
            public static final class Members implements AudioColumns {
            public static final class Members implements AudioColumns {


                public static final Uri getContentUri(String volumeName,
                public static final Uri getContentUri(String volumeName, long genreId) {
                        long genreId) {
                    return ContentUris
                    return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
                            .withAppendedId(Audio.Genres.getContentUri(volumeName), genreId)
                            + "/audio/genres/" + genreId + "/members");
                            .buildUpon().appendPath("members").build();
                }
                }


                /**
                /**
@@ -1595,8 +1681,8 @@ public final class MediaStore {
             * @return the URI to the audio playlists table on the given volume
             * @return the URI to the audio playlists table on the given volume
             */
             */
            public static Uri getContentUri(String volumeName) {
            public static Uri getContentUri(String volumeName) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
                        "/audio/playlists");
                        .appendPath("playlists").build();
            }
            }


            /**
            /**
@@ -1631,10 +1717,10 @@ public final class MediaStore {
             * Sub-directory of each playlist containing all members.
             * Sub-directory of each playlist containing all members.
             */
             */
            public static final class Members implements AudioColumns {
            public static final class Members implements AudioColumns {
                public static final Uri getContentUri(String volumeName,
                public static final Uri getContentUri(String volumeName, long playlistId) {
                        long playlistId) {
                    return ContentUris
                    return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
                            .withAppendedId(Audio.Playlists.getContentUri(volumeName), playlistId)
                            + "/audio/playlists/" + playlistId + "/members");
                            .buildUpon().appendPath("members").build();
                }
                }


                /**
                /**
@@ -1734,8 +1820,8 @@ public final class MediaStore {
             * @return the URI to the audio artists table on the given volume
             * @return the URI to the audio artists table on the given volume
             */
             */
            public static Uri getContentUri(String volumeName) {
            public static Uri getContentUri(String volumeName) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
                        "/audio/artists");
                        .appendPath("artists").build();
            }
            }


            /**
            /**
@@ -1771,10 +1857,10 @@ public final class MediaStore {
             * a song by the artist appears.
             * a song by the artist appears.
             */
             */
            public static final class Albums implements AlbumColumns {
            public static final class Albums implements AlbumColumns {
                public static final Uri getContentUri(String volumeName,
                public static final Uri getContentUri(String volumeName,long artistId) {
                        long artistId) {
                    return ContentUris
                    return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
                            .withAppendedId(Audio.Artists.getContentUri(volumeName), artistId)
                            + "/audio/artists/" + artistId + "/albums");
                            .buildUpon().appendPath("albums").build();
                }
                }
            }
            }
        }
        }
@@ -1869,8 +1955,8 @@ public final class MediaStore {
             * @return the URI to the audio albums table on the given volume
             * @return the URI to the audio albums table on the given volume
             */
             */
            public static Uri getContentUri(String volumeName) {
            public static Uri getContentUri(String volumeName) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
                        "/audio/albums");
                        .appendPath("albums").build();
            }
            }


            /**
            /**
@@ -2004,7 +2090,7 @@ public final class MediaStore {
             * <P>Type: INTEGER</P>
             * <P>Type: INTEGER</P>
             *
             *
             * @deprecated all thumbnails should be obtained via
             * @deprecated all thumbnails should be obtained via
             *             {@link Images.Thumbnails#getThumbnail}, as this
             *             {@link MediaStore.Images.Thumbnails#getThumbnail}, as this
             *             value is no longer supported.
             *             value is no longer supported.
             */
             */
            @Deprecated
            @Deprecated
@@ -2064,8 +2150,8 @@ public final class MediaStore {
             * @return the URI to the video media table on the given volume
             * @return the URI to the video media table on the given volume
             */
             */
            public static Uri getContentUri(String volumeName) {
            public static Uri getContentUri(String volumeName) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("video")
                        "/video/media");
                        .appendPath("media").build();
            }
            }


            /**
            /**
@@ -2188,8 +2274,8 @@ public final class MediaStore {
             * @return the URI to the image media table on the given volume
             * @return the URI to the image media table on the given volume
             */
             */
            public static Uri getContentUri(String volumeName) {
            public static Uri getContentUri(String volumeName) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("video")
                        "/video/thumbnails");
                        .appendPath("thumbnails").build();
            }
            }


            /**
            /**
@@ -2256,6 +2342,30 @@ public final class MediaStore {
        }
        }
    }
    }


    /**
     * Return list of all volume names currently available. This includes a
     * unique name for each shared storage device that is currently mounted.
     * <p>
     * Each name can be passed to APIs like
     * {@link MediaStore.Images.Media#getContentUri(String)} to query media at
     * that location.
     */
    public static @NonNull Set<String> getAllVolumeNames(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.isMountedReadable()) {
                if (vi.isPrimary()) {
                    volumeNames.add(VOLUME_EXTERNAL);
                } else {
                    volumeNames.add(vi.getFsUuid());
                }
            }
        }
        return volumeNames;
    }

    /**
    /**
     * Return the volume name that the given {@link Uri} references.
     * Return the volume name that the given {@link Uri} references.
     */
     */
@@ -2272,7 +2382,7 @@ public final class MediaStore {
     * Uri for querying the state of the media scanner.
     * Uri for querying the state of the media scanner.
     */
     */
    public static Uri getMediaScannerUri() {
    public static Uri getMediaScannerUri() {
        return Uri.parse(CONTENT_AUTHORITY_SLASH + "none/media_scanner");
        return AUTHORITY_URI.buildUpon().appendPath("none").appendPath("media_scanner").build();
    }
    }


    /**
    /**
@@ -2297,17 +2407,11 @@ public final class MediaStore {
     * @return A version string, or null if the version could not be determined.
     * @return A version string, or null if the version could not be determined.
     */
     */
    public static String getVersion(Context context) {
    public static String getVersion(Context context) {
        Cursor c = context.getContentResolver().query(
        final Uri uri = AUTHORITY_URI.buildUpon().appendPath("none").appendPath("version").build();
                Uri.parse(CONTENT_AUTHORITY_SLASH + "none/version"),
        try (Cursor c = context.getContentResolver().query(uri, null, null, null, null)) {
                null, null, null, null);
        if (c != null) {
            try {
            if (c.moveToFirst()) {
            if (c.moveToFirst()) {
                return c.getString(0);
                return c.getString(0);
            }
            }
            } finally {
                c.close();
            }
        }
        }
        return null;
        return null;
    }
    }