mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-21 17:05:39 +03:00
Merge pull request #8868 from element-hq/feature/fga/authenticated_media
Feature/fga/authenticated media
This commit is contained in:
commit
95e1bcbf64
35 changed files with 438 additions and 108 deletions
|
@ -19,7 +19,7 @@ def markwon = "4.6.2"
|
||||||
def moshi = "1.15.1"
|
def moshi = "1.15.1"
|
||||||
def lifecycle = "2.8.3"
|
def lifecycle = "2.8.3"
|
||||||
def flowBinding = "1.2.0"
|
def flowBinding = "1.2.0"
|
||||||
def flipper = "0.190.0"
|
def flipper = "0.259.0"
|
||||||
def epoxy = "5.0.0"
|
def epoxy = "5.0.0"
|
||||||
def mavericks = "3.0.9"
|
def mavericks = "3.0.9"
|
||||||
def glide = "4.16.0"
|
def glide = "4.16.0"
|
||||||
|
|
|
@ -17,7 +17,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "io.realm:realm-gradle-plugin:10.16.0"
|
classpath "io.realm:realm-gradle-plugin:10.18.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -296,6 +296,11 @@ interface Session {
|
||||||
*/
|
*/
|
||||||
fun getOkHttpClient(): OkHttpClient
|
fun getOkHttpClient(): OkHttpClient
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as [getOkHttpClient] but will add the access token to the request.
|
||||||
|
*/
|
||||||
|
fun getAuthenticatedOkHttpClient(): OkHttpClient
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A global session listener to get notified for some events.
|
* A global session listener to get notified for some events.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -61,6 +61,8 @@ interface ContentUrlResolver {
|
||||||
*/
|
*/
|
||||||
fun resolveThumbnail(contentUrl: String?, width: Int, height: Int, method: ThumbnailMethod): String?
|
fun resolveThumbnail(contentUrl: String?, width: Int, height: Int, method: ThumbnailMethod): String?
|
||||||
|
|
||||||
|
fun requiresAuthentication(resolvedUrl: String): Boolean
|
||||||
|
|
||||||
sealed class ResolvedMethod {
|
sealed class ResolvedMethod {
|
||||||
data class GET(val url: String) : ResolvedMethod()
|
data class GET(val url: String) : ResolvedMethod()
|
||||||
data class POST(val url: String, val jsonBody: String) : ResolvedMethod()
|
data class POST(val url: String, val jsonBody: String) : ResolvedMethod()
|
||||||
|
|
|
@ -95,6 +95,10 @@ data class HomeServerCapabilities(
|
||||||
* If set to true, the SDK will not use the network constraint when configuring Worker for the WorkManager, provided in Wellknown.
|
* If set to true, the SDK will not use the network constraint when configuring Worker for the WorkManager, provided in Wellknown.
|
||||||
*/
|
*/
|
||||||
val disableNetworkConstraint: Boolean? = null,
|
val disableNetworkConstraint: Boolean? = null,
|
||||||
|
/**
|
||||||
|
* True if the home server supports authenticated media.
|
||||||
|
*/
|
||||||
|
val canUseAuthenticatedMedia: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
enum class RoomCapabilitySupport {
|
enum class RoomCapabilitySupport {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.matrix.android.sdk.internal.auth.registration.RegisterAddThreePidTask
|
||||||
import org.matrix.android.sdk.internal.network.executeRequest
|
import org.matrix.android.sdk.internal.network.executeRequest
|
||||||
import org.matrix.android.sdk.internal.session.content.DefaultContentUrlResolver
|
import org.matrix.android.sdk.internal.session.content.DefaultContentUrlResolver
|
||||||
import org.matrix.android.sdk.internal.session.contentscanner.DisabledContentScannerService
|
import org.matrix.android.sdk.internal.session.contentscanner.DisabledContentScannerService
|
||||||
|
import org.matrix.android.sdk.internal.session.media.IsAuthenticatedMediaSupported
|
||||||
|
|
||||||
internal class DefaultLoginWizard(
|
internal class DefaultLoginWizard(
|
||||||
private val authAPI: AuthAPI,
|
private val authAPI: AuthAPI,
|
||||||
|
@ -45,8 +46,14 @@ internal class DefaultLoginWizard(
|
||||||
private var pendingSessionData: PendingSessionData = pendingSessionStore.getPendingSessionData() ?: error("Pending session data should exist here")
|
private var pendingSessionData: PendingSessionData = pendingSessionStore.getPendingSessionData() ?: error("Pending session data should exist here")
|
||||||
|
|
||||||
private val getProfileTask: GetProfileTask = DefaultGetProfileTask(
|
private val getProfileTask: GetProfileTask = DefaultGetProfileTask(
|
||||||
authAPI,
|
authAPI = authAPI,
|
||||||
DefaultContentUrlResolver(pendingSessionData.homeServerConnectionConfig, DisabledContentScannerService())
|
contentUrlResolver = DefaultContentUrlResolver(
|
||||||
|
homeServerConnectionConfig = pendingSessionData.homeServerConnectionConfig,
|
||||||
|
scannerService = DisabledContentScannerService(),
|
||||||
|
isAuthenticatedMediaSupported = object : IsAuthenticatedMediaSupported {
|
||||||
|
override fun invoke() = false
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getProfileInfo(matrixId: String): LoginProfileInfo {
|
override suspend fun getProfileInfo(matrixId: String): LoginProfileInfo {
|
||||||
|
|
|
@ -61,5 +61,6 @@ internal data class HomeServerVersion(
|
||||||
val r0_6_1 = HomeServerVersion(major = 0, minor = 6, patch = 1)
|
val r0_6_1 = HomeServerVersion(major = 0, minor = 6, patch = 1)
|
||||||
val v1_3_0 = HomeServerVersion(major = 1, minor = 3, patch = 0)
|
val v1_3_0 = HomeServerVersion(major = 1, minor = 3, patch = 0)
|
||||||
val v1_4_0 = HomeServerVersion(major = 1, minor = 4, patch = 0)
|
val v1_4_0 = HomeServerVersion(major = 1, minor = 4, patch = 0)
|
||||||
|
val v1_11_0 = HomeServerVersion(major = 1, minor = 11, patch = 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ private const val FEATURE_ID_ACCESS_TOKEN = "m.id_access_token"
|
||||||
private const val FEATURE_SEPARATE_ADD_AND_BIND = "m.separate_add_and_bind"
|
private const val FEATURE_SEPARATE_ADD_AND_BIND = "m.separate_add_and_bind"
|
||||||
private const val FEATURE_THREADS_MSC3440 = "org.matrix.msc3440"
|
private const val FEATURE_THREADS_MSC3440 = "org.matrix.msc3440"
|
||||||
private const val FEATURE_THREADS_MSC3440_STABLE = "org.matrix.msc3440.stable"
|
private const val FEATURE_THREADS_MSC3440_STABLE = "org.matrix.msc3440.stable"
|
||||||
|
|
||||||
@Deprecated("The availability of stable get_login_token is now exposed as a capability and part of login flow")
|
@Deprecated("The availability of stable get_login_token is now exposed as a capability and part of login flow")
|
||||||
private const val FEATURE_QR_CODE_LOGIN = "org.matrix.msc3882"
|
private const val FEATURE_QR_CODE_LOGIN = "org.matrix.msc3882"
|
||||||
private const val FEATURE_THREADS_MSC3771 = "org.matrix.msc3771"
|
private const val FEATURE_THREADS_MSC3771 = "org.matrix.msc3771"
|
||||||
|
@ -142,6 +143,15 @@ internal fun Versions.doesServerSupportLogoutDevices(): Boolean {
|
||||||
return getMaxVersion() >= HomeServerVersion.r0_6_1
|
return getMaxVersion() >= HomeServerVersion.r0_6_1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate if the server supports MSC3916 : https://github.com/matrix-org/matrix-spec-proposals/pull/3916
|
||||||
|
*
|
||||||
|
* @return true if authenticated media is supported
|
||||||
|
*/
|
||||||
|
internal fun Versions.doesServerSupportAuthenticatedMedia(): Boolean {
|
||||||
|
return getMaxVersion() >= HomeServerVersion.v1_11_0
|
||||||
|
}
|
||||||
|
|
||||||
private fun Versions.getMaxVersion(): HomeServerVersion {
|
private fun Versions.getMaxVersion(): HomeServerVersion {
|
||||||
return supportedVersions
|
return supportedVersions
|
||||||
?.mapNotNull { HomeServerVersion.parse(it) }
|
?.mapNotNull { HomeServerVersion.parse(it) }
|
||||||
|
|
|
@ -72,6 +72,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo052
|
||||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo053
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo053
|
||||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo054
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo054
|
||||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo055
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo055
|
||||||
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo056
|
||||||
import org.matrix.android.sdk.internal.util.Normalizer
|
import org.matrix.android.sdk.internal.util.Normalizer
|
||||||
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
|
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -80,7 +81,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
||||||
private val normalizer: Normalizer
|
private val normalizer: Normalizer
|
||||||
) : MatrixRealmMigration(
|
) : MatrixRealmMigration(
|
||||||
dbName = "Session",
|
dbName = "Session",
|
||||||
schemaVersion = 55L,
|
schemaVersion = 56L,
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Forces all RealmSessionStoreMigration instances to be equal.
|
* Forces all RealmSessionStoreMigration instances to be equal.
|
||||||
|
@ -145,5 +146,6 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
||||||
if (oldVersion < 53) MigrateSessionTo053(realm).perform()
|
if (oldVersion < 53) MigrateSessionTo053(realm).perform()
|
||||||
if (oldVersion < 54) MigrateSessionTo054(realm).perform()
|
if (oldVersion < 54) MigrateSessionTo054(realm).perform()
|
||||||
if (oldVersion < 55) MigrateSessionTo055(realm).perform()
|
if (oldVersion < 55) MigrateSessionTo055(realm).perform()
|
||||||
|
if (oldVersion < 56) MigrateSessionTo056(realm).perform()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ internal object HomeServerCapabilitiesMapper {
|
||||||
externalAccountManagementUrl = entity.externalAccountManagementUrl,
|
externalAccountManagementUrl = entity.externalAccountManagementUrl,
|
||||||
authenticationIssuer = entity.authenticationIssuer,
|
authenticationIssuer = entity.authenticationIssuer,
|
||||||
disableNetworkConstraint = entity.disableNetworkConstraint,
|
disableNetworkConstraint = entity.disableNetworkConstraint,
|
||||||
|
canUseAuthenticatedMedia = entity.canUseAuthenticatedMedia,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* 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 org.matrix.android.sdk.internal.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
internal class MigrateSessionTo056(realm: DynamicRealm) : RealmMigrator(realm, 56) {
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("HomeServerCapabilitiesEntity")
|
||||||
|
?.addField(HomeServerCapabilitiesEntityFields.CAN_USE_AUTHENTICATED_MEDIA, Boolean::class.java)
|
||||||
|
?.forceRefreshOfHomeServerCapabilities()
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ internal open class HomeServerCapabilitiesEntity(
|
||||||
var externalAccountManagementUrl: String? = null,
|
var externalAccountManagementUrl: String? = null,
|
||||||
var authenticationIssuer: String? = null,
|
var authenticationIssuer: String? = null,
|
||||||
var disableNetworkConstraint: Boolean? = null,
|
var disableNetworkConstraint: Boolean? = null,
|
||||||
|
var canUseAuthenticatedMedia: Boolean = false,
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
companion object
|
companion object
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.network
|
||||||
|
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
import org.matrix.android.sdk.internal.network.httpclient.addAuthenticationHeader
|
||||||
import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
|
import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
|
||||||
|
|
||||||
internal class AccessTokenInterceptor(private val accessTokenProvider: AccessTokenProvider) : Interceptor {
|
internal class AccessTokenInterceptor(private val accessTokenProvider: AccessTokenProvider) : Interceptor {
|
||||||
|
@ -28,7 +29,7 @@ internal class AccessTokenInterceptor(private val accessTokenProvider: AccessTok
|
||||||
// Add the access token to all requests if it is set
|
// Add the access token to all requests if it is set
|
||||||
accessTokenProvider.getToken()?.let { token ->
|
accessTokenProvider.getToken()?.let { token ->
|
||||||
val newRequestBuilder = request.newBuilder()
|
val newRequestBuilder = request.newBuilder()
|
||||||
newRequestBuilder.header(HttpHeaders.Authorization, "Bearer $token")
|
newRequestBuilder.addAuthenticationHeader(token)
|
||||||
request = newRequestBuilder.build()
|
request = newRequestBuilder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
package org.matrix.android.sdk.internal.network.httpclient
|
package org.matrix.android.sdk.internal.network.httpclient
|
||||||
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||||
import org.matrix.android.sdk.internal.network.AccessTokenInterceptor
|
import org.matrix.android.sdk.internal.network.AccessTokenInterceptor
|
||||||
|
import org.matrix.android.sdk.internal.network.HttpHeaders
|
||||||
import org.matrix.android.sdk.internal.network.interceptors.CurlLoggingInterceptor
|
import org.matrix.android.sdk.internal.network.interceptors.CurlLoggingInterceptor
|
||||||
import org.matrix.android.sdk.internal.network.ssl.CertUtil
|
import org.matrix.android.sdk.internal.network.ssl.CertUtil
|
||||||
import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
|
import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
|
||||||
|
@ -66,3 +68,10 @@ internal fun OkHttpClient.Builder.applyMatrixConfiguration(matrixConfiguration:
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Request.Builder.addAuthenticationHeader(accessToken: String?): Request.Builder {
|
||||||
|
if (accessToken != null) {
|
||||||
|
header(HttpHeaders.Authorization, "Bearer $accessToken")
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
|
@ -34,8 +34,11 @@ import org.matrix.android.sdk.api.session.crypto.attachments.ElementToDecrypt
|
||||||
import org.matrix.android.sdk.api.session.file.FileService
|
import org.matrix.android.sdk.api.session.file.FileService
|
||||||
import org.matrix.android.sdk.api.util.md5
|
import org.matrix.android.sdk.api.util.md5
|
||||||
import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments
|
import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments
|
||||||
|
import org.matrix.android.sdk.internal.di.Authenticated
|
||||||
import org.matrix.android.sdk.internal.di.SessionDownloadsDirectory
|
import org.matrix.android.sdk.internal.di.SessionDownloadsDirectory
|
||||||
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificateWithProgress
|
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificateWithProgress
|
||||||
|
import org.matrix.android.sdk.internal.network.httpclient.addAuthenticationHeader
|
||||||
|
import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
|
||||||
import org.matrix.android.sdk.internal.session.download.DownloadProgressInterceptor.Companion.DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER
|
import org.matrix.android.sdk.internal.session.download.DownloadProgressInterceptor.Companion.DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER
|
||||||
import org.matrix.android.sdk.internal.util.file.AtomicFileCreator
|
import org.matrix.android.sdk.internal.util.file.AtomicFileCreator
|
||||||
import org.matrix.android.sdk.internal.util.time.Clock
|
import org.matrix.android.sdk.internal.util.time.Clock
|
||||||
|
@ -54,6 +57,7 @@ internal class DefaultFileService @Inject constructor(
|
||||||
private val okHttpClient: OkHttpClient,
|
private val okHttpClient: OkHttpClient,
|
||||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
|
@Authenticated private val accessTokenProvider: AccessTokenProvider,
|
||||||
) : FileService {
|
) : FileService {
|
||||||
|
|
||||||
// Legacy folder, will be deleted
|
// Legacy folder, will be deleted
|
||||||
|
@ -124,21 +128,26 @@ internal class DefaultFileService @Inject constructor(
|
||||||
val cachedFiles = getFiles(url, fileName, mimeType, elementToDecrypt != null)
|
val cachedFiles = getFiles(url, fileName, mimeType, elementToDecrypt != null)
|
||||||
|
|
||||||
if (!cachedFiles.file.exists()) {
|
if (!cachedFiles.file.exists()) {
|
||||||
val resolvedUrl = contentUrlResolver.resolveForDownload(url, elementToDecrypt) ?: throw IllegalArgumentException("url is null")
|
val resolvedMethod = contentUrlResolver.resolveForDownload(url, elementToDecrypt) ?: throw IllegalArgumentException("url is null")
|
||||||
|
|
||||||
val request = when (resolvedUrl) {
|
val request = when (resolvedMethod) {
|
||||||
is ContentUrlResolver.ResolvedMethod.GET -> {
|
is ContentUrlResolver.ResolvedMethod.GET -> {
|
||||||
Request.Builder()
|
val requestBuilder = Request.Builder()
|
||||||
.url(resolvedUrl.url)
|
.url(resolvedMethod.url)
|
||||||
.header(DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER, url)
|
.header(DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER, url)
|
||||||
.build()
|
|
||||||
|
if (contentUrlResolver.requiresAuthentication(resolvedMethod.url)) {
|
||||||
|
val accessToken = accessTokenProvider.getToken()
|
||||||
|
requestBuilder.addAuthenticationHeader(accessToken)
|
||||||
|
}
|
||||||
|
requestBuilder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
is ContentUrlResolver.ResolvedMethod.POST -> {
|
is ContentUrlResolver.ResolvedMethod.POST -> {
|
||||||
Request.Builder()
|
Request.Builder()
|
||||||
.url(resolvedUrl.url)
|
.url(resolvedMethod.url)
|
||||||
.header(DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER, url)
|
.header(DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER, url)
|
||||||
.post(resolvedUrl.jsonBody.toRequestBody("application/json".toMediaType()))
|
.post(resolvedMethod.jsonBody.toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ import org.matrix.android.sdk.api.util.appendParamToUrl
|
||||||
import org.matrix.android.sdk.internal.auth.SSO_UIA_FALLBACK_PATH
|
import org.matrix.android.sdk.internal.auth.SSO_UIA_FALLBACK_PATH
|
||||||
import org.matrix.android.sdk.internal.auth.SessionParamsStore
|
import org.matrix.android.sdk.internal.auth.SessionParamsStore
|
||||||
import org.matrix.android.sdk.internal.database.tools.RealmDebugTools
|
import org.matrix.android.sdk.internal.database.tools.RealmDebugTools
|
||||||
|
import org.matrix.android.sdk.internal.di.Authenticated
|
||||||
import org.matrix.android.sdk.internal.di.ContentScannerDatabase
|
import org.matrix.android.sdk.internal.di.ContentScannerDatabase
|
||||||
import org.matrix.android.sdk.internal.di.CryptoDatabase
|
import org.matrix.android.sdk.internal.di.CryptoDatabase
|
||||||
import org.matrix.android.sdk.internal.di.IdentityDatabase
|
import org.matrix.android.sdk.internal.di.IdentityDatabase
|
||||||
|
@ -131,6 +132,8 @@ internal class DefaultSession @Inject constructor(
|
||||||
private val eventStreamService: Lazy<EventStreamService>,
|
private val eventStreamService: Lazy<EventStreamService>,
|
||||||
@UnauthenticatedWithCertificate
|
@UnauthenticatedWithCertificate
|
||||||
private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient>,
|
private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient>,
|
||||||
|
@Authenticated
|
||||||
|
private val authenticatedOkHttpClient: Lazy<OkHttpClient>,
|
||||||
private val sessionState: SessionState,
|
private val sessionState: SessionState,
|
||||||
) : Session,
|
) : Session,
|
||||||
GlobalErrorHandler.Listener {
|
GlobalErrorHandler.Listener {
|
||||||
|
@ -234,6 +237,10 @@ internal class DefaultSession @Inject constructor(
|
||||||
return unauthenticatedWithCertificateOkHttpClient.get()
|
return unauthenticatedWithCertificateOkHttpClient.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAuthenticatedOkHttpClient(): OkHttpClient {
|
||||||
|
return authenticatedOkHttpClient.get()
|
||||||
|
}
|
||||||
|
|
||||||
override fun addListener(listener: Session.Listener) {
|
override fun addListener(listener: Session.Listener) {
|
||||||
sessionListeners.addListener(listener)
|
sessionListeners.addListener(listener)
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,7 @@ import org.matrix.android.sdk.internal.session.events.DefaultEventService
|
||||||
import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapabilitiesService
|
import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapabilitiesService
|
||||||
import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService
|
import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService
|
||||||
import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManager
|
import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManager
|
||||||
|
import org.matrix.android.sdk.internal.session.media.DefaultIsAuthenticatedMediaSupported
|
||||||
import org.matrix.android.sdk.internal.session.openid.DefaultOpenIdService
|
import org.matrix.android.sdk.internal.session.openid.DefaultOpenIdService
|
||||||
import org.matrix.android.sdk.internal.session.permalinks.DefaultPermalinkService
|
import org.matrix.android.sdk.internal.session.permalinks.DefaultPermalinkService
|
||||||
import org.matrix.android.sdk.internal.session.room.EventRelationsAggregationProcessor
|
import org.matrix.android.sdk.internal.session.room.EventRelationsAggregationProcessor
|
||||||
|
@ -365,6 +366,10 @@ internal abstract class SessionModule {
|
||||||
@IntoSet
|
@IntoSet
|
||||||
abstract fun bindEventInsertObserver(observer: EventInsertLiveObserver): SessionLifecycleObserver
|
abstract fun bindEventInsertObserver(observer: EventInsertLiveObserver): SessionLifecycleObserver
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoSet
|
||||||
|
abstract fun bindIsMediaAuthenticated(observer: DefaultIsAuthenticatedMediaSupported): SessionLifecycleObserver
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoSet
|
@IntoSet
|
||||||
abstract fun bindIntegrationManager(manager: IntegrationManager): SessionLifecycleObserver
|
abstract fun bindIntegrationManager(manager: IntegrationManager): SessionLifecycleObserver
|
||||||
|
|
|
@ -25,16 +25,18 @@ import org.matrix.android.sdk.api.session.crypto.attachments.ElementToDecrypt
|
||||||
import org.matrix.android.sdk.internal.network.NetworkConstants
|
import org.matrix.android.sdk.internal.network.NetworkConstants
|
||||||
import org.matrix.android.sdk.internal.session.contentscanner.ScanEncryptorUtils
|
import org.matrix.android.sdk.internal.session.contentscanner.ScanEncryptorUtils
|
||||||
import org.matrix.android.sdk.internal.session.contentscanner.model.toJson
|
import org.matrix.android.sdk.internal.session.contentscanner.model.toJson
|
||||||
|
import org.matrix.android.sdk.internal.session.media.IsAuthenticatedMediaSupported
|
||||||
import org.matrix.android.sdk.internal.util.ensureTrailingSlash
|
import org.matrix.android.sdk.internal.util.ensureTrailingSlash
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class DefaultContentUrlResolver @Inject constructor(
|
internal class DefaultContentUrlResolver @Inject constructor(
|
||||||
homeServerConnectionConfig: HomeServerConnectionConfig,
|
homeServerConnectionConfig: HomeServerConnectionConfig,
|
||||||
private val scannerService: ContentScannerService
|
private val scannerService: ContentScannerService,
|
||||||
|
private val isAuthenticatedMediaSupported: IsAuthenticatedMediaSupported,
|
||||||
) : ContentUrlResolver {
|
) : ContentUrlResolver {
|
||||||
|
|
||||||
private val baseUrl = homeServerConnectionConfig.homeServerUriBase.toString().ensureTrailingSlash()
|
private val baseUrl = homeServerConnectionConfig.homeServerUriBase.toString().ensureTrailingSlash()
|
||||||
|
private val authenticatedMediaApiPath = baseUrl + NetworkConstants.URI_API_PREFIX_PATH_V1 + "media/"
|
||||||
override val uploadUrl = baseUrl + NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "upload"
|
override val uploadUrl = baseUrl + NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "upload"
|
||||||
|
|
||||||
override fun resolveForDownload(contentUrl: String?, elementToDecrypt: ElementToDecrypt?): ContentUrlResolver.ResolvedMethod? {
|
override fun resolveForDownload(contentUrl: String?, elementToDecrypt: ElementToDecrypt?): ContentUrlResolver.ResolvedMethod? {
|
||||||
|
@ -80,15 +82,20 @@ internal class DefaultContentUrlResolver @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun requiresAuthentication(resolvedUrl: String): Boolean {
|
||||||
|
return resolvedUrl.startsWith(authenticatedMediaApiPath)
|
||||||
|
}
|
||||||
|
|
||||||
private fun resolve(
|
private fun resolve(
|
||||||
contentUrl: String,
|
contentUrl: String,
|
||||||
toThumbnail: Boolean,
|
toThumbnail: Boolean,
|
||||||
params: String = ""
|
params: String = ""
|
||||||
): String {
|
): String {
|
||||||
var serverAndMediaId = contentUrl.removeMxcPrefix()
|
var serverAndMediaId = contentUrl.removeMxcPrefix()
|
||||||
|
|
||||||
val apiPath = if (scannerService.isScannerEnabled()) {
|
val apiPath = if (scannerService.isScannerEnabled()) {
|
||||||
NetworkConstants.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE
|
NetworkConstants.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE
|
||||||
|
} else if (isAuthenticatedMediaSupported()) {
|
||||||
|
NetworkConstants.URI_API_PREFIX_PATH_V1 + "media/"
|
||||||
} else {
|
} else {
|
||||||
NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0
|
NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,11 @@ import com.zhuinden.monarchy.Monarchy
|
||||||
import org.matrix.android.sdk.api.MatrixPatterns.getServerName
|
import org.matrix.android.sdk.api.MatrixPatterns.getServerName
|
||||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||||
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
|
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
|
||||||
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.extensions.orTrue
|
import org.matrix.android.sdk.api.extensions.orTrue
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||||
import org.matrix.android.sdk.internal.auth.version.Versions
|
import org.matrix.android.sdk.internal.auth.version.Versions
|
||||||
|
import org.matrix.android.sdk.internal.auth.version.doesServerSupportAuthenticatedMedia
|
||||||
import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices
|
import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices
|
||||||
import org.matrix.android.sdk.internal.auth.version.doesServerSupportQrCodeLogin
|
import org.matrix.android.sdk.internal.auth.version.doesServerSupportQrCodeLogin
|
||||||
import org.matrix.android.sdk.internal.auth.version.doesServerSupportRedactionOfRelatedEvents
|
import org.matrix.android.sdk.internal.auth.version.doesServerSupportRedactionOfRelatedEvents
|
||||||
|
@ -38,8 +40,9 @@ import org.matrix.android.sdk.internal.di.UserId
|
||||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||||
import org.matrix.android.sdk.internal.network.executeRequest
|
import org.matrix.android.sdk.internal.network.executeRequest
|
||||||
import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManagerConfigExtractor
|
import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManagerConfigExtractor
|
||||||
|
import org.matrix.android.sdk.internal.session.media.AuthenticatedMediaAPI
|
||||||
import org.matrix.android.sdk.internal.session.media.GetMediaConfigResult
|
import org.matrix.android.sdk.internal.session.media.GetMediaConfigResult
|
||||||
import org.matrix.android.sdk.internal.session.media.MediaAPI
|
import org.matrix.android.sdk.internal.session.media.UnauthenticatedMediaAPI
|
||||||
import org.matrix.android.sdk.internal.task.Task
|
import org.matrix.android.sdk.internal.task.Task
|
||||||
import org.matrix.android.sdk.internal.util.awaitTransaction
|
import org.matrix.android.sdk.internal.util.awaitTransaction
|
||||||
import org.matrix.android.sdk.internal.wellknown.GetWellknownTask
|
import org.matrix.android.sdk.internal.wellknown.GetWellknownTask
|
||||||
|
@ -55,7 +58,8 @@ internal interface GetHomeServerCapabilitiesTask : Task<GetHomeServerCapabilitie
|
||||||
|
|
||||||
internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||||
private val capabilitiesAPI: CapabilitiesAPI,
|
private val capabilitiesAPI: CapabilitiesAPI,
|
||||||
private val mediaAPI: MediaAPI,
|
private val unauthenticatedMediaAPI: UnauthenticatedMediaAPI,
|
||||||
|
private val authenticatedMediaAPI: AuthenticatedMediaAPI,
|
||||||
@SessionDatabase private val monarchy: Monarchy,
|
@SessionDatabase private val monarchy: Monarchy,
|
||||||
private val globalErrorReceiver: GlobalErrorReceiver,
|
private val globalErrorReceiver: GlobalErrorReceiver,
|
||||||
private val getWellknownTask: GetWellknownTask,
|
private val getWellknownTask: GetWellknownTask,
|
||||||
|
@ -70,7 +74,6 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||||
if (!doRequest) {
|
if (!doRequest) {
|
||||||
monarchy.awaitTransaction { realm ->
|
monarchy.awaitTransaction { realm ->
|
||||||
val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity.getOrCreate(realm)
|
val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity.getOrCreate(realm)
|
||||||
|
|
||||||
doRequest = homeServerCapabilitiesEntity.lastUpdatedTimestamp + MIN_DELAY_BETWEEN_TWO_REQUEST_MILLIS < Date().time
|
doRequest = homeServerCapabilitiesEntity.lastUpdatedTimestamp + MIN_DELAY_BETWEEN_TWO_REQUEST_MILLIS < Date().time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,18 +88,22 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||||
}
|
}
|
||||||
}.getOrNull()
|
}.getOrNull()
|
||||||
|
|
||||||
val mediaConfig = runCatching {
|
|
||||||
executeRequest(globalErrorReceiver) {
|
|
||||||
mediaAPI.getMediaConfig()
|
|
||||||
}
|
|
||||||
}.getOrNull()
|
|
||||||
|
|
||||||
val versions = runCatching {
|
val versions = runCatching {
|
||||||
executeRequest(null) {
|
executeRequest(null) {
|
||||||
capabilitiesAPI.getVersions()
|
capabilitiesAPI.getVersions()
|
||||||
}
|
}
|
||||||
}.getOrNull()
|
}.getOrNull()
|
||||||
|
|
||||||
|
val mediaConfig = runCatching {
|
||||||
|
executeRequest(globalErrorReceiver) {
|
||||||
|
if (versions?.doesServerSupportAuthenticatedMedia().orFalse()) {
|
||||||
|
authenticatedMediaAPI.getMediaConfig()
|
||||||
|
} else {
|
||||||
|
unauthenticatedMediaAPI.getMediaConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.getOrNull()
|
||||||
|
|
||||||
// Domain may include a port (eg, matrix.org:8080)
|
// Domain may include a port (eg, matrix.org:8080)
|
||||||
// Per https://spec.matrix.org/latest/client-server-api/#well-known-uri we should extract the hostname from the server name
|
// Per https://spec.matrix.org/latest/client-server-api/#well-known-uri we should extract the hostname from the server name
|
||||||
// So we take everything before the last : as the domain for the well-known task.
|
// So we take everything before the last : as the domain for the well-known task.
|
||||||
|
@ -155,6 +162,8 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||||
getVersionResult.doesServerSupportRemoteToggleOfPushNotifications()
|
getVersionResult.doesServerSupportRemoteToggleOfPushNotifications()
|
||||||
homeServerCapabilitiesEntity.canRedactEventWithRelations =
|
homeServerCapabilitiesEntity.canRedactEventWithRelations =
|
||||||
getVersionResult.doesServerSupportRedactionOfRelatedEvents()
|
getVersionResult.doesServerSupportRedactionOfRelatedEvents()
|
||||||
|
homeServerCapabilitiesEntity.canUseAuthenticatedMedia =
|
||||||
|
getVersionResult.doesServerSupportAuthenticatedMedia()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) {
|
if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) {
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* 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 org.matrix.android.sdk.internal.session.media
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
|
import org.matrix.android.sdk.internal.network.NetworkConstants
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the media repository API using the new Authenticated media API.
|
||||||
|
*/
|
||||||
|
internal interface AuthenticatedMediaAPI : MediaAPI {
|
||||||
|
/**
|
||||||
|
* Retrieve the configuration of the content repository
|
||||||
|
* Ref: https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv1mediaconfig
|
||||||
|
*/
|
||||||
|
@GET(NetworkConstants.URI_API_PREFIX_PATH_V1 + "media/config")
|
||||||
|
override suspend fun getMediaConfig(): GetMediaConfigResult
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about a URL for the client. Typically this is called when a client
|
||||||
|
* sees a URL in a message and wants to render a preview for the user.
|
||||||
|
* Ref: https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv1mediapreview_url
|
||||||
|
* @param url Required. The URL to get a preview of.
|
||||||
|
* @param ts The preferred point in time to return a preview for. The server may return a newer version
|
||||||
|
* if it does not have the requested version available.
|
||||||
|
*/
|
||||||
|
@GET(NetworkConstants.URI_API_PREFIX_PATH_V1 + "media/preview_url")
|
||||||
|
override suspend fun getPreviewUrlData(@Query("url") url: String, @Query("ts") ts: Long?): JsonDict
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* 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 org.matrix.android.sdk.internal.session.media
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import io.realm.Realm
|
||||||
|
import io.realm.RealmResults
|
||||||
|
import org.matrix.android.sdk.internal.database.RealmLiveEntityObserver
|
||||||
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
||||||
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@SessionScope
|
||||||
|
internal class DefaultIsAuthenticatedMediaSupported @Inject constructor(
|
||||||
|
@SessionDatabase private val monarchy: Monarchy,
|
||||||
|
) :
|
||||||
|
IsAuthenticatedMediaSupported,
|
||||||
|
RealmLiveEntityObserver<HomeServerCapabilitiesEntity>(monarchy.realmConfiguration) {
|
||||||
|
|
||||||
|
override fun invoke(): Boolean {
|
||||||
|
return canUseAuthenticatedMedia
|
||||||
|
}
|
||||||
|
|
||||||
|
override val query = Monarchy.Query {
|
||||||
|
it.where(HomeServerCapabilitiesEntity::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChange(results: RealmResults<HomeServerCapabilitiesEntity>) {
|
||||||
|
canUseAuthenticatedMedia = results.canUseAuthenticatedMedia()
|
||||||
|
Timber.d("canUseAuthenticatedMedia: $canUseAuthenticatedMedia")
|
||||||
|
}
|
||||||
|
|
||||||
|
private var canUseAuthenticatedMedia = getInitialValue()
|
||||||
|
|
||||||
|
private fun getInitialValue(): Boolean {
|
||||||
|
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||||
|
query.createQuery(realm).findAll().canUseAuthenticatedMedia()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun RealmResults<HomeServerCapabilitiesEntity>.canUseAuthenticatedMedia(): Boolean {
|
||||||
|
return firstOrNull()?.canUseAuthenticatedMedia ?: false
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ internal interface GetPreviewUrlTask : Task<GetPreviewUrlTask.Params, PreviewUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class DefaultGetPreviewUrlTask @Inject constructor(
|
internal class DefaultGetPreviewUrlTask @Inject constructor(
|
||||||
private val mediaAPI: MediaAPI,
|
private val mediaAPIProvider: MediaAPIProvider,
|
||||||
private val globalErrorReceiver: GlobalErrorReceiver,
|
private val globalErrorReceiver: GlobalErrorReceiver,
|
||||||
@SessionDatabase private val monarchy: Monarchy
|
@SessionDatabase private val monarchy: Monarchy
|
||||||
) : GetPreviewUrlTask {
|
) : GetPreviewUrlTask {
|
||||||
|
@ -66,7 +66,7 @@ internal class DefaultGetPreviewUrlTask @Inject constructor(
|
||||||
|
|
||||||
private suspend fun doRequest(url: String, timestamp: Long?): PreviewUrlData {
|
private suspend fun doRequest(url: String, timestamp: Long?): PreviewUrlData {
|
||||||
return executeRequest(globalErrorReceiver) {
|
return executeRequest(globalErrorReceiver) {
|
||||||
mediaAPI.getPreviewUrlData(url, timestamp)
|
mediaAPIProvider.getMediaAPI().getPreviewUrlData(url, timestamp)
|
||||||
}
|
}
|
||||||
.toPreviewUrlData(url)
|
.toPreviewUrlData(url)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,13 @@ internal interface GetRawPreviewUrlTask : Task<GetRawPreviewUrlTask.Params, Json
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class DefaultGetRawPreviewUrlTask @Inject constructor(
|
internal class DefaultGetRawPreviewUrlTask @Inject constructor(
|
||||||
private val mediaAPI: MediaAPI,
|
private val mediaAPIProvider: MediaAPIProvider,
|
||||||
private val globalErrorReceiver: GlobalErrorReceiver
|
private val globalErrorReceiver: GlobalErrorReceiver
|
||||||
) : GetRawPreviewUrlTask {
|
) : GetRawPreviewUrlTask {
|
||||||
|
|
||||||
override suspend fun execute(params: GetRawPreviewUrlTask.Params): JsonDict {
|
override suspend fun execute(params: GetRawPreviewUrlTask.Params): JsonDict {
|
||||||
return executeRequest(globalErrorReceiver) {
|
return executeRequest(globalErrorReceiver) {
|
||||||
mediaAPI.getPreviewUrlData(params.url, params.timestamp)
|
mediaAPIProvider.getMediaAPI().getPreviewUrlData(params.url, params.timestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* 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 org.matrix.android.sdk.internal.session.media
|
||||||
|
|
||||||
|
interface IsAuthenticatedMediaSupported {
|
||||||
|
operator fun invoke(): Boolean
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
* Copyright (C) 2024 The Matrix.org Foundation C.I.C.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@ -17,26 +17,11 @@
|
||||||
package org.matrix.android.sdk.internal.session.media
|
package org.matrix.android.sdk.internal.session.media
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.util.JsonDict
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
import org.matrix.android.sdk.internal.network.NetworkConstants
|
|
||||||
import retrofit2.http.GET
|
|
||||||
import retrofit2.http.Query
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This defines some method to interact with the media repository.
|
||||||
|
*/
|
||||||
internal interface MediaAPI {
|
internal interface MediaAPI {
|
||||||
/**
|
|
||||||
* Retrieve the configuration of the content repository
|
|
||||||
* Ref: https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-media-r0-config
|
|
||||||
*/
|
|
||||||
@GET(NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "config")
|
|
||||||
suspend fun getMediaConfig(): GetMediaConfigResult
|
suspend fun getMediaConfig(): GetMediaConfigResult
|
||||||
|
suspend fun getPreviewUrlData(url: String, ts: Long?): JsonDict
|
||||||
/**
|
|
||||||
* Get information about a URL for the client. Typically this is called when a client
|
|
||||||
* sees a URL in a message and wants to render a preview for the user.
|
|
||||||
* Ref: https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-media-r0-preview-url
|
|
||||||
* @param url Required. The URL to get a preview of.
|
|
||||||
* @param ts The preferred point in time to return a preview for. The server may return a newer version
|
|
||||||
* if it does not have the requested version available.
|
|
||||||
*/
|
|
||||||
@GET(NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "preview_url")
|
|
||||||
suspend fun getPreviewUrlData(@Query("url") url: String, @Query("ts") ts: Long?): JsonDict
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* 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 org.matrix.android.sdk.internal.session.media
|
||||||
|
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal class MediaAPIProvider @Inject constructor(
|
||||||
|
private val isAuthenticatedMediaSupported: IsAuthenticatedMediaSupported,
|
||||||
|
private val authenticatedMediaAPI: AuthenticatedMediaAPI,
|
||||||
|
private val unauthenticatedMediaAPI: UnauthenticatedMediaAPI,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun getMediaAPI(): MediaAPI {
|
||||||
|
return if (isAuthenticatedMediaSupported()) {
|
||||||
|
authenticatedMediaAPI
|
||||||
|
} else {
|
||||||
|
unauthenticatedMediaAPI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,11 +31,21 @@ internal abstract class MediaModule {
|
||||||
@Provides
|
@Provides
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@SessionScope
|
@SessionScope
|
||||||
fun providesMediaAPI(retrofit: Retrofit): MediaAPI {
|
fun providesUnauthenticatedMediaAPI(retrofit: Retrofit): UnauthenticatedMediaAPI {
|
||||||
return retrofit.create(MediaAPI::class.java)
|
return retrofit.create(UnauthenticatedMediaAPI::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@JvmStatic
|
||||||
|
@SessionScope
|
||||||
|
fun providesAuthenticatedMediaAPI(retrofit: Retrofit): AuthenticatedMediaAPI {
|
||||||
|
return retrofit.create(AuthenticatedMediaAPI::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindIsAuthenticatedMediaSupported(isAuthenticatedMediaSupported: DefaultIsAuthenticatedMediaSupported): IsAuthenticatedMediaSupported
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindMediaService(service: DefaultMediaService): MediaService
|
abstract fun bindMediaService(service: DefaultMediaService): MediaService
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* 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 org.matrix.android.sdk.internal.session.media
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
|
import org.matrix.android.sdk.internal.network.NetworkConstants
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
internal interface UnauthenticatedMediaAPI : MediaAPI {
|
||||||
|
/**
|
||||||
|
* Retrieve the configuration of the content repository
|
||||||
|
* Ref: https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-media-r0-config
|
||||||
|
*/
|
||||||
|
@GET(NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "config")
|
||||||
|
override suspend fun getMediaConfig(): GetMediaConfigResult
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about a URL for the client. Typically this is called when a client
|
||||||
|
* sees a URL in a message and wants to render a preview for the user.
|
||||||
|
* Ref: https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-media-r0-preview-url
|
||||||
|
* @param url Required. The URL to get a preview of.
|
||||||
|
* @param ts The preferred point in time to return a preview for. The server may return a newer version
|
||||||
|
* if it does not have the requested version available.
|
||||||
|
*/
|
||||||
|
@GET(NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "preview_url")
|
||||||
|
override suspend fun getPreviewUrlData(@Query("url") url: String, @Query("ts") ts: Long?): JsonDict
|
||||||
|
}
|
|
@ -399,7 +399,7 @@ dependencies {
|
||||||
exclude group: 'com.facebook.fbjni', module: 'fbjni'
|
exclude group: 'com.facebook.fbjni', module: 'fbjni'
|
||||||
}
|
}
|
||||||
debugImplementation 'com.facebook.soloader:soloader:0.10.5'
|
debugImplementation 'com.facebook.soloader:soloader:0.10.5'
|
||||||
debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.2.0"
|
debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.3.0"
|
||||||
|
|
||||||
gplayImplementation "com.google.android.gms:play-services-location:21.3.0"
|
gplayImplementation "com.google.android.gms:play-services-location:21.3.0"
|
||||||
// UnifiedPush gplay flavor only
|
// UnifiedPush gplay flavor only
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package im.vector.app.core.di
|
package im.vector.app.core.di
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import im.vector.app.ActiveSessionDataSource
|
import im.vector.app.ActiveSessionDataSource
|
||||||
import im.vector.app.core.dispatchers.CoroutineDispatchers
|
import im.vector.app.core.dispatchers.CoroutineDispatchers
|
||||||
import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase
|
import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase
|
||||||
|
@ -50,7 +49,6 @@ class ActiveSessionHolder @Inject constructor(
|
||||||
private val imageManager: ImageManager,
|
private val imageManager: ImageManager,
|
||||||
private val guardServiceStarter: GuardServiceStarter,
|
private val guardServiceStarter: GuardServiceStarter,
|
||||||
private val sessionInitializer: SessionInitializer,
|
private val sessionInitializer: SessionInitializer,
|
||||||
private val applicationContext: Context,
|
|
||||||
private val authenticationService: AuthenticationService,
|
private val authenticationService: AuthenticationService,
|
||||||
private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase,
|
private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase,
|
||||||
private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
|
private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
|
||||||
|
|
|
@ -21,8 +21,7 @@ import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.model.GlideUrl
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
import com.github.piasy.biv.BigImageViewer
|
import com.github.piasy.biv.BigImageViewer
|
||||||
import com.github.piasy.biv.loader.glide.GlideImageLoader
|
import com.github.piasy.biv.loader.glide.GlideImageLoader
|
||||||
import im.vector.app.ActiveSessionDataSource
|
import im.vector.app.core.glide.AuthenticatedGlideUrlLoaderFactory
|
||||||
import im.vector.app.core.glide.FactoryUrl
|
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -32,16 +31,16 @@ import javax.inject.Inject
|
||||||
*/
|
*/
|
||||||
class ImageManager @Inject constructor(
|
class ImageManager @Inject constructor(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val activeSessionDataSource: ActiveSessionDataSource
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun onSessionStarted(session: Session) {
|
fun onSessionStarted(session: Session) {
|
||||||
// Do this call first
|
// Do this call first
|
||||||
BigImageViewer.initialize(GlideImageLoader.with(context, session.getOkHttpClient()))
|
val glideImageLoader = GlideImageLoader.with(context, session.getOkHttpClient())
|
||||||
|
BigImageViewer.initialize(glideImageLoader)
|
||||||
|
|
||||||
val glide = Glide.get(context)
|
val glide = Glide.get(context)
|
||||||
|
|
||||||
// And this one. FIXME But are losing what BigImageViewer has done to add a Progress listener
|
// And this one. It'll be tried first, otherwise it'll use the one initialised by GlideImageLoader.
|
||||||
glide.registry.replace(GlideUrl::class.java, InputStream::class.java, FactoryUrl(activeSessionDataSource))
|
glide.registry.prepend(GlideUrl::class.java, InputStream::class.java, AuthenticatedGlideUrlLoaderFactory(context))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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.app.core.glide
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher
|
||||||
|
import com.bumptech.glide.load.Options
|
||||||
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
|
import com.bumptech.glide.load.model.ModelLoader
|
||||||
|
import com.bumptech.glide.load.model.ModelLoaderFactory
|
||||||
|
import com.bumptech.glide.load.model.MultiModelLoaderFactory
|
||||||
|
import im.vector.app.core.extensions.singletonEntryPoint
|
||||||
|
import okhttp3.Call
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
class AuthenticatedGlideUrlLoaderFactory(private val context: Context) : ModelLoaderFactory<GlideUrl, InputStream> {
|
||||||
|
|
||||||
|
private val defaultClient = OkHttpClient()
|
||||||
|
|
||||||
|
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<GlideUrl, InputStream> {
|
||||||
|
return AuthenticatedGlideUrlLoader(context, defaultClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun teardown() = Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
class AuthenticatedGlideUrlLoader(
|
||||||
|
context: Context,
|
||||||
|
private val defaultClient: OkHttpClient
|
||||||
|
) :
|
||||||
|
ModelLoader<GlideUrl, InputStream> {
|
||||||
|
|
||||||
|
private val activeSessionHolder = context.singletonEntryPoint().activeSessionHolder()
|
||||||
|
private val client: OkHttpClient
|
||||||
|
get() = activeSessionHolder.getSafeActiveSession()
|
||||||
|
?.getAuthenticatedOkHttpClient()
|
||||||
|
?: defaultClient
|
||||||
|
|
||||||
|
private val callFactory = Call.Factory { request -> client.newCall(request) }
|
||||||
|
|
||||||
|
override fun handles(model: GlideUrl): Boolean {
|
||||||
|
if (!activeSessionHolder.hasActiveSession()) return false
|
||||||
|
val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver()
|
||||||
|
val stringUrl = model.toStringUrl()
|
||||||
|
return contentUrlResolver.requiresAuthentication(stringUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildLoadData(model: GlideUrl, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream> {
|
||||||
|
val fetcher = OkHttpStreamFetcher(callFactory, model)
|
||||||
|
return ModelLoader.LoadData(model, fetcher)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 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.app.core.glide
|
|
||||||
|
|
||||||
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
|
|
||||||
import com.bumptech.glide.load.model.GlideUrl
|
|
||||||
import com.bumptech.glide.load.model.ModelLoader
|
|
||||||
import com.bumptech.glide.load.model.ModelLoaderFactory
|
|
||||||
import com.bumptech.glide.load.model.MultiModelLoaderFactory
|
|
||||||
import im.vector.app.ActiveSessionDataSource
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
class FactoryUrl(private val activeSessionDataSource: ActiveSessionDataSource) : ModelLoaderFactory<GlideUrl, InputStream> {
|
|
||||||
|
|
||||||
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<GlideUrl, InputStream> {
|
|
||||||
val client = activeSessionDataSource.currentValue?.orNull()?.getOkHttpClient() ?: OkHttpClient()
|
|
||||||
return OkHttpUrlLoader(client)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun teardown() {
|
|
||||||
// Do nothing, this instance doesn't own the client.
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -32,15 +32,14 @@ import im.vector.app.features.session.coroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
class VectorGlideModelLoaderFactory(private val context: Context) : ModelLoaderFactory<ImageContentRenderer.Data, InputStream> {
|
class ImageContentRendererDataLoaderFactory(private val context: Context) : ModelLoaderFactory<ImageContentRenderer.Data, InputStream> {
|
||||||
|
|
||||||
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<ImageContentRenderer.Data, InputStream> {
|
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<ImageContentRenderer.Data, InputStream> {
|
||||||
return VectorGlideModelLoader(context)
|
return ImageContentRendererDataLoader(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun teardown() {
|
override fun teardown() {
|
||||||
|
@ -48,7 +47,7 @@ class VectorGlideModelLoaderFactory(private val context: Context) : ModelLoaderF
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VectorGlideModelLoader(private val context: Context) :
|
class ImageContentRendererDataLoader(private val context: Context) :
|
||||||
ModelLoader<ImageContentRenderer.Data, InputStream> {
|
ModelLoader<ImageContentRenderer.Data, InputStream> {
|
||||||
override fun handles(model: ImageContentRenderer.Data): Boolean {
|
override fun handles(model: ImageContentRenderer.Data): Boolean {
|
||||||
// Always handle
|
// Always handle
|
||||||
|
@ -56,11 +55,11 @@ class VectorGlideModelLoader(private val context: Context) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun buildLoadData(model: ImageContentRenderer.Data, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream>? {
|
override fun buildLoadData(model: ImageContentRenderer.Data, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream>? {
|
||||||
return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(context, model, width, height))
|
return ModelLoader.LoadData(ObjectKey(model), ImageContentRendererDataFetcher(context, model, width, height))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VectorGlideDataFetcher(
|
class ImageContentRendererDataFetcher(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val data: ImageContentRenderer.Data,
|
private val data: ImageContentRenderer.Data,
|
||||||
private val width: Int,
|
private val width: Int,
|
||||||
|
@ -71,8 +70,6 @@ class VectorGlideDataFetcher(
|
||||||
private val localFilesHelper = LocalFilesHelper(context)
|
private val localFilesHelper = LocalFilesHelper(context)
|
||||||
private val activeSessionHolder = context.singletonEntryPoint().activeSessionHolder()
|
private val activeSessionHolder = context.singletonEntryPoint().activeSessionHolder()
|
||||||
|
|
||||||
private val client = activeSessionHolder.getSafeActiveSession()?.getOkHttpClient() ?: OkHttpClient()
|
|
||||||
|
|
||||||
override fun getDataClass(): Class<InputStream> {
|
override fun getDataClass(): Class<InputStream> {
|
||||||
return InputStream::class.java
|
return InputStream::class.java
|
||||||
}
|
}
|
|
@ -38,7 +38,7 @@ class MyAppGlideModule : AppGlideModule() {
|
||||||
registry.append(
|
registry.append(
|
||||||
ImageContentRenderer.Data::class.java,
|
ImageContentRenderer.Data::class.java,
|
||||||
InputStream::class.java,
|
InputStream::class.java,
|
||||||
VectorGlideModelLoaderFactory(context)
|
ImageContentRendererDataLoaderFactory(context)
|
||||||
)
|
)
|
||||||
registry.append(
|
registry.append(
|
||||||
AvatarPlaceholder::class.java,
|
AvatarPlaceholder::class.java,
|
||||||
|
|
Loading…
Reference in a new issue