forked from bumptech/glide
-
Notifications
You must be signed in to change notification settings - Fork 6
/
MediaStoreDataSource.kt
131 lines (119 loc) · 4.24 KB
/
MediaStoreDataSource.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package com.bumptech.glide.samples.gallery
import android.content.Context
import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.os.Parcelable
import android.provider.MediaStore
import android.provider.MediaStore.Files.FileColumns
import android.provider.MediaStore.MediaColumns
import com.bumptech.glide.util.Preconditions
import com.bumptech.glide.util.Util
import java.util.ArrayList
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
/** Loads metadata from the media store for images and videos. */
class MediaStoreDataSource internal constructor(
private val context: Context,
) {
fun loadMediaStoreData(): Flow<List<MediaStoreData>> = callbackFlow {
val contentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange)
launch {
trySend(query())
}
}
}
context.contentResolver.registerContentObserver(
MEDIA_STORE_FILE_URI,
/* notifyForDescendants=*/ true,
contentObserver)
trySend(query())
awaitClose {
context.contentResolver.unregisterContentObserver(contentObserver)
}
}
private fun query(): MutableList<MediaStoreData> {
Preconditions.checkArgument(
Util.isOnBackgroundThread(), "Can only query from a background thread")
val data: MutableList<MediaStoreData> = ArrayList()
val cursor =
context
.contentResolver
.query(
MEDIA_STORE_FILE_URI,
PROJECTION,
FileColumns.MEDIA_TYPE + " = " + FileColumns.MEDIA_TYPE_IMAGE
+ " OR " + FileColumns.MEDIA_TYPE + " = " + FileColumns.MEDIA_TYPE_VIDEO,
/* selectionArgs= */ null,
"${MediaColumns.DATE_TAKEN} DESC"
) ?: return data
@Suppress("NAME_SHADOWING") // Might as well, it's the same object?
cursor.use { cursor ->
val idColNum = cursor.getColumnIndexOrThrow(MediaColumns._ID)
val dateTakenColNum = cursor.getColumnIndexOrThrow(MediaColumns.DATE_TAKEN)
val dateModifiedColNum = cursor.getColumnIndexOrThrow(MediaColumns.DATE_MODIFIED)
val mimeTypeColNum = cursor.getColumnIndexOrThrow(MediaColumns.MIME_TYPE)
val orientationColNum = cursor.getColumnIndexOrThrow(MediaColumns.ORIENTATION)
val mediaTypeColumnIndex = cursor.getColumnIndexOrThrow(FileColumns.MEDIA_TYPE)
val displayNameIndex = cursor.getColumnIndexOrThrow(FileColumns.DISPLAY_NAME)
while (cursor.moveToNext()) {
val id = cursor.getLong(idColNum)
val dateTaken = cursor.getLong(dateTakenColNum)
val mimeType = cursor.getString(mimeTypeColNum)
val dateModified = cursor.getLong(dateModifiedColNum)
val orientation = cursor.getInt(orientationColNum)
val displayName = cursor.getString(displayNameIndex)
val type =
if (cursor.getInt(mediaTypeColumnIndex) == FileColumns.MEDIA_TYPE_IMAGE)
Type.IMAGE
else
Type.VIDEO
data.add(
MediaStoreData(
type = type,
rowId = id,
uri = Uri.withAppendedPath(MEDIA_STORE_FILE_URI, id.toString()),
mimeType = mimeType,
dateModified = dateModified,
orientation = orientation,
dateTaken = dateTaken,
displayName = displayName,
))
}
}
return data
}
companion object {
private val MEDIA_STORE_FILE_URI = MediaStore.Files.getContentUri("external")
private val PROJECTION = arrayOf(
MediaColumns._ID,
MediaColumns.DATE_TAKEN,
MediaColumns.DATE_MODIFIED,
MediaColumns.MIME_TYPE,
MediaColumns.ORIENTATION,
MediaColumns.DISPLAY_NAME,
FileColumns.MEDIA_TYPE)
}
}
/** A data model containing data for a single media item. */
@Parcelize
data class MediaStoreData(
private val type: Type,
val rowId: Long,
val uri: Uri,
val mimeType: String?,
val dateModified: Long,
val orientation: Int,
val dateTaken: Long,
val displayName: String?
) : Parcelable
/** The type of data. */
enum class Type {
VIDEO, IMAGE
}