Fix sharing media inside the app (#7016)
When a `MediaSource` is disposed, the local temp file associated to it will be deleted from disk. When we try sharing a media from the media viewer screen to another room, this will dismiss the screen, which in turn will dispose of the media source and remove the file, which then fails to be shared. If we copy it first and then make sure we delete it after trying to send it, it works fine.
This commit is contained in:
committed by
GitHub
parent
710f501689
commit
8e9c0bedf2
+10
-1
@@ -7,6 +7,7 @@
|
||||
|
||||
package io.element.android.features.share.impl
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
@@ -15,13 +16,14 @@ import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.features.share.api.OnSharedData
|
||||
import io.element.android.features.share.api.ShareIntentData
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
import timber.log.Timber
|
||||
import kotlin.collections.forEach
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultOnSharedData(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val buildMeta: BuildMeta,
|
||||
) : OnSharedData {
|
||||
override fun invoke(data: ShareIntentData) {
|
||||
when (data) {
|
||||
@@ -29,6 +31,13 @@ class DefaultOnSharedData(
|
||||
// No-op, there is nothing to do for plain text intents.
|
||||
}
|
||||
is ShareIntentData.Uris -> {
|
||||
val fileProvider = "${buildMeta.applicationId}.fileprovider"
|
||||
for (sharedUri in data.uris) {
|
||||
// Remove the local copy of the shared file, as it is not needed anymore
|
||||
if (sharedUri.uri.scheme == ContentResolver.SCHEME_CONTENT && sharedUri.uri.host == fileProvider) {
|
||||
context.contentResolver.delete(sharedUri.uri, null)
|
||||
}
|
||||
}
|
||||
revokeUriPermissions(data.uris.map { it.uri })
|
||||
}
|
||||
}
|
||||
|
||||
+11
-4
@@ -100,7 +100,11 @@ class AndroidLocalMediaActions(
|
||||
override suspend fun share(localMedia: LocalMedia): Result<Unit> = withContext(coroutineDispatchers.io) {
|
||||
require(localMedia.uri.scheme == ContentResolver.SCHEME_FILE)
|
||||
runCatchingExceptions {
|
||||
val shareableUri = localMedia.toShareableUri()
|
||||
// Make a copy of the shared file in the cache directory, otherwise the original file will be gone once this screen is dismissed
|
||||
// and will prevent sharing the media to another room inside the app.
|
||||
val copiedFile = localMedia.uri.toFile()
|
||||
.copyTo(File(context.cacheDir, "temp/media/" + (localMedia.uri.lastPathSegment ?: "shared_file")), true)
|
||||
val shareableUri = copiedFile.toShareableUri()
|
||||
val shareMediaIntent = Intent(Intent.ACTION_SEND)
|
||||
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
.putExtra(Intent.EXTRA_STREAM, shareableUri)
|
||||
@@ -157,10 +161,13 @@ class AndroidLocalMediaActions(
|
||||
}
|
||||
}
|
||||
|
||||
private fun LocalMedia.toShareableUri(): Uri {
|
||||
val mediaAsFile = this.toFile()
|
||||
private fun File.toShareableUri(): Uri {
|
||||
val authority = "${buildMeta.applicationId}.fileprovider"
|
||||
return FileProvider.getUriForFile(context, authority, mediaAsFile).normalizeScheme()
|
||||
return FileProvider.getUriForFile(context, authority, this).normalizeScheme()
|
||||
}
|
||||
|
||||
private fun LocalMedia.toShareableUri(): Uri {
|
||||
return this.toFile().toShareableUri()
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
|
||||
Reference in New Issue
Block a user