Content : make content url resolution aware of homeserver url

This commit is contained in:
ganfra 2019-01-23 16:25:24 +01:00
parent 1d400180bc
commit cc4c1cf308
8 changed files with 131 additions and 26 deletions

View File

@ -4,16 +4,13 @@ import android.widget.ImageView
import androidx.core.content.ContextCompat
import com.amulyakhare.textdrawable.TextDrawable
import com.bumptech.glide.request.RequestOptions
import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.session.room.model.RoomMember
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotredesign.R
import im.vector.riotredesign.core.extensions.firstCharAsString
import im.vector.riotredesign.core.glide.GlideApp

private const val MEDIA_URL = "https://matrix.org/_matrix/media/v1/download/"
private const val MXC_PREFIX = "mxc://"

object AvatarRenderer {

fun render(roomMember: RoomMember, imageView: ImageView) {
@ -28,7 +25,7 @@ object AvatarRenderer {
if (name.isNullOrEmpty()) {
return
}
val resolvedUrl = ContentUrlResolver.resolve(avatarUrl)
val resolvedUrl = Matrix.getInstance().currentSession.contentUrlResolver().resolveFullSize(avatarUrl)
val avatarColor = ContextCompat.getColor(imageView.context, R.color.pale_teal)
val fallbackDrawable = TextDrawable.builder().buildRound(name.firstCharAsString().toUpperCase(), avatarColor)


View File

@ -5,6 +5,7 @@ import android.graphics.Point
import android.media.ExifInterface
import android.view.WindowManager
import android.widget.ImageView
import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
import im.vector.riotredesign.core.glide.GlideApp
@ -48,12 +49,17 @@ object MessageImageRenderer {
imageView.layoutParams.height = finalHeight
imageView.layoutParams.width = finalWidth

val resolvedUrl = ContentUrlResolver.resolve(messageContent.url) ?: return
val contentUrlResolver = Matrix.getInstance().currentSession.contentUrlResolver()
val resolvedUrl = contentUrlResolver.resolveThumbnail(
messageContent.url,
finalWidth,
finalHeight,
ContentUrlResolver.ThumbnailMethod.SCALE
) ?: return

GlideApp
.with(imageView)
.load(resolvedUrl)
.override(finalWidth, finalHeight)
.thumbnail(0.3f)
.into(imageView)
}


View File

@ -1,7 +1,7 @@
package im.vector.matrix.android.api

import androidx.lifecycle.ProcessLifecycleOwner
import android.content.Context
import androidx.lifecycle.ProcessLifecycleOwner
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.auth.Authenticator
import im.vector.matrix.android.api.session.Session

View File

@ -2,6 +2,7 @@ package im.vector.matrix.android.api.session

import androidx.annotation.MainThread
import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.matrix.android.api.session.group.GroupService
import im.vector.matrix.android.api.session.room.RoomService

@ -15,6 +16,8 @@ interface Session : RoomService, GroupService {
@MainThread
fun close()

fun contentUrlResolver(): ContentUrlResolver

fun addListener(listener: Listener)

fun removeListener(listener: Listener)

View File

@ -1,9 +1,32 @@
/*
*
* * 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.matrix.android.api.session.content

object ContentUrlResolver {
/**
* This interface defines methods for accessing content from the current session.
*/
interface ContentUrlResolver {

private const val MATRIX_CONTENT_URI_SCHEME = "mxc://"
private const val MEDIA_URL = "https://matrix.org/_matrix/media/v1/download/"
enum class ThumbnailMethod(val value: String) {
CROP("crop"),
SCALE("scale")
}

/**
* Get the actual URL for accessing the full-size image of a Matrix media content URI.
@ -11,21 +34,16 @@ object ContentUrlResolver {
* @param contentUrl the Matrix media content URI (in the form of "mxc://...").
* @return the URL to access the described resource, or null if the url is invalid.
*/
fun resolve(contentUrl: String?): String? {
if (contentUrl.isValidMatrixContentUrl()) {
return contentUrl?.replace(MATRIX_CONTENT_URI_SCHEME, MEDIA_URL)
}
return null
}
fun resolveFullSize(contentUrl: String?): String?

/**
* Check whether an url is a valid matrix content url.
* Get the actual URL for accessing the thumbnail image of a given Matrix media content URI.
*
* @param contentUrl the content URL (in the form of "mxc://...").
* @return true if contentUrl is valid.
* @param contentUrl the Matrix media content URI (in the form of "mxc://...").
* @param width the desired width
* @param height the desired height
* @param method the desired method (METHOD_CROP or METHOD_SCALE)
* @return the URL to access the described resource, or null if the url is invalid.
*/
private fun String?.isValidMatrixContentUrl(): Boolean {
return !this.isNullOrEmpty() && startsWith(MATRIX_CONTENT_URI_SCHEME)
}

fun resolveThumbnail(contentUrl: String?, width: Int, height: Int, method: ThumbnailMethod): String?
}

View File

@ -1,10 +1,11 @@
package im.vector.matrix.android.internal.session

import androidx.lifecycle.LiveData
import android.os.Looper
import androidx.annotation.MainThread
import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.matrix.android.api.session.group.Group
import im.vector.matrix.android.api.session.group.GroupService
import im.vector.matrix.android.api.session.group.model.GroupSummary
@ -35,6 +36,7 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
private val roomService by inject<RoomService>()
private val groupService by inject<GroupService>()
private val syncThread by inject<SyncThread>()
private val contentUrlResolver by inject<ContentUrlResolver>()
private var isOpen = false

@MainThread
@ -63,6 +65,10 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
isOpen = false
}

override fun contentUrlResolver(): ContentUrlResolver {
return contentUrlResolver
}

override fun addListener(listener: Session.Listener) {
sessionListeners.addListener(listener)
}

View File

@ -3,9 +3,11 @@ package im.vector.matrix.android.internal.session
import android.content.Context
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.matrix.android.api.session.group.GroupService
import im.vector.matrix.android.api.session.room.RoomService
import im.vector.matrix.android.internal.database.LiveEntityObserver
import im.vector.matrix.android.internal.session.content.DefaultContentUrlResolver
import im.vector.matrix.android.internal.session.group.DefaultGroupService
import im.vector.matrix.android.internal.session.group.GroupSummaryUpdater
import im.vector.matrix.android.internal.session.room.DefaultRoomService
@ -78,6 +80,10 @@ internal class SessionModule(private val sessionParams: SessionParams) {
SessionListeners()
}

scope(DefaultSession.SCOPE) {
DefaultContentUrlResolver(sessionParams.homeServerConnectionConfig) as ContentUrlResolver
}

scope(DefaultSession.SCOPE) {
val roomSummaryUpdater = RoomSummaryUpdater(get(), get(), get(), get(), sessionParams.credentials)
val groupSummaryUpdater = GroupSummaryUpdater(get())

View File

@ -0,0 +1,69 @@
/*
*
* * 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.matrix.android.internal.session.content

import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.session.content.ContentUrlResolver


private const val MATRIX_CONTENT_URI_SCHEME = "mxc://"
private const val URI_PREFIX_CONTENT_API = "/_matrix/media/v1/"

internal class DefaultContentUrlResolver(private val homeServerConnectionConfig: HomeServerConnectionConfig) : ContentUrlResolver {

override fun resolveFullSize(contentUrl: String?): String? {
if (contentUrl?.isValidMatrixContentUrl() == true) {
val baseUrl = homeServerConnectionConfig.homeServerUri.toString()
val prefix = URI_PREFIX_CONTENT_API + "download/"
return resolve(baseUrl, contentUrl, prefix)
}
return null
}

override fun resolveThumbnail(contentUrl: String?, width: Int, height: Int, method: ContentUrlResolver.ThumbnailMethod): String? {
if (contentUrl?.isValidMatrixContentUrl() == true) {
val baseUrl = homeServerConnectionConfig.homeServerUri.toString()
val prefix = URI_PREFIX_CONTENT_API + "thumbnail/"
val params = "?width=$width&height=$height&method=${method.value}"
return resolve(baseUrl, contentUrl, prefix, params)
}
// do not allow non-mxc content URLs
return null
}

private fun resolve(baseUrl: String,
contentUrl: String,
prefix: String,
params: String? = null): String? {

var serverAndMediaId = contentUrl.removePrefix(MATRIX_CONTENT_URI_SCHEME)
val fragmentOffset = serverAndMediaId.indexOf("#")
var fragment = ""
if (fragmentOffset >= 0) {
fragment = serverAndMediaId.substring(fragmentOffset)
serverAndMediaId = serverAndMediaId.substring(0, fragmentOffset)
}
return baseUrl + prefix + serverAndMediaId + (params ?: "") + fragment
}

private fun String.isValidMatrixContentUrl(): Boolean {
return startsWith(MATRIX_CONTENT_URI_SCHEME)
}

}