BayernMessenger/vector/src/main/java/im/vector/riotx/core/glide/VectorGlideModelLoader.kt

128 lines
4.4 KiB
Kotlin

/*
* 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.core.glide
import com.bumptech.glide.Priority
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.data.DataFetcher
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.MXEncryptedAttachments
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.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(private val activeSessionHolder: ActiveSessionHolder)
: ModelLoaderFactory<ImageContentRenderer.Data, InputStream> {
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<ImageContentRenderer.Data, InputStream> {
return VectorGlideModelLoader(activeSessionHolder)
}
override fun teardown() {
// Is there something to do here?
}
}
class VectorGlideModelLoader(private val activeSessionHolder: ActiveSessionHolder)
: ModelLoader<ImageContentRenderer.Data, InputStream> {
override fun handles(model: ImageContentRenderer.Data): Boolean {
// Always handle
return true
}
override fun buildLoadData(model: ImageContentRenderer.Data, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream>? {
return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(activeSessionHolder, model, width, height))
}
}
class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolder,
private val data: ImageContentRenderer.Data,
private val width: Int,
private val height: Int)
: DataFetcher<InputStream> {
val client = OkHttpClient()
override fun getDataClass(): Class<InputStream> {
return InputStream::class.java
}
private var stream: InputStream? = null
override fun cleanup() {
cancel()
}
override fun getDataSource(): DataSource {
// ?
return DataSource.REMOTE
}
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<in InputStream>) {
Timber.v("Load data: $data")
if (data.isLocalFile()) {
val initialFile = File(data.url)
callback.onDataReady(FileInputStream(initialFile))
return
}
val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver()
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)
}
}