diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentAttachmentData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentAttachmentData.kt
index e32bb9f21f..b80a17b017 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentAttachmentData.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/content/ContentAttachmentData.kt
@@ -16,6 +16,7 @@
 
 package im.vector.matrix.android.api.session.content
 
+import android.net.Uri
 import android.os.Parcelable
 import androidx.exifinterface.media.ExifInterface
 import kotlinx.android.parcel.Parcelize
@@ -29,8 +30,7 @@ data class ContentAttachmentData(
         val width: Long? = 0,
         val exifOrientation: Int = ExifInterface.ORIENTATION_UNDEFINED,
         val name: String? = null,
-        val queryUri: String,
-        val path: String,
+        val queryUri: Uri,
         private val mimeType: String?,
         val type: Type
 ) : Parcelable {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt
index 4071c9224f..4fa0cb5013 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt
@@ -53,9 +53,9 @@ internal class FileUploader @Inject constructor(@Authenticated
 
     suspend fun uploadByteArray(byteArray: ByteArray,
                                 filename: String?,
-                                mimeType: String,
+                                mimeType: String?,
                                 progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse {
-        val uploadBody = byteArray.toRequestBody(mimeType.toMediaTypeOrNull())
+        val uploadBody = byteArray.toRequestBody(mimeType?.toMediaTypeOrNull())
         return upload(uploadBody, filename, progressListener)
     }
 
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ThumbnailExtractor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ThumbnailExtractor.kt
index 083cac0278..2ce249ab80 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ThumbnailExtractor.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/ThumbnailExtractor.kt
@@ -16,12 +16,14 @@
 
 package im.vector.matrix.android.internal.session.content
 
+import android.content.Context
 import android.graphics.Bitmap
-import android.media.ThumbnailUtils
-import android.provider.MediaStore
+import android.media.MediaMetadataRetriever
 import im.vector.matrix.android.api.session.content.ContentAttachmentData
+import timber.log.Timber
 import java.io.ByteArrayOutputStream
-import java.io.File
+import kotlin.math.max
+import kotlin.math.roundToInt
 
 internal object ThumbnailExtractor {
 
@@ -33,34 +35,48 @@ internal object ThumbnailExtractor {
             val mimeType: String
     )
 
-    fun extractThumbnail(attachment: ContentAttachmentData): ThumbnailData? {
-        val file = File(attachment.path)
-        if (!file.exists() || !file.isFile) {
-            return null
-        }
+    fun extractThumbnail(context: Context, attachment: ContentAttachmentData): ThumbnailData? {
         return if (attachment.type == ContentAttachmentData.Type.VIDEO) {
-            extractVideoThumbnail(attachment)
+            extractVideoThumbnail(context, attachment)
         } else {
             null
         }
     }
 
-    private fun extractVideoThumbnail(attachment: ContentAttachmentData): ThumbnailData? {
-        val thumbnail = ThumbnailUtils.createVideoThumbnail(attachment.path, MediaStore.Video.Thumbnails.MINI_KIND) ?: return null
-        val outputStream = ByteArrayOutputStream()
-        thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
-        val thumbnailWidth = thumbnail.width
-        val thumbnailHeight = thumbnail.height
-        val thumbnailSize = outputStream.size()
-        val thumbnailData = ThumbnailData(
-                width = thumbnailWidth,
-                height = thumbnailHeight,
-                size = thumbnailSize.toLong(),
-                bytes = outputStream.toByteArray(),
-                mimeType = "image/jpeg"
-        )
-        thumbnail.recycle()
-        outputStream.reset()
-        return thumbnailData
+    private fun extractVideoThumbnail(context: Context, attachment: ContentAttachmentData): ThumbnailData? {
+        val mediaMetadataRetriever = MediaMetadataRetriever()
+        try {
+            mediaMetadataRetriever.setDataSource(context, attachment.queryUri)
+            var thumbnail = mediaMetadataRetriever.frameAtTime
+            // Scale down the bitmap if it's too large.
+            val width: Int = thumbnail.width
+            val height: Int = thumbnail.height
+            val max = max(width, height)
+            if (max > 512) {
+                val scale = 512f / max
+                val w = (scale * width).roundToInt()
+                val h = (scale * height).roundToInt()
+                thumbnail = Bitmap.createScaledBitmap(thumbnail, w, h, true)
+            }
+
+            val outputStream = ByteArrayOutputStream()
+            thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
+            val thumbnailWidth = thumbnail.width
+            val thumbnailHeight = thumbnail.height
+            val thumbnailSize = outputStream.size()
+            val thumbnailData = ThumbnailData(
+                    width = thumbnailWidth,
+                    height = thumbnailHeight,
+                    size = thumbnailSize.toLong(),
+                    bytes = outputStream.toByteArray(),
+                    mimeType = "image/jpeg"
+            )
+            thumbnail.recycle()
+            outputStream.reset()
+            return thumbnailData
+        } catch (e: Exception) {
+            Timber.e(e, "Cannot extract video thumbnail")
+            return null
+        }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt
index 1c88f87804..21ab649c23 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt
@@ -17,12 +17,9 @@
 package im.vector.matrix.android.internal.session.content
 
 import android.content.Context
-import android.graphics.BitmapFactory
 import androidx.work.CoroutineWorker
 import androidx.work.WorkerParameters
 import com.squareup.moshi.JsonClass
-import id.zelory.compressor.Compressor
-import id.zelory.compressor.constraint.default
 import im.vector.matrix.android.api.session.content.ContentAttachmentData
 import im.vector.matrix.android.api.session.events.model.Event
 import im.vector.matrix.android.api.session.events.model.toContent
@@ -41,8 +38,6 @@ import im.vector.matrix.android.internal.worker.WorkerParamsFactory
 import im.vector.matrix.android.internal.worker.getSessionComponent
 import timber.log.Timber
 import java.io.ByteArrayInputStream
-import java.io.File
-import java.io.FileInputStream
 import javax.inject.Inject
 
 private data class NewImageAttributes(
@@ -94,8 +89,84 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
 
         var newImageAttributes: NewImageAttributes? = null
 
-        val attachmentFile = try {
-            File(attachment.path)
+        try {
+            val inputStream = context.contentResolver.openInputStream(attachment.queryUri) ?: return Result.success()
+
+            inputStream.use {
+                var uploadedThumbnailUrl: String? = null
+                var uploadedThumbnailEncryptedFileInfo: EncryptedFileInfo? = null
+
+                ThumbnailExtractor.extractThumbnail(context, params.attachment)?.let { thumbnailData ->
+                    val thumbnailProgressListener = object : ProgressRequestBody.Listener {
+                        override fun onProgress(current: Long, total: Long) {
+                            notifyTracker(params) { contentUploadStateTracker.setProgressThumbnail(it, current, total) }
+                        }
+                    }
+
+                    try {
+                        val contentUploadResponse = if (params.isEncrypted) {
+                            Timber.v("Encrypt thumbnail")
+                            notifyTracker(params) { contentUploadStateTracker.setEncryptingThumbnail(it) }
+                            val encryptionResult = MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType)
+                            uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo
+                            fileUploader.uploadByteArray(encryptionResult.encryptedByteArray,
+                                    "thumb_${attachment.name}",
+                                    "application/octet-stream",
+                                    thumbnailProgressListener)
+                        } else {
+                            fileUploader.uploadByteArray(thumbnailData.bytes,
+                                    "thumb_${attachment.name}",
+                                    thumbnailData.mimeType,
+                                    thumbnailProgressListener)
+                        }
+
+                        uploadedThumbnailUrl = contentUploadResponse.contentUri
+                    } catch (t: Throwable) {
+                        Timber.e(t)
+                        return handleFailure(params, t)
+                    }
+                }
+
+                val progressListener = object : ProgressRequestBody.Listener {
+                    override fun onProgress(current: Long, total: Long) {
+                        notifyTracker(params) {
+                            if (isStopped) {
+                                contentUploadStateTracker.setFailure(it, Throwable("Cancelled"))
+                            } else {
+                                contentUploadStateTracker.setProgress(it, current, total)
+                            }
+                        }
+                    }
+                }
+
+                var uploadedFileEncryptedFileInfo: EncryptedFileInfo? = null
+
+                return try {
+                    val contentUploadResponse = if (params.isEncrypted) {
+                        Timber.v("Encrypt file")
+                        notifyTracker(params) { contentUploadStateTracker.setEncrypting(it) }
+
+                        val encryptionResult = MXEncryptedAttachments.encryptAttachment(inputStream, attachment.getSafeMimeType())
+                        uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo
+
+                        fileUploader
+                                .uploadByteArray(encryptionResult.encryptedByteArray, attachment.name, "application/octet-stream", progressListener)
+                    } else {
+                        fileUploader
+                                .uploadByteArray(inputStream.readBytes(), attachment.name, attachment.getSafeMimeType(), progressListener)
+                    }
+
+                    handleSuccess(params,
+                            contentUploadResponse.contentUri,
+                            uploadedFileEncryptedFileInfo,
+                            uploadedThumbnailUrl,
+                            uploadedThumbnailEncryptedFileInfo,
+                            newImageAttributes)
+                } catch (t: Throwable) {
+                    Timber.e(t)
+                    handleFailure(params, t)
+                }
+            }
         } catch (e: Exception) {
             Timber.e(e)
             notifyTracker(params) { contentUploadStateTracker.setFailure(it, e) }
@@ -106,109 +177,6 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
                             )
                     )
             )
-        }
-                .let { originalFile ->
-                    if (attachment.type == ContentAttachmentData.Type.IMAGE) {
-                        if (params.compressBeforeSending) {
-                            Compressor.compress(context, originalFile) {
-                                default(
-                                        width = MAX_IMAGE_SIZE,
-                                        height = MAX_IMAGE_SIZE
-                                )
-                            }.also { compressedFile ->
-                                // Update the params
-                                val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
-                                BitmapFactory.decodeFile(compressedFile.absolutePath, options)
-                                val fileSize = compressedFile.length().toInt()
-
-                                newImageAttributes = NewImageAttributes(
-                                        options.outWidth,
-                                        options.outHeight,
-                                        fileSize
-                                )
-                            }
-                        } else {
-                            // TODO Fix here the image rotation issue
-                            originalFile
-                        }
-                    } else {
-                        // Other type
-                        originalFile
-                    }
-                }
-
-        var uploadedThumbnailUrl: String? = null
-        var uploadedThumbnailEncryptedFileInfo: EncryptedFileInfo? = null
-
-        ThumbnailExtractor.extractThumbnail(params.attachment)?.let { thumbnailData ->
-            val thumbnailProgressListener = object : ProgressRequestBody.Listener {
-                override fun onProgress(current: Long, total: Long) {
-                    notifyTracker(params) { contentUploadStateTracker.setProgressThumbnail(it, current, total) }
-                }
-            }
-
-            try {
-                val contentUploadResponse = if (params.isEncrypted) {
-                    Timber.v("Encrypt thumbnail")
-                    notifyTracker(params) { contentUploadStateTracker.setEncryptingThumbnail(it) }
-                    val encryptionResult = MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType)
-                    uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo
-                    fileUploader.uploadByteArray(encryptionResult.encryptedByteArray,
-                            "thumb_${attachment.name}",
-                            "application/octet-stream",
-                            thumbnailProgressListener)
-                } else {
-                    fileUploader.uploadByteArray(thumbnailData.bytes,
-                            "thumb_${attachment.name}",
-                            thumbnailData.mimeType,
-                            thumbnailProgressListener)
-                }
-
-                uploadedThumbnailUrl = contentUploadResponse.contentUri
-            } catch (t: Throwable) {
-                Timber.e(t)
-                return handleFailure(params, t)
-            }
-        }
-
-        val progressListener = object : ProgressRequestBody.Listener {
-            override fun onProgress(current: Long, total: Long) {
-                notifyTracker(params) {
-                    if (isStopped) {
-                        contentUploadStateTracker.setFailure(it, Throwable("Cancelled"))
-                    } else {
-                        contentUploadStateTracker.setProgress(it, current, total)
-                    }
-                }
-            }
-        }
-
-        var uploadedFileEncryptedFileInfo: EncryptedFileInfo? = null
-
-        return try {
-            val contentUploadResponse = if (params.isEncrypted) {
-                Timber.v("Encrypt file")
-                notifyTracker(params) { contentUploadStateTracker.setEncrypting(it) }
-
-                val encryptionResult = MXEncryptedAttachments.encryptAttachment(FileInputStream(attachmentFile), attachment.getSafeMimeType())
-                uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo
-
-                fileUploader
-                        .uploadByteArray(encryptionResult.encryptedByteArray, attachment.name, "application/octet-stream", progressListener)
-            } else {
-                fileUploader
-                        .uploadFile(attachmentFile, attachment.name, attachment.getSafeMimeType(), progressListener)
-            }
-
-            handleSuccess(params,
-                    contentUploadResponse.contentUri,
-                    uploadedFileEncryptedFileInfo,
-                    uploadedThumbnailUrl,
-                    uploadedThumbnailEncryptedFileInfo,
-                    newImageAttributes)
-        } catch (t: Throwable) {
-            Timber.e(t)
-            handleFailure(params, t)
         }
     }
 
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt
index f10c40ded5..a4a6eb6972 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt
@@ -16,6 +16,7 @@
 
 package im.vector.matrix.android.internal.session.room.send
 
+import android.content.Context
 import android.graphics.Bitmap
 import android.media.MediaMetadataRetriever
 import androidx.exifinterface.media.ExifInterface
@@ -74,6 +75,7 @@ import javax.inject.Inject
  * The transactionId is used as loc
  */
 internal class LocalEchoEventFactory @Inject constructor(
+        private val context: Context,
         @UserId private val userId: String,
         private val stringProvider: StringProvider,
         private val textPillsUtils: TextPillsUtils,
@@ -266,14 +268,14 @@ internal class LocalEchoEventFactory @Inject constructor(
                         height = height?.toInt() ?: 0,
                         size = attachment.size.toInt()
                 ),
-                url = attachment.path
+                url = attachment.queryUri.toString()
         )
         return createEvent(roomId, content)
     }
 
     private fun createVideoEvent(roomId: String, attachment: ContentAttachmentData): Event {
         val mediaDataRetriever = MediaMetadataRetriever()
-        mediaDataRetriever.setDataSource(attachment.path)
+        mediaDataRetriever.setDataSource(context, attachment.queryUri)
 
         // Use frame to calculate height and width as we are sure to get the right ones
         val firstFrame: Bitmap? = mediaDataRetriever.frameAtTime
@@ -281,7 +283,7 @@ internal class LocalEchoEventFactory @Inject constructor(
         val width = firstFrame?.width ?: 0
         mediaDataRetriever.release()
 
-        val thumbnailInfo = ThumbnailExtractor.extractThumbnail(attachment)?.let {
+        val thumbnailInfo = ThumbnailExtractor.extractThumbnail(context, attachment)?.let {
             ThumbnailInfo(
                     width = it.width,
                     height = it.height,
@@ -299,10 +301,10 @@ internal class LocalEchoEventFactory @Inject constructor(
                         size = attachment.size,
                         duration = attachment.duration?.toInt() ?: 0,
                         // Glide will be able to use the local path and extract a thumbnail.
-                        thumbnailUrl = attachment.path,
+                        thumbnailUrl = attachment.queryUri.toString(),
                         thumbnailInfo = thumbnailInfo
                 ),
-                url = attachment.path
+                url = attachment.queryUri.toString()
         )
         return createEvent(roomId, content)
     }
@@ -315,7 +317,7 @@ internal class LocalEchoEventFactory @Inject constructor(
                         mimeType = attachment.getSafeMimeType()?.takeIf { it.isNotBlank() } ?: "audio/mpeg",
                         size = attachment.size
                 ),
-                url = attachment.path
+                url = attachment.queryUri.toString()
         )
         return createEvent(roomId, content)
     }
@@ -329,7 +331,7 @@ internal class LocalEchoEventFactory @Inject constructor(
                                 ?: "application/octet-stream",
                         size = attachment.size
                 ),
-                url = attachment.path
+                url = attachment.queryUri.toString()
         )
         return createEvent(roomId, content)
     }
diff --git a/multipicker/src/main/java/im/vector/riotx/multipicker/AudioPicker.kt b/multipicker/src/main/java/im/vector/riotx/multipicker/AudioPicker.kt
index 8fb23ec49d..23873aae1c 100644
--- a/multipicker/src/main/java/im/vector/riotx/multipicker/AudioPicker.kt
+++ b/multipicker/src/main/java/im/vector/riotx/multipicker/AudioPicker.kt
@@ -54,6 +54,7 @@ class AudioPicker(override val requestCode: Int) : Picker<MultiPickerAudioType>(
             selectedUriList.add(dataUri)
         } else {
             data?.extras?.get(Intent.EXTRA_STREAM)?.let {
+                @Suppress("UNCHECKED_CAST")
                 when (it) {
                     is List<*> -> selectedUriList.addAll(it as List<Uri>)
                     else     -> selectedUriList.add(it as Uri)
diff --git a/multipicker/src/main/java/im/vector/riotx/multipicker/CameraPicker.kt b/multipicker/src/main/java/im/vector/riotx/multipicker/CameraPicker.kt
index 6962f2098a..81e665a43f 100644
--- a/multipicker/src/main/java/im/vector/riotx/multipicker/CameraPicker.kt
+++ b/multipicker/src/main/java/im/vector/riotx/multipicker/CameraPicker.kt
@@ -23,7 +23,6 @@ import android.graphics.BitmapFactory
 import android.graphics.ImageDecoder
 import android.net.Uri
 import android.os.Build
-import android.os.Environment
 import android.provider.MediaStore
 import androidx.core.content.FileProvider
 import androidx.exifinterface.media.ExifInterface
diff --git a/multipicker/src/main/java/im/vector/riotx/multipicker/FilePicker.kt b/multipicker/src/main/java/im/vector/riotx/multipicker/FilePicker.kt
index 9d3292c115..0e1169755e 100644
--- a/multipicker/src/main/java/im/vector/riotx/multipicker/FilePicker.kt
+++ b/multipicker/src/main/java/im/vector/riotx/multipicker/FilePicker.kt
@@ -53,6 +53,7 @@ class FilePicker(override val requestCode: Int) : Picker<MultiPickerFileType>(re
             selectedUriList.add(dataUri)
         } else {
             data?.extras?.get(Intent.EXTRA_STREAM)?.let {
+                @Suppress("UNCHECKED_CAST")
                 when (it) {
                     is List<*> -> selectedUriList.addAll(it as List<Uri>)
                     else     -> selectedUriList.add(it as Uri)
diff --git a/multipicker/src/main/java/im/vector/riotx/multipicker/ImagePicker.kt b/multipicker/src/main/java/im/vector/riotx/multipicker/ImagePicker.kt
index f33ceb816c..8bf589800d 100644
--- a/multipicker/src/main/java/im/vector/riotx/multipicker/ImagePicker.kt
+++ b/multipicker/src/main/java/im/vector/riotx/multipicker/ImagePicker.kt
@@ -57,6 +57,7 @@ class ImagePicker(override val requestCode: Int) : Picker<MultiPickerImageType>(
             selectedUriList.add(dataUri)
         } else {
             data?.extras?.get(Intent.EXTRA_STREAM)?.let {
+                @Suppress("UNCHECKED_CAST")
                 when (it) {
                     is List<*> -> selectedUriList.addAll(it as List<Uri>)
                     else     -> selectedUriList.add(it as Uri)
diff --git a/multipicker/src/main/java/im/vector/riotx/multipicker/MultiPickerFileProvider.kt b/multipicker/src/main/java/im/vector/riotx/multipicker/MultiPickerFileProvider.kt
index 832d721eef..1549b43fd7 100644
--- a/multipicker/src/main/java/im/vector/riotx/multipicker/MultiPickerFileProvider.kt
+++ b/multipicker/src/main/java/im/vector/riotx/multipicker/MultiPickerFileProvider.kt
@@ -18,5 +18,4 @@ package im.vector.riotx.multipicker
 
 import androidx.core.content.FileProvider
 
-class MultiPickerFileProvider : FileProvider() {
-}
+class MultiPickerFileProvider : FileProvider()
diff --git a/multipicker/src/main/java/im/vector/riotx/multipicker/VideoPicker.kt b/multipicker/src/main/java/im/vector/riotx/multipicker/VideoPicker.kt
index 92d1e9c240..d4b8d6a985 100644
--- a/multipicker/src/main/java/im/vector/riotx/multipicker/VideoPicker.kt
+++ b/multipicker/src/main/java/im/vector/riotx/multipicker/VideoPicker.kt
@@ -54,6 +54,7 @@ class VideoPicker(override val requestCode: Int) : Picker<MultiPickerVideoType>(
             selectedUriList.add(dataUri)
         } else {
             data?.extras?.get(Intent.EXTRA_STREAM)?.let {
+                @Suppress("UNCHECKED_CAST")
                 when (it) {
                     is List<*> -> selectedUriList.addAll(it as List<Uri>)
                     else     -> selectedUriList.add(it as Uri)
diff --git a/vector/build.gradle b/vector/build.gradle
index 447ad7a767..2887ebba46 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -348,9 +348,6 @@ dependencies {
     // Badge for compatibility
     implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
 
-    // File picker
-    implementation 'com.kbeanie:multipicker:1.6@aar'
-
     // DI
     implementation "com.google.dagger:dagger:$daggerVersion"
     kapt "com.google.dagger:dagger-compiler:$daggerVersion"
diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsHelper.kt b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsHelper.kt
index c576ebe1b9..daea538e12 100644
--- a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsHelper.kt
+++ b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsHelper.kt
@@ -18,20 +18,13 @@ package im.vector.riotx.features.attachments
 import android.app.Activity
 import android.content.Context
 import android.content.Intent
+import android.net.Uri
 import android.os.Bundle
 import androidx.fragment.app.Fragment
-import com.kbeanie.multipicker.api.Picker.PICK_AUDIO
-import com.kbeanie.multipicker.api.Picker.PICK_CONTACT
-import com.kbeanie.multipicker.api.Picker.PICK_FILE
-import com.kbeanie.multipicker.api.Picker.PICK_IMAGE_CAMERA
-import com.kbeanie.multipicker.api.Picker.PICK_IMAGE_DEVICE
-import com.kbeanie.multipicker.core.ImagePickerImpl
-import com.kbeanie.multipicker.core.PickerManager
-import com.kbeanie.multipicker.utils.IntentUtils
 import im.vector.matrix.android.BuildConfig
 import im.vector.matrix.android.api.session.content.ContentAttachmentData
 import im.vector.riotx.core.platform.Restorable
-import im.vector.riotx.features.attachments.AttachmentsHelper.Callback
+import im.vector.riotx.multipicker.MultiPicker
 import timber.log.Timber
 
 private const val CAPTURE_PATH_KEY = "CAPTURE_PATH_KEY"
@@ -39,20 +32,8 @@ private const val PENDING_TYPE_KEY = "PENDING_TYPE_KEY"
 
 /**
  * This class helps to handle attachments by providing simple methods.
- * The process is asynchronous and you must implement [Callback] methods to get the data or a failure.
  */
-class AttachmentsHelper private constructor(private val context: Context,
-                                            private val pickerManagerFactory: PickerManagerFactory) : Restorable {
-
-    companion object {
-        fun create(fragment: Fragment, callback: Callback): AttachmentsHelper {
-            return AttachmentsHelper(fragment.requireContext(), FragmentPickerManagerFactory(fragment, callback))
-        }
-
-        fun create(activity: Activity, callback: Callback): AttachmentsHelper {
-            return AttachmentsHelper(activity, ActivityPickerManagerFactory(activity, callback))
-        }
-    }
+class AttachmentsHelper(val context: Context, val callback: Callback) : Restorable {
 
     interface Callback {
         fun onContactAttachmentReady(contactAttachment: ContactAttachment) {
@@ -66,39 +47,15 @@ class AttachmentsHelper private constructor(private val context: Context,
     }
 
     // Capture path allows to handle camera image picking. It must be restored if the activity gets killed.
-    private var capturePath: String? = null
+    private var captureUri: Uri? = null
     // The pending type is set if we have to handle permission request. It must be restored if the activity gets killed.
     var pendingType: AttachmentTypeSelectorView.Type? = null
 
-    private val imagePicker by lazy {
-        pickerManagerFactory.createImagePicker()
-    }
-
-    private val videoPicker by lazy {
-        pickerManagerFactory.createVideoPicker()
-    }
-
-    private val cameraImagePicker by lazy {
-        pickerManagerFactory.createCameraImagePicker()
-    }
-
-    private val filePicker by lazy {
-        pickerManagerFactory.createFilePicker()
-    }
-
-    private val audioPicker by lazy {
-        pickerManagerFactory.createAudioPicker()
-    }
-
-    private val contactPicker by lazy {
-        pickerManagerFactory.createContactPicker()
-    }
-
     // Restorable
 
     override fun onSaveInstanceState(outState: Bundle) {
-        capturePath?.also {
-            outState.putString(CAPTURE_PATH_KEY, it)
+        captureUri?.also {
+            outState.putParcelable(CAPTURE_PATH_KEY, it)
         }
         pendingType?.also {
             outState.putSerializable(PENDING_TYPE_KEY, it)
@@ -106,10 +63,7 @@ class AttachmentsHelper private constructor(private val context: Context,
     }
 
     override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
-        capturePath = savedInstanceState?.getString(CAPTURE_PATH_KEY)
-        if (capturePath != null) {
-            cameraImagePicker.reinitialize(capturePath)
-        }
+        captureUri = savedInstanceState?.getParcelable(CAPTURE_PATH_KEY) as? Uri
         pendingType = savedInstanceState?.getSerializable(PENDING_TYPE_KEY) as? AttachmentTypeSelectorView.Type
     }
 
@@ -118,36 +72,36 @@ class AttachmentsHelper private constructor(private val context: Context,
     /**
      * Starts the process for handling file picking
      */
-    fun selectFile() {
-        filePicker.pickFile()
+    fun selectFile(fragment: Fragment) {
+        MultiPicker.get(MultiPicker.FILE).startWith(fragment)
     }
 
     /**
      * Starts the process for handling image picking
      */
-    fun selectGallery() {
-        imagePicker.pickImage()
+    fun selectGallery(fragment: Fragment) {
+        MultiPicker.get(MultiPicker.IMAGE).startWith(fragment)
     }
 
     /**
      * Starts the process for handling audio picking
      */
-    fun selectAudio() {
-        audioPicker.pickAudio()
+    fun selectAudio(fragment: Fragment) {
+        MultiPicker.get(MultiPicker.AUDIO).startWith(fragment)
     }
 
     /**
      * Starts the process for handling capture image picking
      */
-    fun openCamera() {
-        capturePath = cameraImagePicker.pickImage()
+    fun openCamera(fragment: Fragment) {
+        captureUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(fragment)
     }
 
     /**
      * Starts the process for handling contact picking
      */
-    fun selectContact() {
-        contactPicker.pickContact()
+    fun selectContact(fragment: Fragment) {
+        MultiPicker.get(MultiPicker.CONTACT).startWith(fragment)
     }
 
     /**
@@ -157,14 +111,58 @@ class AttachmentsHelper private constructor(private val context: Context,
      */
     fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
         if (resultCode == Activity.RESULT_OK) {
-            val pickerManager = getPickerManagerForRequestCode(requestCode)
-            if (pickerManager != null) {
-                if (pickerManager is ImagePickerImpl) {
-                    pickerManager.reinitialize(capturePath)
+            when (requestCode) {
+                MultiPicker.REQUEST_CODE_PICK_FILE    -> {
+                    callback.onContentAttachmentsReady(
+                            MultiPicker.get(MultiPicker.FILE)
+                                    .getSelectedFiles(context, requestCode, resultCode, data)
+                                    .map { it.toContentAttachmentData() }
+                    )
                 }
-                pickerManager.submit(data)
-                return true
+                MultiPicker.REQUEST_CODE_PICK_AUDIO   -> {
+                    callback.onContentAttachmentsReady(
+                            MultiPicker.get(MultiPicker.AUDIO)
+                                    .getSelectedFiles(context, requestCode, resultCode, data)
+                                    .map { it.toContentAttachmentData() }
+                    )
+                }
+                MultiPicker.REQUEST_CODE_PICK_CONTACT -> {
+                    MultiPicker.get(MultiPicker.CONTACT)
+                            .getSelectedFiles(context, requestCode, resultCode, data)
+                            .firstOrNull()
+                            ?.toContactAttachment()
+                            ?.let {
+                                callback.onContactAttachmentReady(it)
+                            }
+                }
+                MultiPicker.REQUEST_CODE_PICK_IMAGE   -> {
+                    callback.onContentAttachmentsReady(
+                            MultiPicker.get(MultiPicker.IMAGE)
+                                    .getSelectedFiles(context, requestCode, resultCode, data)
+                                    .map { it.toContentAttachmentData() }
+                    )
+                }
+                MultiPicker.REQUEST_CODE_TAKE_PHOTO   -> {
+                    captureUri?.let { captureUri ->
+                        MultiPicker.get(MultiPicker.CAMERA)
+                                .getTakenPhoto(context, requestCode, resultCode, captureUri)
+                                ?.let {
+                                    callback.onContentAttachmentsReady(
+                                            listOf(it).map { it.toContentAttachmentData() }
+                                    )
+                                }
+                    }
+                }
+                MultiPicker.REQUEST_CODE_PICK_VIDEO   -> {
+                    callback.onContentAttachmentsReady(
+                            MultiPicker.get(MultiPicker.VIDEO)
+                                    .getSelectedFiles(context, requestCode, resultCode, data)
+                                    .map { it.toContentAttachmentData() }
+                    )
+                }
+                else                                  -> return false
             }
+            return true
         }
         return false
     }
@@ -174,39 +172,35 @@ class AttachmentsHelper private constructor(private val context: Context,
      *
      * @return true if it can handle the intent data, false otherwise
      */
-    fun handleShareIntent(intent: Intent): Boolean {
+    fun handleShareIntent(context: Context, intent: Intent): Boolean {
         val type = intent.resolveType(context) ?: return false
         if (type.startsWith("image")) {
-            imagePicker.submit(safeShareIntent(intent))
+            callback.onContentAttachmentsReady(
+                    MultiPicker.get(MultiPicker.IMAGE).getIncomingFiles(context, intent).map {
+                        it.toContentAttachmentData()
+                    }
+            )
         } else if (type.startsWith("video")) {
-            videoPicker.submit(safeShareIntent(intent))
+            callback.onContentAttachmentsReady(
+                    MultiPicker.get(MultiPicker.VIDEO).getIncomingFiles(context, intent).map {
+                        it.toContentAttachmentData()
+                    }
+            )
         } else if (type.startsWith("audio")) {
-            videoPicker.submit(safeShareIntent(intent))
+            callback.onContentAttachmentsReady(
+                    MultiPicker.get(MultiPicker.AUDIO).getIncomingFiles(context, intent).map {
+                        it.toContentAttachmentData()
+                    }
+            )
         } else if (type.startsWith("application") || type.startsWith("file") || type.startsWith("*")) {
-            filePicker.submit(safeShareIntent(intent))
+            callback.onContentAttachmentsReady(
+                    MultiPicker.get(MultiPicker.FILE).getIncomingFiles(context, intent).map {
+                        it.toContentAttachmentData()
+                    }
+            )
         } else {
             return false
         }
         return true
     }
-
-    private fun safeShareIntent(intent: Intent): Intent {
-        // Work around for getPickerIntentForSharing doing NPE in android 10
-        return try {
-            IntentUtils.getPickerIntentForSharing(intent)
-        } catch (failure: Throwable) {
-            intent
-        }
-    }
-
-    private fun getPickerManagerForRequestCode(requestCode: Int): PickerManager? {
-        return when (requestCode) {
-            PICK_IMAGE_DEVICE -> imagePicker
-            PICK_IMAGE_CAMERA -> cameraImagePicker
-            PICK_FILE         -> filePicker
-            PICK_CONTACT      -> contactPicker
-            PICK_AUDIO        -> audioPicker
-            else              -> null
-        }
-    }
 }
diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsMapper.kt b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsMapper.kt
index a3de5084de..02b712b8a7 100644
--- a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsMapper.kt
+++ b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsMapper.kt
@@ -16,51 +16,48 @@
 
 package im.vector.riotx.features.attachments
 
-import com.kbeanie.multipicker.api.entity.ChosenAudio
-import com.kbeanie.multipicker.api.entity.ChosenContact
-import com.kbeanie.multipicker.api.entity.ChosenFile
-import com.kbeanie.multipicker.api.entity.ChosenImage
-import com.kbeanie.multipicker.api.entity.ChosenVideo
 import im.vector.matrix.android.api.session.content.ContentAttachmentData
+import im.vector.riotx.multipicker.entity.MultiPickerAudioType
+import im.vector.riotx.multipicker.entity.MultiPickerBaseType
+import im.vector.riotx.multipicker.entity.MultiPickerContactType
+import im.vector.riotx.multipicker.entity.MultiPickerFileType
+import im.vector.riotx.multipicker.entity.MultiPickerImageType
+import im.vector.riotx.multipicker.entity.MultiPickerVideoType
 import timber.log.Timber
 
-fun ChosenContact.toContactAttachment(): ContactAttachment {
+fun MultiPickerContactType.toContactAttachment(): ContactAttachment {
     return ContactAttachment(
             displayName = displayName,
             photoUri = photoUri,
-            emails = emails.toList(),
-            phones = phones.toList()
+            emails = emailList.toList(),
+            phones = phoneNumberList.toList()
     )
 }
 
-fun ChosenFile.toContentAttachmentData(): ContentAttachmentData {
+fun MultiPickerFileType.toContentAttachmentData(): ContentAttachmentData {
     if (mimeType == null) Timber.w("No mimeType")
     return ContentAttachmentData(
-            path = originalPath,
             mimeType = mimeType,
             type = mapType(),
             size = size,
-            date = createdAt?.time ?: System.currentTimeMillis(),
             name = displayName,
-            queryUri = queryUri
+            queryUri = contentUri
     )
 }
 
-fun ChosenAudio.toContentAttachmentData(): ContentAttachmentData {
+fun MultiPickerAudioType.toContentAttachmentData(): ContentAttachmentData {
     if (mimeType == null) Timber.w("No mimeType")
     return ContentAttachmentData(
-            path = originalPath,
             mimeType = mimeType,
             type = mapType(),
             size = size,
-            date = createdAt?.time ?: System.currentTimeMillis(),
             name = displayName,
             duration = duration,
-            queryUri = queryUri
+            queryUri = contentUri
     )
 }
 
-private fun ChosenFile.mapType(): ContentAttachmentData.Type {
+private fun MultiPickerBaseType.mapType(): ContentAttachmentData.Type {
     return when {
         mimeType?.startsWith("image/") == true -> ContentAttachmentData.Type.IMAGE
         mimeType?.startsWith("video/") == true -> ContentAttachmentData.Type.VIDEO
@@ -69,10 +66,9 @@ private fun ChosenFile.mapType(): ContentAttachmentData.Type {
     }
 }
 
-fun ChosenImage.toContentAttachmentData(): ContentAttachmentData {
+fun MultiPickerImageType.toContentAttachmentData(): ContentAttachmentData {
     if (mimeType == null) Timber.w("No mimeType")
     return ContentAttachmentData(
-            path = originalPath,
             mimeType = mimeType,
             type = mapType(),
             name = displayName,
@@ -80,23 +76,20 @@ fun ChosenImage.toContentAttachmentData(): ContentAttachmentData {
             height = height.toLong(),
             width = width.toLong(),
             exifOrientation = orientation,
-            date = createdAt?.time ?: System.currentTimeMillis(),
-            queryUri = queryUri
+            queryUri = contentUri
     )
 }
 
-fun ChosenVideo.toContentAttachmentData(): ContentAttachmentData {
+fun MultiPickerVideoType.toContentAttachmentData(): ContentAttachmentData {
     if (mimeType == null) Timber.w("No mimeType")
     return ContentAttachmentData(
-            path = originalPath,
             mimeType = mimeType,
             type = ContentAttachmentData.Type.VIDEO,
             size = size,
-            date = createdAt?.time ?: System.currentTimeMillis(),
             height = height.toLong(),
             width = width.toLong(),
             duration = duration,
             name = displayName,
-            queryUri = queryUri
+            queryUri = contentUri
     )
 }
diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsPickerCallback.kt b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsPickerCallback.kt
deleted file mode 100644
index 62956e08c8..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsPickerCallback.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.riotx.features.attachments
-
-import com.kbeanie.multipicker.api.callbacks.AudioPickerCallback
-import com.kbeanie.multipicker.api.callbacks.ContactPickerCallback
-import com.kbeanie.multipicker.api.callbacks.FilePickerCallback
-import com.kbeanie.multipicker.api.callbacks.ImagePickerCallback
-import com.kbeanie.multipicker.api.callbacks.VideoPickerCallback
-import com.kbeanie.multipicker.api.entity.ChosenAudio
-import com.kbeanie.multipicker.api.entity.ChosenContact
-import com.kbeanie.multipicker.api.entity.ChosenFile
-import com.kbeanie.multipicker.api.entity.ChosenImage
-import com.kbeanie.multipicker.api.entity.ChosenVideo
-
-/**
- * This class delegates the PickerManager callbacks to an [AttachmentsHelper.Callback]
- */
-class AttachmentsPickerCallback(private val callback: AttachmentsHelper.Callback)
-    : ImagePickerCallback,
-        FilePickerCallback,
-        VideoPickerCallback,
-        AudioPickerCallback,
-        ContactPickerCallback {
-
-    override fun onContactChosen(contact: ChosenContact?) {
-        if (contact == null) {
-            callback.onAttachmentsProcessFailed()
-        } else {
-            val contactAttachment = contact.toContactAttachment()
-            callback.onContactAttachmentReady(contactAttachment)
-        }
-    }
-
-    override fun onAudiosChosen(audios: MutableList<ChosenAudio>?) {
-        if (audios.isNullOrEmpty()) {
-            callback.onAttachmentsProcessFailed()
-        } else {
-            val attachments = audios.map {
-                it.toContentAttachmentData()
-            }
-            callback.onContentAttachmentsReady(attachments)
-        }
-    }
-
-    override fun onFilesChosen(files: MutableList<ChosenFile>?) {
-        if (files.isNullOrEmpty()) {
-            callback.onAttachmentsProcessFailed()
-        } else {
-            val attachments = files.map {
-                it.toContentAttachmentData()
-            }
-            callback.onContentAttachmentsReady(attachments)
-        }
-    }
-
-    override fun onImagesChosen(images: MutableList<ChosenImage>?) {
-        if (images.isNullOrEmpty()) {
-            callback.onAttachmentsProcessFailed()
-        } else {
-            val attachments = images.map {
-                it.toContentAttachmentData()
-            }
-            callback.onContentAttachmentsReady(attachments)
-        }
-    }
-
-    override fun onVideosChosen(videos: MutableList<ChosenVideo>?) {
-        if (videos.isNullOrEmpty()) {
-            callback.onAttachmentsProcessFailed()
-        } else {
-            val attachments = videos.map {
-                it.toContentAttachmentData()
-            }
-            callback.onContentAttachmentsReady(attachments)
-        }
-    }
-
-    override fun onError(error: String?) {
-        callback.onAttachmentsProcessFailed()
-    }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/PickerManagerFactory.kt b/vector/src/main/java/im/vector/riotx/features/attachments/PickerManagerFactory.kt
deleted file mode 100644
index 6c03f21ab3..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/attachments/PickerManagerFactory.kt
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.riotx.features.attachments
-
-import android.app.Activity
-import androidx.fragment.app.Fragment
-import com.kbeanie.multipicker.api.AudioPicker
-import com.kbeanie.multipicker.api.CameraImagePicker
-import com.kbeanie.multipicker.api.ContactPicker
-import com.kbeanie.multipicker.api.FilePicker
-import com.kbeanie.multipicker.api.ImagePicker
-import com.kbeanie.multipicker.api.VideoPicker
-
-/**
- * Factory for creating different pickers. It allows to use with fragment or activity builders.
- */
-interface PickerManagerFactory {
-
-    fun createImagePicker(): ImagePicker
-
-    fun createCameraImagePicker(): CameraImagePicker
-
-    fun createVideoPicker(): VideoPicker
-
-    fun createFilePicker(): FilePicker
-
-    fun createAudioPicker(): AudioPicker
-
-    fun createContactPicker(): ContactPicker
-}
-
-class ActivityPickerManagerFactory(private val activity: Activity, callback: AttachmentsHelper.Callback) : PickerManagerFactory {
-
-    private val attachmentsPickerCallback = AttachmentsPickerCallback(callback)
-
-    override fun createImagePicker(): ImagePicker {
-        return ImagePicker(activity).also {
-            it.setImagePickerCallback(attachmentsPickerCallback)
-            it.allowMultiple()
-        }
-    }
-
-    override fun createCameraImagePicker(): CameraImagePicker {
-        return CameraImagePicker(activity).also {
-            it.setImagePickerCallback(attachmentsPickerCallback)
-        }
-    }
-
-    override fun createVideoPicker(): VideoPicker {
-        return VideoPicker(activity).also {
-            it.setVideoPickerCallback(attachmentsPickerCallback)
-            it.allowMultiple()
-        }
-    }
-
-    override fun createFilePicker(): FilePicker {
-        return FilePicker(activity).also {
-            it.allowMultiple()
-            it.setFilePickerCallback(attachmentsPickerCallback)
-        }
-    }
-
-    override fun createAudioPicker(): AudioPicker {
-        return AudioPicker(activity).also {
-            it.allowMultiple()
-            it.setAudioPickerCallback(attachmentsPickerCallback)
-        }
-    }
-
-    override fun createContactPicker(): ContactPicker {
-        return ContactPicker(activity).also {
-            it.setContactPickerCallback(attachmentsPickerCallback)
-        }
-    }
-}
-
-class FragmentPickerManagerFactory(private val fragment: Fragment, callback: AttachmentsHelper.Callback) : PickerManagerFactory {
-
-    private val attachmentsPickerCallback = AttachmentsPickerCallback(callback)
-
-    override fun createImagePicker(): ImagePicker {
-        return ImagePicker(fragment).also {
-            it.setImagePickerCallback(attachmentsPickerCallback)
-            it.allowMultiple()
-        }
-    }
-
-    override fun createCameraImagePicker(): CameraImagePicker {
-        return CameraImagePicker(fragment).also {
-            it.setImagePickerCallback(attachmentsPickerCallback)
-        }
-    }
-
-    override fun createVideoPicker(): VideoPicker {
-        return VideoPicker(fragment).also {
-            it.setVideoPickerCallback(attachmentsPickerCallback)
-            it.allowMultiple()
-        }
-    }
-
-    override fun createFilePicker(): FilePicker {
-        return FilePicker(fragment).also {
-            it.allowMultiple()
-            it.setFilePickerCallback(attachmentsPickerCallback)
-        }
-    }
-
-    override fun createAudioPicker(): AudioPicker {
-        return AudioPicker(fragment).also {
-            it.allowMultiple()
-            it.setAudioPickerCallback(attachmentsPickerCallback)
-        }
-    }
-
-    override fun createContactPicker(): ContactPicker {
-        return ContactPicker(fragment).also {
-            it.setContactPickerCallback(attachmentsPickerCallback)
-        }
-    }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentPreviewControllers.kt b/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentPreviewControllers.kt
index 34f018aaf9..60ee722116 100644
--- a/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentPreviewControllers.kt
+++ b/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentPreviewControllers.kt
@@ -25,7 +25,7 @@ class AttachmentBigPreviewController @Inject constructor() : TypedEpoxyControlle
     override fun buildModels(data: AttachmentsPreviewViewState) {
         data.attachments.forEach {
             attachmentBigPreviewItem {
-                id(it.path)
+                id(it.queryUri.toString())
                 attachment(it)
             }
         }
@@ -43,7 +43,7 @@ class AttachmentMiniaturePreviewController @Inject constructor() : TypedEpoxyCon
     override fun buildModels(data: AttachmentsPreviewViewState) {
         data.attachments.forEachIndexed { index, contentAttachmentData ->
             attachmentMiniaturePreviewItem {
-                id(contentAttachmentData.path)
+                id(contentAttachmentData.queryUri.toString())
                 attachment(contentAttachmentData)
                 checked(data.currentAttachmentIndex == index)
                 clickListener { _ ->
diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentPreviewItems.kt b/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentPreviewItems.kt
index 3b43fa6e20..373298bf31 100644
--- a/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentPreviewItems.kt
+++ b/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentPreviewItems.kt
@@ -33,11 +33,10 @@ abstract class AttachmentPreviewItem<H : AttachmentPreviewItem.Holder> : VectorE
     abstract val attachment: ContentAttachmentData
 
     override fun bind(holder: H) {
-        val path = attachment.path
         if (attachment.type == ContentAttachmentData.Type.VIDEO || attachment.type == ContentAttachmentData.Type.IMAGE) {
             Glide.with(holder.view.context)
                     .asBitmap()
-                    .load(path)
+                    .load(attachment.queryUri)
                     .apply(RequestOptions().frame(0))
                     .into(holder.imageView)
         } else {
diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewAction.kt b/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewAction.kt
index 5acc59b035..aef724331f 100644
--- a/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewAction.kt
+++ b/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewAction.kt
@@ -17,10 +17,11 @@
 
 package im.vector.riotx.features.attachments.preview
 
+import android.net.Uri
 import im.vector.riotx.core.platform.VectorViewModelAction
 
 sealed class AttachmentsPreviewAction : VectorViewModelAction {
     object RemoveCurrentAttachment : AttachmentsPreviewAction()
     data class SetCurrentAttachment(val index: Int): AttachmentsPreviewAction()
-    data class UpdatePathOfCurrentAttachment(val newPath: String): AttachmentsPreviewAction()
+    data class UpdatePathOfCurrentAttachment(val newUri: Uri): AttachmentsPreviewAction()
 }
diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewFragment.kt b/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewFragment.kt
index e52b497df4..f059da7d85 100644
--- a/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewFragment.kt
@@ -172,9 +172,9 @@ class AttachmentsPreviewFragment @Inject constructor(
     }
 
     private fun handleCropResult(result: Intent) {
-        val resultPath = UCrop.getOutput(result)?.path
-        if (resultPath != null) {
-            viewModel.handle(AttachmentsPreviewAction.UpdatePathOfCurrentAttachment(resultPath))
+        val resultUri = UCrop.getOutput(result)
+        if (resultUri != null) {
+            viewModel.handle(AttachmentsPreviewAction.UpdatePathOfCurrentAttachment(resultUri))
         } else {
             Toast.makeText(requireContext(), "Cannot retrieve cropped value", Toast.LENGTH_SHORT).show()
         }
@@ -203,7 +203,7 @@ class AttachmentsPreviewFragment @Inject constructor(
         val currentAttachment = it.attachments.getOrNull(it.currentAttachmentIndex) ?: return@withState
         val destinationFile = File(requireContext().cacheDir, "${currentAttachment.name}_edited_image_${System.currentTimeMillis()}")
         // Note: using currentAttachment.queryUri.toUri() make the app crash when sharing from Google Photos
-        val uri = File(currentAttachment.path).toUri()
+        val uri = currentAttachment.queryUri
         UCrop.of(uri, destinationFile.toUri())
                 .withOptions(
                         UCrop.Options()
diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewViewModel.kt b/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewViewModel.kt
index 1f6c8c2f8b..d1e44fa963 100644
--- a/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/attachments/preview/AttachmentsPreviewViewModel.kt
@@ -62,7 +62,7 @@ class AttachmentsPreviewViewModel @AssistedInject constructor(@Assisted initialS
     private fun handleUpdatePathOfCurrentAttachment(action: AttachmentsPreviewAction.UpdatePathOfCurrentAttachment) = withState {
         val attachments = it.attachments.mapIndexed { index, contentAttachmentData ->
             if (index == it.currentAttachmentIndex) {
-                contentAttachmentData.copy(path = action.newPath)
+                contentAttachmentData.copy(queryUri = action.newUri)
             } else {
                 contentAttachmentData
             }
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
index 13de137e8f..779b7fb089 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
@@ -251,7 +251,7 @@ class RoomDetailFragment @Inject constructor(
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
-        attachmentsHelper = AttachmentsHelper.create(this, this).register()
+        attachmentsHelper = AttachmentsHelper(requireContext(), this).register()
         keyboardStateUtils = KeyboardStateUtils(requireActivity())
         setupToolbar(roomToolbar)
         setupRecyclerView()
@@ -517,29 +517,6 @@ class RoomDetailFragment @Inject constructor(
     }
 
     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
-        when (requestCode) {
-            MultiPicker.REQUEST_CODE_PICK_IMAGE -> {
-                MultiPicker.get(MultiPicker.IMAGE).getSelectedFiles(requireContext(), requestCode, resultCode, data)
-            }
-            MultiPicker.REQUEST_CODE_PICK_VIDEO -> {
-                MultiPicker.get(MultiPicker.VIDEO).getSelectedFiles(requireContext(), requestCode, resultCode, data)
-            }
-            MultiPicker.REQUEST_CODE_PICK_FILE  -> {
-                MultiPicker.get(MultiPicker.FILE).getSelectedFiles(requireContext(), requestCode, resultCode, data)
-            }
-            MultiPicker.REQUEST_CODE_PICK_AUDIO  -> {
-                MultiPicker.get(MultiPicker.AUDIO).getSelectedFiles(requireContext(), requestCode, resultCode, data)
-            }
-            MultiPicker.REQUEST_CODE_PICK_CONTACT  -> {
-                MultiPicker.get(MultiPicker.CONTACT).getSelectedFiles(requireContext(), requestCode, resultCode, data)
-            }
-            MultiPicker.REQUEST_CODE_TAKE_PHOTO  -> {
-                cameraPhotoUri?.let {
-                    MultiPicker.get(MultiPicker.CAMERA).getTakenPhoto(requireContext(), requestCode, resultCode, it)
-                }
-            }
-        }
-
         val hasBeenHandled = attachmentsHelper.onActivityResult(requestCode, resultCode, data)
         if (!hasBeenHandled && resultCode == RESULT_OK && data != null) {
             when (requestCode) {
@@ -689,7 +666,7 @@ class RoomDetailFragment @Inject constructor(
     private fun sendUri(uri: Uri): Boolean {
         roomDetailViewModel.preventAttachmentPreview = true
         val shareIntent = Intent(Intent.ACTION_SEND, uri)
-        val isHandled = attachmentsHelper.handleShareIntent(shareIntent)
+        val isHandled = attachmentsHelper.handleShareIntent(requireContext(), shareIntent)
         if (!isHandled) {
             roomDetailViewModel.preventAttachmentPreview = false
             Toast.makeText(requireContext(), R.string.error_handling_incoming_share, Toast.LENGTH_SHORT).show()
@@ -1372,16 +1349,13 @@ class RoomDetailFragment @Inject constructor(
         }
     }
 
-    private var cameraPhotoUri: Uri? = null
     private fun launchAttachmentProcess(type: AttachmentTypeSelectorView.Type) {
         when (type) {
-            AttachmentTypeSelectorView.Type.CAMERA  -> {
-                cameraPhotoUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(this)
-            }
-            AttachmentTypeSelectorView.Type.FILE    -> MultiPicker.get(MultiPicker.FILE).startWith(this)
-            AttachmentTypeSelectorView.Type.GALLERY -> MultiPicker.get(MultiPicker.IMAGE).startWith(this)
-            AttachmentTypeSelectorView.Type.AUDIO   -> MultiPicker.get(MultiPicker.AUDIO).startWith(this)
-            AttachmentTypeSelectorView.Type.CONTACT -> MultiPicker.get(MultiPicker.CONTACT).startWith(this)
+            AttachmentTypeSelectorView.Type.CAMERA  -> attachmentsHelper.openCamera(this)
+            AttachmentTypeSelectorView.Type.FILE    -> attachmentsHelper.selectFile(this)
+            AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(this)
+            AttachmentTypeSelectorView.Type.AUDIO   -> attachmentsHelper.selectAudio(this)
+            AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(this)
             AttachmentTypeSelectorView.Type.STICKER -> vectorBaseActivity.notImplemented("Adding stickers")
         }.exhaustive
     }
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt
index 2ad90f073a..cef172da73 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt
@@ -610,7 +610,7 @@ class RoomDetailViewModel @AssistedInject constructor(
             when (val tooBigFile = attachments.find { it.size > maxUploadFileSize }) {
                 null -> room.sendMedias(attachments, action.compressBeforeSending, emptySet())
                 else -> _viewEvents.post(RoomDetailViewEvents.FileTooBigError(
-                        tooBigFile.name ?: tooBigFile.path,
+                        tooBigFile.name ?: tooBigFile.queryUri.toString(),
                         tooBigFile.size,
                         maxUploadFileSize
                 ))
diff --git a/vector/src/main/java/im/vector/riotx/features/share/IncomingShareFragment.kt b/vector/src/main/java/im/vector/riotx/features/share/IncomingShareFragment.kt
index 74821ab2fe..aa665b5653 100644
--- a/vector/src/main/java/im/vector/riotx/features/share/IncomingShareFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/share/IncomingShareFragment.kt
@@ -72,18 +72,18 @@ class IncomingShareFragment @Inject constructor(
         super.onViewCreated(view, savedInstanceState)
         setupRecyclerView()
         setupToolbar(incomingShareToolbar)
-        attachmentsHelper = AttachmentsHelper.create(this, this).register()
+        attachmentsHelper = AttachmentsHelper(requireContext(), this).register()
 
         val intent = vectorBaseActivity.intent
         val isShareManaged = when (intent?.action) {
             Intent.ACTION_SEND          -> {
-                var isShareManaged = attachmentsHelper.handleShareIntent(intent)
+                var isShareManaged = attachmentsHelper.handleShareIntent(requireContext(), intent)
                 if (!isShareManaged) {
                     isShareManaged = handleTextShare(intent)
                 }
                 isShareManaged
             }
-            Intent.ACTION_SEND_MULTIPLE -> attachmentsHelper.handleShareIntent(intent)
+            Intent.ACTION_SEND_MULTIPLE -> attachmentsHelper.handleShareIntent(requireContext(), intent)
             else                        -> false
         }