Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Commit 235a187

Browse files
committed
Use MediaStore to get file properties
1 parent 1cb595a commit 235a187

1 file changed

Lines changed: 19 additions & 54 deletions

File tree

ScopedStorage/app/src/main/java/com/samples/storage/mediastore/AddDocumentViewModel.kt

Lines changed: 19 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ import okhttp3.Request
4646
import okhttp3.ResponseBody
4747
import java.io.File
4848
import java.net.URLConnection
49-
import java.nio.file.Files
50-
import java.nio.file.attribute.FileTime
49+
5150

5251
private const val TAG = "AddDocumentViewModel"
5352

@@ -131,9 +130,9 @@ class AddDocumentViewModel(
131130
withContext(Dispatchers.IO) {
132131
try {
133132
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
134-
val uri = addFileToDownloadsApi29(filename)
135-
val outputStream = context.contentResolver.openOutputStream(uri, "w")
136-
?: throw Exception("ContentResolver couldn't open $uri outputStream")
133+
val newFileUri = addFileToDownloadsApi29(filename)
134+
val outputStream = context.contentResolver.openOutputStream(newFileUri, "w")
135+
?: throw Exception("ContentResolver couldn't open $newFileUri outputStream")
137136

138137
val responseBody = downloadFileFromInternet(randomRemoteUrl)
139138

@@ -150,18 +149,18 @@ class AddDocumentViewModel(
150149
}
151150
}
152151

153-
Log.d(TAG, "File downloaded ($uri)")
152+
Log.d(TAG, "File downloaded ($newFileUri)")
154153

155-
val path = getMediaStoreEntryPathApi29(uri)
156-
?: throw Exception("ContentResolver couldn't find $uri")
154+
val path = getMediaStoreEntryPathApi29(newFileUri)
155+
?: throw Exception("ContentResolver couldn't find $newFileUri")
157156

158157
// We scan the newly added file to make sure MediaStore.Downloads is always up
159158
// to date
160-
scanFilePath(path, responseBody.contentType().toString()) {
161-
Log.d(TAG, "MediaStore updated ($path)")
159+
scanFilePath(path, responseBody.contentType().toString()) { uri ->
160+
Log.d(TAG, "MediaStore updated ($path, $uri)")
162161

163162
viewModelScope.launch {
164-
val fileDetails = getFileDetailsApi29(uri)
163+
val fileDetails = getFileDetails(uri)
165164
Log.d(TAG, "New file: $fileDetails")
166165

167166
_currentFileEntry.postValue(fileDetails)
@@ -191,15 +190,11 @@ class AddDocumentViewModel(
191190

192191
// We scan the newly added file to make sure MediaStore.Files is always up to
193192
// date
194-
scanFilePath(file.path, responseBody.contentType().toString()) {
195-
Log.d(TAG, "MediaStore updated ($file.path)")
193+
scanFilePath(file.path, responseBody.contentType().toString()) { uri ->
194+
Log.d(TAG, "MediaStore updated ($file.path, $uri)")
196195

197196
viewModelScope.launch {
198-
val fileDetails = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
199-
getFileDetailsApi26(file.absolutePath)
200-
} else {
201-
getFileDetailsApi21(file.absolutePath)
202-
}
197+
val fileDetails = getFileDetails(uri)
203198
Log.d(TAG, "New file: $fileDetails")
204199

205200
_currentFileEntry.postValue(fileDetails)
@@ -274,10 +269,10 @@ class AddDocumentViewModel(
274269
* size, even though the file is definitely not empty. MediaStore will eventually scan the file
275270
* but it's better to do it ourselves to have a fresher state whenever we can
276271
*/
277-
private suspend fun scanFilePath(path: String, mimeType: String, callback: () -> Unit) {
272+
private suspend fun scanFilePath(path: String, mimeType: String, callback: (uri: Uri) -> Unit) {
278273
withContext(Dispatchers.IO) {
279-
MediaScannerConnection.scanFile(context, arrayOf(path), arrayOf(mimeType)) { _, _ ->
280-
callback()
274+
MediaScannerConnection.scanFile(context, arrayOf(path), arrayOf(mimeType)) { _, uri ->
275+
callback(uri)
281276
}
282277
}
283278
}
@@ -311,7 +306,7 @@ class AddDocumentViewModel(
311306
* It uses the classic java.io APIs but can't get the added time as there's not a reliable way
312307
* to do so until Api 26
313308
*/
314-
private suspend fun getFileDetailsApi21(path: String): FileEntry? {
309+
private suspend fun getFileDetailsIoApi21(path: String): FileEntry? {
315310
return withContext(Dispatchers.IO) {
316311
val file = File(path)
317312

@@ -331,41 +326,11 @@ class AddDocumentViewModel(
331326
}
332327

333328
/**
334-
* Get file details on Api 26
335-
*
336-
* It uses java.nio APIs to get the mime type and added time properties
337-
*/
338-
@Suppress("BlockingMethodInNonBlockingContext")
339-
@RequiresApi(Build.VERSION_CODES.O)
340-
private suspend fun getFileDetailsApi26(path: String): FileEntry? {
341-
return withContext(Dispatchers.IO) {
342-
val file = File(path)
343-
344-
if (!file.exists()) {
345-
return@withContext null
346-
}
347-
348-
return@withContext FileEntry(
349-
filename = file.name,
350-
size = file.length(),
351-
mimeType = Files.probeContentType(file.toPath()),
352-
addedAt = (
353-
Files.getAttribute(
354-
file.toPath(),
355-
"creationTime"
356-
) as FileTime
357-
).toMillis(),
358-
path = path
359-
)
360-
}
361-
}
362-
363-
/**
364-
* Get file details on Api 29
329+
* Get file details on Api 21
365330
*
366331
* It uses MediaStore to all the file properties
367332
*/
368-
private suspend fun getFileDetailsApi29(uri: Uri): FileEntry? {
333+
private suspend fun getFileDetails(uri: Uri): FileEntry? {
369334
return withContext(Dispatchers.IO) {
370335
val cursor = context.contentResolver.query(
371336
uri,

0 commit comments

Comments
 (0)