From 950f5a0207d3a88d881f5d26161ec6e2f0c60f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Tue, 25 Jul 2023 12:13:54 +0200 Subject: [PATCH] Read using new queries on R+ devices to properly get trashed media --- app/build.gradle | 2 +- .../voicerecorder/extensions/Activity.kt | 8 +-- .../voicerecorder/extensions/Context.kt | 70 ++++++++++++++----- 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3409246..5a146b2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -63,7 +63,7 @@ android { } dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:f76d729b9d' + implementation 'com.github.esensar:Simple-Commons:6e36665609' implementation 'org.greenrobot:eventbus:3.3.1' implementation 'com.github.Armen101:AudioRecordView:1.0.4' implementation 'androidx.documentfile:documentfile:1.0.1' diff --git a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Activity.kt b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Activity.kt index 2ba3022..b940621 100644 --- a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Activity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Activity.kt @@ -3,13 +3,13 @@ package com.simplemobiletools.voicerecorder.extensions import android.content.ContentValues import android.provider.MediaStore import android.provider.MediaStore.Audio.Media -import androidx.core.net.toUri import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.extensions.deleteFile import com.simplemobiletools.commons.extensions.getParentPath import com.simplemobiletools.commons.extensions.toFileDirItem import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.models.FileDirItem +import com.simplemobiletools.voicerecorder.helpers.getAudioFileContentUri import com.simplemobiletools.voicerecorder.models.Recording import java.io.File @@ -17,7 +17,7 @@ fun BaseSimpleActivity.deleteRecordings(recordingsToRemove: Collection { val fileUris = recordingsToRemove.map { recording -> - "${Media.EXTERNAL_CONTENT_URI}/${recording.id.toLong()}".toUri() + getAudioFileContentUri(recording.id.toLong()) } deleteSDK30Uris(fileUris, callback) @@ -52,7 +52,7 @@ fun BaseSimpleActivity.restoreRecordings(recordingsToRestore: Collection { val fileUris = recordingsToRestore.map { recording -> - "${Media.EXTERNAL_CONTENT_URI}/${recording.id.toLong()}".toUri() + getAudioFileContentUri(recording.id.toLong()) } trashSDK30Uris(fileUris, false, callback) @@ -107,7 +107,7 @@ fun BaseSimpleActivity.moveRecordingsToRecycleBin(recordingsToMove: Collection { val fileUris = recordingsToMove.map { recording -> - "${Media.EXTERNAL_CONTENT_URI}/${recording.id.toLong()}".toUri() + getAudioFileContentUri(recording.id.toLong()) } trashSDK30Uris(fileUris, true, callback) diff --git a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Context.kt index 863de5c..173962b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Context.kt @@ -3,13 +3,16 @@ package com.simplemobiletools.voicerecorder.extensions import android.annotation.SuppressLint import android.appwidget.AppWidgetManager import android.content.ComponentName +import android.content.ContentResolver import android.content.Context import android.content.Intent +import android.database.Cursor import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.drawable.Drawable import android.media.MediaMetadataRetriever import android.net.Uri +import android.os.Bundle import android.os.Environment import android.provider.MediaStore import android.provider.MediaStore.Audio.Media @@ -57,6 +60,37 @@ fun Context.getDefaultRecordingsRelativePath(): String { } } +@SuppressLint("InlinedApi") +fun Context.getNewMediaStoreRecordings(trashed: Boolean = false): ArrayList { + val recordings = ArrayList() + + val uri = Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) + val projection = arrayOf( + Media._ID, + Media.DISPLAY_NAME, + Media.DATE_ADDED, + Media.DURATION, + Media.SIZE + ) + + val bundle = Bundle().apply { + putStringArray(ContentResolver.QUERY_ARG_SORT_COLUMNS, arrayOf(Media.DATE_ADDED)) + putInt(ContentResolver.QUERY_ARG_SORT_DIRECTION, ContentResolver.QUERY_SORT_DIRECTION_DESCENDING) + putString(ContentResolver.QUERY_ARG_SQL_SELECTION, "${Media.OWNER_PACKAGE_NAME} = ?") + putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, arrayOf(packageName)) + if (config.useRecycleBin) { + val trashedValue = if (trashed) MediaStore.MATCH_ONLY else MediaStore.MATCH_EXCLUDE + putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, trashedValue) + } + } + queryCursor(uri, projection, bundle, true) { cursor -> + val recording = readRecordingFromCursor(cursor) + recordings.add(recording) + } + + return recordings +} + @SuppressLint("InlinedApi") fun Context.getMediaStoreRecordings(trashed: Boolean = false): ArrayList { val recordings = ArrayList() @@ -81,21 +115,7 @@ fun Context.getMediaStoreRecordings(trashed: Boolean = false): ArrayList - val id = cursor.getIntValue(Media._ID) - val title = cursor.getStringValue(Media.DISPLAY_NAME) - val timestamp = cursor.getIntValue(Media.DATE_ADDED) - var duration = cursor.getLongValue(Media.DURATION) / 1000 - var size = cursor.getIntValue(Media.SIZE) - - if (duration == 0L) { - duration = getDurationFromUri(getAudioFileContentUri(id.toLong())) - } - - if (size == 0) { - size = getSizeFromUri(id.toLong()) - } - - val recording = Recording(id, title, "", timestamp, duration.toInt(), size) + val recording = readRecordingFromCursor(cursor) recordings.add(recording) } @@ -152,7 +172,7 @@ fun Context.getAllRecordings(trashed: Boolean = false): ArrayList { val recordings = ArrayList() return when { isRPlus() -> { - recordings.addAll(getMediaStoreRecordings(trashed)) + recordings.addAll(getNewMediaStoreRecordings(trashed)) recordings.addAll(getSAFRecordings(trashed)) recordings } @@ -181,6 +201,24 @@ fun Context.getOrCreateTrashFolder(): String { return trashFolder } +private fun Context.readRecordingFromCursor(cursor: Cursor): Recording { + val id = cursor.getIntValue(Media._ID) + val title = cursor.getStringValue(Media.DISPLAY_NAME) + val timestamp = cursor.getIntValue(Media.DATE_ADDED) + var duration = cursor.getLongValue(Media.DURATION) / 1000 + var size = cursor.getIntValue(Media.SIZE) + + if (duration == 0L) { + duration = getDurationFromUri(getAudioFileContentUri(id.toLong())) + } + + if (size == 0) { + size = getSizeFromUri(id.toLong()) + } + + return Recording(id, title, "", timestamp, duration.toInt(), size) +} + private fun Context.getSizeFromUri(id: Long): Int { val recordingUri = getAudioFileContentUri(id) return try {