From 164c8dab0943905574b5847a5e4b3348324ab5f7 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 28 Jun 2019 19:31:32 +0200 Subject: [PATCH] Glide: try to handle encrypted image. [WIP] --- .../attachments/MXEncryptedAttachments.kt | 9 --- .../core/glide/VectorGlideModelLoader.kt | 75 ++++++++++++++----- .../features/media/ImageContentRenderer.kt | 21 +----- 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt index 9c98d58c76..033ce1f002 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt @@ -166,15 +166,6 @@ object MXEncryptedAttachments { return null } - // detect if there is no data to decrypt - try { - if (0 == attachmentStream.available()) { - return ByteArrayInputStream(ByteArray(0)) - } - } catch (e: Exception) { - Timber.e(e, "Fail to retrieve the file size") - } - val t0 = System.currentTimeMillis() val outStream = ByteArrayOutputStream() diff --git a/vector/src/main/java/im/vector/riotredesign/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/riotredesign/core/glide/VectorGlideModelLoader.kt index 8556739deb..844309caf0 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/glide/VectorGlideModelLoader.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/glide/VectorGlideModelLoader.kt @@ -24,14 +24,22 @@ import com.bumptech.glide.load.model.ModelLoader import com.bumptech.glide.load.model.ModelLoaderFactory import com.bumptech.glide.load.model.MultiModelLoaderFactory import com.bumptech.glide.signature.ObjectKey -import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt +import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.internal.crypto.attachments.MXEncryptedAttachments +import im.vector.riotredesign.features.media.ImageContentRenderer +import okhttp3.OkHttpClient +import okhttp3.Request +import timber.log.Timber +import java.io.File +import java.io.FileInputStream +import java.io.IOException import java.io.InputStream import com.bumptech.glide.load.engine.Resource as Resource1 -class VectorGlideModelLoaderFactory : ModelLoaderFactory { - override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { +class VectorGlideModelLoaderFactory : ModelLoaderFactory { + + override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { return VectorGlideModelLoader() } @@ -41,25 +49,31 @@ class VectorGlideModelLoaderFactory : ModelLoaderFactory { - override fun handles(model: InputStream): Boolean { +class VectorGlideModelLoader : ModelLoader { + override fun handles(model: ImageContentRenderer.Data): Boolean { // Always handle return true } - override fun buildLoadData(model: InputStream, width: Int, height: Int, options: Options): ModelLoader.LoadData? { - return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(model, options.get(ELEMENT_TO_DECRYPT))) + override fun buildLoadData(model: ImageContentRenderer.Data, width: Int, height: Int, options: Options): ModelLoader.LoadData? { + return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(model, width, height)) } } -class VectorGlideDataFetcher(private val inputStream: InputStream, - private val elementToDecrypt: ElementToDecrypt?) : DataFetcher { +class VectorGlideDataFetcher(private val data: ImageContentRenderer.Data, + private val width: Int, + private val height: Int) : DataFetcher { + + val client = OkHttpClient() + override fun getDataClass(): Class { return InputStream::class.java } + private var stream: InputStream? = null + override fun cleanup() { - // ? + cancel() } override fun getDataSource(): DataSource { @@ -68,16 +82,43 @@ class VectorGlideDataFetcher(private val inputStream: InputStream, } override fun cancel() { - // ? + if (stream != null) { + try { + stream?.close() // interrupts decode if any + stream = null + } catch (ignore: IOException) { + Timber.e(ignore) + } + } } override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { - if (elementToDecrypt?.k?.isNotBlank() == true) { - // Encrypted stream - callback.onDataReady(MXEncryptedAttachments.decryptAttachment(inputStream, elementToDecrypt)) - } else { - // Not encrypted stream - callback.onDataReady(inputStream) + Timber.v("Load data: $data") + if (data.isLocalFile()) { + val initialFile = File(data.url) + callback.onDataReady(FileInputStream(initialFile)) + return } + val contentUrlResolver = Matrix.getInstance().currentSession?.contentUrlResolver() ?: return + val url = contentUrlResolver.resolveFullSize(data.url) + ?: return + + val request = Request.Builder() + .url(url) + .build() + + val response = client.newCall(request).execute() + val inputStream = response.body()?.byteStream() + Timber.v("Response size ${response.body()?.contentLength()} - Stream available: ${inputStream?.available()}") + if (!response.isSuccessful) { + callback.onLoadFailed(IOException("Unexpected code $response")) + return + } + stream = if (data.elementToDecrypt != null && data.elementToDecrypt.k.isNotBlank()) { + MXEncryptedAttachments.decryptAttachment(inputStream, data.elementToDecrypt) + } else { + inputStream + } + callback.onDataReady(stream) } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/media/ImageContentRenderer.kt b/vector/src/main/java/im/vector/riotredesign/features/media/ImageContentRenderer.kt index 5fcb443bbd..e12ad7152f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/media/ImageContentRenderer.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/media/ImageContentRenderer.kt @@ -20,13 +20,11 @@ import android.net.Uri import android.os.Parcelable import android.widget.ImageView import androidx.exifinterface.media.ExifInterface -import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.github.piasy.biv.view.BigImageView import im.vector.matrix.android.api.session.content.ContentUrlResolver import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt import im.vector.riotredesign.core.di.ActiveSessionHolder -import im.vector.riotredesign.core.glide.ELEMENT_TO_DECRYPT import im.vector.riotredesign.core.glide.GlideApp import im.vector.riotredesign.core.utils.DimensionUtils.dpToPx import kotlinx.android.parcel.Parcelize @@ -62,26 +60,9 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder: val (width, height) = processSize(data, mode) imageView.layoutParams.height = height imageView.layoutParams.width = width - val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() - val resolvedUrl = when (mode) { - Mode.FULL_SIZE -> contentUrlResolver.resolveFullSize(data.url) - Mode.THUMBNAIL -> contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE) - } - //Fallback to base url - ?: data.url - GlideApp .with(imageView) - .load(resolvedUrl) - .apply { - // Give element to decrypt to Glide - if (data.elementToDecrypt != null) { - set(ELEMENT_TO_DECRYPT, data.elementToDecrypt) - // And disable cache - .skipMemoryCache(true) - .diskCacheStrategy(DiskCacheStrategy.NONE) - } - } + .load(data) .dontAnimate() .transform(RoundedCorners(dpToPx(8, imageView.context))) .thumbnail(0.3f)