Reworked Media Store export functions in compatibility packages

This commit is contained in:
Sylvain Berfini 2023-01-10 10:49:57 +01:00
parent 1238d8ace0
commit f32a2ec995
4 changed files with 152 additions and 183 deletions

View file

@ -95,7 +95,7 @@ class TopBarFragment : GenericFragment<FileViewerTopBarFragmentBinding>() {
Compatibility.addImageToMediaStore(requireContext(), content) Compatibility.addImageToMediaStore(requireContext(), content)
} }
if (export.await()) { if (export.await()) {
Log.i("[File Viewer] Adding image ${content.name} to Media Store terminated: ${content.userData}") Log.i("[File Viewer] Successfully exported image [${content.name}] to Media Store: ${content.userData}")
mediaStoreFilePath = content.userData.toString() mediaStoreFilePath = content.userData.toString()
} else { } else {
Log.e("[File Viewer] Something went wrong while copying file to Media Store...") Log.e("[File Viewer] Something went wrong while copying file to Media Store...")
@ -106,7 +106,7 @@ class TopBarFragment : GenericFragment<FileViewerTopBarFragmentBinding>() {
Compatibility.addVideoToMediaStore(requireContext(), content) Compatibility.addVideoToMediaStore(requireContext(), content)
} }
if (export.await()) { if (export.await()) {
Log.i("[File Viewer] Adding video ${content.name} to Media Store terminated: ${content.userData}") Log.i("[File Viewer] Successfully exported video [${content.name}] to Media Store: ${content.userData}")
mediaStoreFilePath = content.userData.toString() mediaStoreFilePath = content.userData.toString()
} else { } else {
Log.e("[File Viewer] Something went wrong while copying file to Media Store...") Log.e("[File Viewer] Something went wrong while copying file to Media Store...")
@ -117,14 +117,14 @@ class TopBarFragment : GenericFragment<FileViewerTopBarFragmentBinding>() {
Compatibility.addAudioToMediaStore(requireContext(), content) Compatibility.addAudioToMediaStore(requireContext(), content)
} }
if (export.await()) { if (export.await()) {
Log.i("[File Viewer] Adding audio ${content.name} to Media Store terminated: ${content.userData}") Log.i("[File Viewer] Successfully exported audio [${content.name}] to Media Store: ${content.userData}")
mediaStoreFilePath = content.userData.toString() mediaStoreFilePath = content.userData.toString()
} else { } else {
Log.e("[File Viewer] Something went wrong while copying file to Media Store...") Log.e("[File Viewer] Something went wrong while copying file to Media Store...")
} }
} }
else -> { else -> {
Log.w("[File Viewer] File ${content.name} isn't either an image, an audio file or a video, can't add it to the Media Store") Log.w("[File Viewer] File [${content.name}] isn't either an image, an audio file or a video, can't add it to the Media Store")
} }
} }
} else { } else {
@ -142,7 +142,7 @@ class TopBarFragment : GenericFragment<FileViewerTopBarFragmentBinding>() {
if (!FileUtils.openFileInThirdPartyApp(requireActivity(), plainFilePath)) { if (!FileUtils.openFileInThirdPartyApp(requireActivity(), plainFilePath)) {
(requireActivity() as SnackBarActivity).showSnackBar(R.string.chat_message_no_app_found_to_handle_file_mime_type) (requireActivity() as SnackBarActivity).showSnackBar(R.string.chat_message_no_app_found_to_handle_file_mime_type)
if (plainFilePath != content.filePath.orEmpty()) { if (plainFilePath != content.filePath.orEmpty()) {
Log.i("[File Viewer] No app to open plain file path: $plainFilePath, destroying it") Log.i("[File Viewer] No app to open plain file path [$plainFilePath], destroying it")
FileUtils.deleteFile(plainFilePath) FileUtils.deleteFile(plainFilePath)
} }
plainFilePath = "" plainFilePath = ""

View file

@ -142,119 +142,100 @@ class Api23Compatibility {
} }
suspend fun addImageToMediaStore(context: Context, content: Content): Boolean { suspend fun addImageToMediaStore(context: Context, content: Content): Boolean {
return addContentToMediaStore(context, content, isImage = true)
}
suspend fun addVideoToMediaStore(context: Context, content: Content): Boolean {
return addContentToMediaStore(context, content, isVideo = true)
}
suspend fun addAudioToMediaStore(context: Context, content: Content): Boolean {
return addContentToMediaStore(context, content, isAudio = true)
}
private suspend fun addContentToMediaStore(
context: Context,
content: Content,
isImage: Boolean = false,
isVideo: Boolean = false,
isAudio: Boolean = false
): Boolean {
if (!PermissionHelper.get().hasWriteExternalStoragePermission()) { if (!PermissionHelper.get().hasWriteExternalStoragePermission()) {
Log.e("[Media Store] Write external storage permission denied") Log.e("[Media Store] Write external storage permission denied")
return false return false
} }
val isContentEncrypted = content.isFileEncrypted
val filePath = if (content.isFileEncrypted) {
val plainFilePath = content.exportPlainFile().orEmpty() val plainFilePath = content.exportPlainFile().orEmpty()
val isVfsEncrypted = plainFilePath.isNotEmpty() Log.w("[Media Store] Content is encrypted, plain file path is: $plainFilePath")
Log.w("[Media Store] Content is encrypted, requesting plain file path") plainFilePath
val filePath = if (isVfsEncrypted) plainFilePath else content.filePath } else content.filePath
if (filePath == null) {
if (filePath.isNullOrEmpty()) {
Log.e("[Media Store] Content doesn't have a file path!") Log.e("[Media Store] Content doesn't have a file path!")
return false return false
} }
val appName = AppUtils.getString(R.string.app_name) val appName = AppUtils.getString(R.string.app_name)
val relativePath = "${Environment.DIRECTORY_PICTURES}/$appName" val directory = when {
isImage -> Environment.DIRECTORY_PICTURES
isVideo -> Environment.DIRECTORY_MOVIES
isAudio -> Environment.DIRECTORY_MUSIC
else -> Environment.DIRECTORY_DOWNLOADS
}
val relativePath = "$directory/$appName"
val fileName = content.name val fileName = content.name
val mime = "${content.type}/${content.subtype}" val mime = "${content.type}/${content.subtype}"
Log.i("[Media Store] Adding image $filePath to Media Store with name $fileName and MIME $mime, asking to be stored in $relativePath") val type = when {
isImage -> "image"
isVideo -> "video"
isAudio -> "audio"
else -> "unexpected"
}
Log.i("[Media Store] Adding $type [$filePath] to Media Store with name [$fileName] and MIME [$mime], asking to be stored in: $relativePath")
val mediaStoreFilePath = when {
isImage -> {
val values = ContentValues().apply { val values = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, fileName) put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
put(MediaStore.Images.Media.MIME_TYPE, mime) put(MediaStore.Images.Media.MIME_TYPE, mime)
} }
val collection = MediaStore.Images.Media.getContentUri("external") val collection = MediaStore.Images.Media.getContentUri("external")
val mediaStoreFilePath = addContentValuesToCollection(context, filePath, collection, values) addContentValuesToCollection(context, filePath, collection, values)
if (isVfsEncrypted) {
Log.w("[Media Store] Content was encrypted, delete plain version: $plainFilePath")
FileUtils.deleteFile(plainFilePath)
} }
if (mediaStoreFilePath.isNotEmpty()) { isVideo -> {
content.userData = mediaStoreFilePath
return true
}
return false
}
suspend fun addVideoToMediaStore(context: Context, content: Content): Boolean {
if (!PermissionHelper.get().hasWriteExternalStoragePermission()) {
Log.e("[Media Store] Write external storage permission denied")
return false
}
val plainFilePath = content.exportPlainFile().orEmpty()
val isVfsEncrypted = plainFilePath.isNotEmpty()
Log.w("[Media Store] Content is encrypted, requesting plain file path")
val filePath = if (isVfsEncrypted) plainFilePath else content.filePath
if (filePath == null) {
Log.e("[Media Store] Content doesn't have a file path!")
return false
}
val appName = AppUtils.getString(R.string.app_name)
val relativePath = "${Environment.DIRECTORY_MOVIES}/$appName"
val fileName = content.name
val mime = "${content.type}/${content.subtype}"
Log.i("[Media Store] Adding video $filePath to Media Store with name $fileName and MIME $mime, asking to be stored in $relativePath")
val values = ContentValues().apply { val values = ContentValues().apply {
put(MediaStore.Video.Media.TITLE, fileName) put(MediaStore.Video.Media.TITLE, fileName)
put(MediaStore.Video.Media.DISPLAY_NAME, fileName) put(MediaStore.Video.Media.DISPLAY_NAME, fileName)
put(MediaStore.Video.Media.MIME_TYPE, mime) put(MediaStore.Video.Media.MIME_TYPE, mime)
} }
val collection = MediaStore.Video.Media.getContentUri("external") val collection = MediaStore.Video.Media.getContentUri("external")
val mediaStoreFilePath = addContentValuesToCollection(context, filePath, collection, values) addContentValuesToCollection(context, filePath, collection, values)
if (isVfsEncrypted) {
Log.w("[Media Store] Content was encrypted, delete plain version: $plainFilePath")
FileUtils.deleteFile(plainFilePath)
} }
if (mediaStoreFilePath.isNotEmpty()) { isAudio -> {
content.userData = mediaStoreFilePath
return true
}
return false
}
suspend fun addAudioToMediaStore(context: Context, content: Content): Boolean {
if (!PermissionHelper.get().hasWriteExternalStoragePermission()) {
Log.e("[Media Store] Write external storage permission denied")
return false
}
val plainFilePath = content.exportPlainFile().orEmpty()
val isVfsEncrypted = plainFilePath.isNotEmpty()
Log.w("[Media Store] Content is encrypted, requesting plain file path")
val filePath = if (isVfsEncrypted) plainFilePath else content.filePath
if (filePath == null) {
Log.e("[Media Store] Content doesn't have a file path!")
return false
}
val appName = AppUtils.getString(R.string.app_name)
val relativePath = "${Environment.DIRECTORY_MUSIC}/$appName"
val fileName = content.name
val mime = "${content.type}/${content.subtype}"
Log.i("[Media Store] Adding audio $filePath to Media Store with name $fileName and MIME $mime, asking to be stored in $relativePath")
val values = ContentValues().apply { val values = ContentValues().apply {
put(MediaStore.Audio.Media.TITLE, fileName) put(MediaStore.Audio.Media.TITLE, fileName)
put(MediaStore.Audio.Media.DISPLAY_NAME, fileName) put(MediaStore.Audio.Media.DISPLAY_NAME, fileName)
put(MediaStore.Audio.Media.MIME_TYPE, mime) put(MediaStore.Audio.Media.MIME_TYPE, mime)
} }
val collection = MediaStore.Audio.Media.getContentUri("external") val collection = MediaStore.Audio.Media.getContentUri("external")
addContentValuesToCollection(context, filePath, collection, values)
val mediaStoreFilePath = addContentValuesToCollection(context, filePath, collection, values)
if (isVfsEncrypted) {
Log.w("[Media Store] Content was encrypted, delete plain version: $plainFilePath")
FileUtils.deleteFile(plainFilePath)
} }
else -> ""
}
if (isContentEncrypted) {
Log.w("[Media Store] Content was encrypted, delete plain version: $filePath")
FileUtils.deleteFile(filePath)
}
if (mediaStoreFilePath.isNotEmpty()) { if (mediaStoreFilePath.isNotEmpty()) {
Log.i("[Media Store] Exported file path is: $mediaStoreFilePath")
content.userData = mediaStoreFilePath content.userData = mediaStoreFilePath
return true return true
} }
return false return false
} }

View file

@ -104,21 +104,56 @@ class Api29Compatibility {
} }
suspend fun addImageToMediaStore(context: Context, content: Content): Boolean { suspend fun addImageToMediaStore(context: Context, content: Content): Boolean {
return addContentToMediaStore(context, content, isImage = true)
}
suspend fun addVideoToMediaStore(context: Context, content: Content): Boolean {
return addContentToMediaStore(context, content, isVideo = true)
}
suspend fun addAudioToMediaStore(context: Context, content: Content): Boolean {
return addContentToMediaStore(context, content, isAudio = true)
}
private suspend fun addContentToMediaStore(
context: Context,
content: Content,
isImage: Boolean = false,
isVideo: Boolean = false,
isAudio: Boolean = false
): Boolean {
val isContentEncrypted = content.isFileEncrypted
val filePath = if (content.isFileEncrypted) {
val plainFilePath = content.exportPlainFile().orEmpty() val plainFilePath = content.exportPlainFile().orEmpty()
val isVfsEncrypted = plainFilePath.isNotEmpty() Log.w("[Media Store] Content is encrypted, plain file path is: $plainFilePath")
Log.w("[Media Store] Content is encrypted, requesting plain file path") plainFilePath
val filePath = if (isVfsEncrypted) plainFilePath else content.filePath } else content.filePath
if (filePath == null) {
if (filePath.isNullOrEmpty()) {
Log.e("[Media Store] Content doesn't have a file path!") Log.e("[Media Store] Content doesn't have a file path!")
return false return false
} }
val appName = AppUtils.getString(R.string.app_name) val appName = AppUtils.getString(R.string.app_name)
val relativePath = "${Environment.DIRECTORY_PICTURES}/$appName" val directory = when {
isImage -> Environment.DIRECTORY_PICTURES
isVideo -> Environment.DIRECTORY_MOVIES
isAudio -> Environment.DIRECTORY_MUSIC
else -> Environment.DIRECTORY_DOWNLOADS
}
val relativePath = "$directory/$appName"
val fileName = content.name val fileName = content.name
val mime = "${content.type}/${content.subtype}" val mime = "${content.type}/${content.subtype}"
Log.i("[Media Store] Adding image $filePath to Media Store with name $fileName and MIME $mime, asking to be stored in $relativePath") val type = when {
isImage -> "image"
isVideo -> "video"
isAudio -> "audio"
else -> "unexpected"
}
Log.i("[Media Store] Adding $type [$filePath] to Media Store with name [$fileName] and MIME [$mime], asking to be stored in: $relativePath")
val mediaStoreFilePath = when {
isImage -> {
val values = ContentValues().apply { val values = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, fileName) put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
put(MediaStore.Images.Media.MIME_TYPE, mime) put(MediaStore.Images.Media.MIME_TYPE, mime)
@ -126,35 +161,9 @@ class Api29Compatibility {
put(MediaStore.Images.Media.IS_PENDING, 1) put(MediaStore.Images.Media.IS_PENDING, 1)
} }
val collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val mediaStoreFilePath = addContentValuesToCollection(context, filePath, collection, values, MediaStore.Images.Media.IS_PENDING) addContentValuesToCollection(context, filePath, collection, values, MediaStore.Images.Media.IS_PENDING)
if (isVfsEncrypted) {
Log.w("[Media Store] Content was encrypted, delete plain version: $plainFilePath")
FileUtils.deleteFile(plainFilePath)
} }
if (mediaStoreFilePath.isNotEmpty()) { isVideo -> {
content.userData = mediaStoreFilePath
return true
}
return false
}
suspend fun addVideoToMediaStore(context: Context, content: Content): Boolean {
val plainFilePath = content.exportPlainFile().orEmpty()
val isVfsEncrypted = plainFilePath.isNotEmpty()
Log.w("[Media Store] Content is encrypted, requesting plain file path")
val filePath = if (isVfsEncrypted) plainFilePath else content.filePath
if (filePath == null) {
Log.e("[Media Store] Content doesn't have a file path!")
return false
}
val appName = AppUtils.getString(R.string.app_name)
val relativePath = "${Environment.DIRECTORY_MOVIES}/$appName"
val fileName = content.name
val mime = "${content.type}/${content.subtype}"
Log.i("[Media Store] Adding video $filePath to Media Store with name $fileName and MIME $mime, asking to be stored in $relativePath")
val values = ContentValues().apply { val values = ContentValues().apply {
put(MediaStore.Video.Media.TITLE, fileName) put(MediaStore.Video.Media.TITLE, fileName)
put(MediaStore.Video.Media.DISPLAY_NAME, fileName) put(MediaStore.Video.Media.DISPLAY_NAME, fileName)
@ -163,35 +172,9 @@ class Api29Compatibility {
put(MediaStore.Video.Media.IS_PENDING, 1) put(MediaStore.Video.Media.IS_PENDING, 1)
} }
val collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val mediaStoreFilePath = addContentValuesToCollection(context, filePath, collection, values, MediaStore.Video.Media.IS_PENDING) addContentValuesToCollection(context, filePath, collection, values, MediaStore.Video.Media.IS_PENDING)
if (isVfsEncrypted) {
Log.w("[Media Store] Content was encrypted, delete plain version: $plainFilePath")
FileUtils.deleteFile(plainFilePath)
} }
if (mediaStoreFilePath.isNotEmpty()) { isAudio -> {
content.userData = mediaStoreFilePath
return true
}
return false
}
suspend fun addAudioToMediaStore(context: Context, content: Content): Boolean {
val plainFilePath = content.exportPlainFile().orEmpty()
val isVfsEncrypted = plainFilePath.isNotEmpty()
Log.w("[Media Store] Content is encrypted, requesting plain file path")
val filePath = if (isVfsEncrypted) plainFilePath else content.filePath
if (filePath == null) {
Log.e("[Media Store] Content doesn't have a file path!")
return false
}
val appName = AppUtils.getString(R.string.app_name)
val relativePath = "${Environment.DIRECTORY_MUSIC}/$appName"
val fileName = content.name
val mime = "${content.type}/${content.subtype}"
Log.i("[Media Store] Adding audio $filePath to Media Store with name $fileName and MIME $mime, asking to be stored in $relativePath")
val values = ContentValues().apply { val values = ContentValues().apply {
put(MediaStore.Audio.Media.TITLE, fileName) put(MediaStore.Audio.Media.TITLE, fileName)
put(MediaStore.Audio.Media.DISPLAY_NAME, fileName) put(MediaStore.Audio.Media.DISPLAY_NAME, fileName)
@ -200,17 +183,22 @@ class Api29Compatibility {
put(MediaStore.Audio.Media.IS_PENDING, 1) put(MediaStore.Audio.Media.IS_PENDING, 1)
} }
val collection = MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val collection = MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
addContentValuesToCollection(context, filePath, collection, values, MediaStore.Audio.Media.IS_PENDING)
val mediaStoreFilePath = addContentValuesToCollection(context, filePath, collection, values, MediaStore.Audio.Media.IS_PENDING)
if (isVfsEncrypted) {
Log.w("[Media Store] Content was encrypted, delete plain version: $plainFilePath")
FileUtils.deleteFile(plainFilePath)
} }
else -> ""
}
if (isContentEncrypted) {
Log.w("[Media Store] Content was encrypted, delete plain version: $filePath")
FileUtils.deleteFile(filePath)
}
if (mediaStoreFilePath.isNotEmpty()) { if (mediaStoreFilePath.isNotEmpty()) {
Log.i("[Media Store] Exported file path is: $mediaStoreFilePath")
content.userData = mediaStoreFilePath content.userData = mediaStoreFilePath
return true return true
} }
return false return false
} }

View file

@ -897,21 +897,21 @@ class CoreContext(
when { when {
FileUtils.isExtensionImage(filePath) -> { FileUtils.isExtensionImage(filePath) -> {
if (Compatibility.addImageToMediaStore(context, content)) { if (Compatibility.addImageToMediaStore(context, content)) {
Log.i("[Context] Adding image ${content.name} to Media Store terminated") Log.i("[Context] Successfully exported image [${content.name}] to Media Store")
} else { } else {
Log.e("[Context] Something went wrong while copying file to Media Store...") Log.e("[Context] Something went wrong while copying file to Media Store...")
} }
} }
FileUtils.isExtensionVideo(filePath) -> { FileUtils.isExtensionVideo(filePath) -> {
if (Compatibility.addVideoToMediaStore(context, content)) { if (Compatibility.addVideoToMediaStore(context, content)) {
Log.i("[Context] Adding video ${content.name} to Media Store terminated") Log.i("[Context] Successfully exported video [${content.name}] to Media Store")
} else { } else {
Log.e("[Context] Something went wrong while copying file to Media Store...") Log.e("[Context] Something went wrong while copying file to Media Store...")
} }
} }
FileUtils.isExtensionAudio(filePath) -> { FileUtils.isExtensionAudio(filePath) -> {
if (Compatibility.addAudioToMediaStore(context, content)) { if (Compatibility.addAudioToMediaStore(context, content)) {
Log.i("[Context] Adding audio ${content.name} to Media Store terminated") Log.i("[Context] Successfully exported audio [${content.name}] to Media Store")
} else { } else {
Log.e("[Context] Something went wrong while copying file to Media Store...") Log.e("[Context] Something went wrong while copying file to Media Store...")
} }