Skip to content

MediaStore

Danger

The filesystem and mediastore modules are deprecated. You should use the new storage module which is relying on Okio Filesystem API.

On Android, every files on the shared storage (files visible when using a file manager) are indexed by MediaStore, to allow apps to query them by type, date, size, etc.

On API 29 (Android 10), Scoped Storage has been introduced, enabling a sandboxed view on the shared storage and the ability to add files without requesting permission. To read media files created by other apps, you need to request REQUEST_EXTERNAL_STORAGE and editing/deleting them require to ask user's consent.

modernstorage-mediastore is a library abstracting these MediaStore API interactions on API 21+ (Android Lollipop).

Add dependency to project

modernstorage-mediastore is available on mavenCentral().

// build.gradle
implementation("com.google.modernstorage:modernstorage-mediastore:1.0.0-alpha03")

API reference

modernstorage-mediastore API reference is available here.

Initialize repository

To interact with MediaStore, you need to initialize a MediaStoreRepository instance:

val mediaStore by lazy { MediaStoreRepository(context) }

Checking permissions

Before adding, editing or deleting files, you should check if you have the permissions to do so.

To avoid having a complex permission checking logic due to Scoped Storage changes, we have included helper methods in MediaStoreRepository:

/**
 * If you only need to read your own entries in MediaStore
 */
if(mediaStore.canReadOwnEntries()) {
    println("Read my image")
}

/**
 * If you only need to read and write your own entries in MediaStore
 */
if(mediaStore.canWriteOwnEntries()) {
    println("Edit my image")
}

/**
 * If you need to read your own entries as well as the ones created by other apps in MediaStore
 */
if(mediaStore.canReadSharedEntries()) {
    println("Read an image created by another app")
}

/**
 * If you need to read and write your own entries as well as the ones created by other apps in
 * MediaStore
 */
if(mediaStore.canWriteSharedEntries()) {
    println("Edit an image created by another app")
}

Create media URI

If you're using intents like ACTION_IMAGE_CAPTURE and want to personalize the MediaStore entry, use the createMediaUri method:

val photoUri = mediaStore.createMediaUri(
    filename = "new-image.jpg",
    type = FileType.IMAGE,
    location = SharedPrimary
).getOrElse { reason ->
    println("Creating Media URI failed: $reason")
}

Add media file

You can add a media file by using the method addMediaFromStream. It will create a MediaStore URI, save the inputStream content in it, and scans the file before returning its Uri:

/**
 * If you already have an InputStream
 */
val photoUri = mediaStore.addMediaFromStream(
   filename = "new-image.jpg",
   type = FileType.IMAGE,
   mimeType = "image/jpg",
   inputStream = sample,
   location = SharedPrimary
).getOrElse { reason ->
    println("Creating Media URI failed: $reason")
}

/**
 * Otherwise with a ByteArray
 */
val videoUri = mediaStore.addMediaFromStream(
   filename = "new-video.mp4",
   type = FileType.VIDEO,
   mimeType = "video/mp4",
   inputStream = ByteArrayInputStream(sampleByteArray),
   location = SharedPrimary
).getOrElse { reason ->
    println("Creating Media URI failed: $reason")
}

Scan media URI

Modifying a file requires to scan it to make MediaStore aware of the file changes (size, modification date, etc.). To request a scan for a media URI, use the scanUri method:

mediaStore.scanUri(updatedPhotoUri, "image/png").getOrElse { reason ->
    println("Scanning failed ($mediaUri): $reason")
}

Get media URI details

To get the details of a media URI (filename, size, file type, mime type), use the getResourceByUri method:

val mediaDetails = mediaStore.getResourceByUri(mediaUri).getOrElse { reason ->
    println("Fetching details failed ($mediaUri): $reason")
}