Merge pull request #1611 from vector-im/feature/okhttp_for_glide

Feature/okhttp for glide
This commit is contained in:
Benoit Marty 2020-07-10 15:54:31 +02:00 committed by GitHub
commit 4741169cc7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 204 additions and 83 deletions

View file

@ -1,5 +1,6 @@
Useful links:
- https://codelabs.developers.google.com/codelabs/webrtc-web/#0
- http://webrtc.github.io/webrtc-org/native-code/android/
╔════════════════════════════════════════════════╗

View file

@ -33,7 +33,7 @@ data class MatrixConfiguration(
),
/**
* Optional proxy to connect to the matrix servers
* You can create one using for instance Proxy(proxyType, InetSocketAddress(hostname, port)
* You can create one using for instance Proxy(proxyType, InetSocketAddress.createUnresolved(hostname, port)
*/
val proxy: Proxy? = null
) {

View file

@ -47,6 +47,7 @@ import im.vector.matrix.android.api.session.terms.TermsService
import im.vector.matrix.android.api.session.typing.TypingUsersTracker
import im.vector.matrix.android.api.session.user.UserService
import im.vector.matrix.android.api.session.widgets.WidgetService
import okhttp3.OkHttpClient
/**
* This interface defines interactions with a session.
@ -205,6 +206,13 @@ interface Session :
*/
fun removeListener(listener: Listener)
/**
* Will return a OkHttpClient which will manage pinned certificates and Proxy if configured.
* It will not add any access-token to the request.
* So it is exposed to let the app be able to download image with Glide or any other libraries which accept an OkHttp client.
*/
fun getOkHttpClient(): OkHttpClient
/**
* A global session listener to get notified for some events.
*/

View file

@ -52,6 +52,7 @@ import im.vector.matrix.android.internal.auth.SessionParamsStore
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.UnauthenticatedWithCertificate
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.session.identity.DefaultIdentityService
import im.vector.matrix.android.internal.session.room.timeline.TimelineEventDecryptor
@ -64,6 +65,7 @@ import im.vector.matrix.android.internal.util.createUIHandler
import io.realm.RealmConfiguration
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@ -113,8 +115,10 @@ internal class DefaultSession @Inject constructor(
private val defaultIdentityService: DefaultIdentityService,
private val integrationManagerService: IntegrationManagerService,
private val taskExecutor: TaskExecutor,
private val callSignalingService: Lazy<CallSignalingService>)
: Session,
private val callSignalingService: Lazy<CallSignalingService>,
@UnauthenticatedWithCertificate
private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient>
) : Session,
RoomService by roomService.get(),
RoomDirectoryService by roomDirectoryService.get(),
GroupService by groupService.get(),
@ -255,6 +259,10 @@ internal class DefaultSession @Inject constructor(
override fun callSignalingService(): CallSignalingService = callSignalingService.get()
override fun getOkHttpClient(): OkHttpClient {
return unauthenticatedWithCertificateOkHttpClient.get()
}
override fun addListener(listener: Session.Listener) {
sessionListeners.addListener(listener)
}

View file

@ -22,7 +22,7 @@ import javax.inject.Inject
internal class SessionListeners @Inject constructor() {
private val listeners = ArrayList<Session.Listener>()
private val listeners = mutableSetOf<Session.Listener>()
fun addListener(listener: Session.Listener) {
synchronized(listeners) {

View file

@ -32,8 +32,6 @@ import com.airbnb.epoxy.EpoxyAsyncUtil
import com.airbnb.epoxy.EpoxyController
import com.facebook.stetho.Stetho
import com.gabrielittner.threetenbp.LazyThreeTen
import com.github.piasy.biv.BigImageViewer
import com.github.piasy.biv.loader.glide.GlideImageLoader
import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.MatrixConfiguration
import im.vector.matrix.android.api.auth.AuthenticationService
@ -44,15 +42,12 @@ import im.vector.riotx.core.di.HasVectorInjector
import im.vector.riotx.core.di.VectorComponent
import im.vector.riotx.core.extensions.configureAndStart
import im.vector.riotx.core.rx.RxConfig
import im.vector.riotx.features.call.WebRtcPeerConnectionManager
import im.vector.riotx.features.configuration.VectorConfiguration
import im.vector.riotx.features.lifecycle.VectorActivityLifecycleCallbacks
import im.vector.riotx.features.notifications.NotificationDrawerManager
import im.vector.riotx.features.notifications.NotificationUtils
import im.vector.riotx.features.notifications.PushRuleTriggerListener
import im.vector.riotx.features.popup.PopupAlertManager
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
import im.vector.riotx.features.session.SessionListener
import im.vector.riotx.features.settings.VectorPreferences
import im.vector.riotx.features.version.VersionProvider
import im.vector.riotx.push.fcm.FcmHelper
@ -79,16 +74,13 @@ class VectorApplication :
@Inject lateinit var emojiCompatWrapper: EmojiCompatWrapper
@Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
@Inject lateinit var sessionListener: SessionListener
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
@Inject lateinit var pushRuleTriggerListener: PushRuleTriggerListener
@Inject lateinit var vectorPreferences: VectorPreferences
@Inject lateinit var versionProvider: VersionProvider
@Inject lateinit var notificationUtils: NotificationUtils
@Inject lateinit var appStateHandler: AppStateHandler
@Inject lateinit var rxConfig: RxConfig
@Inject lateinit var popupAlertManager: PopupAlertManager
@Inject lateinit var webRtcPeerConnectionManager: WebRtcPeerConnectionManager
lateinit var vectorComponent: VectorComponent
@ -114,7 +106,6 @@ class VectorApplication :
logInfo()
LazyThreeTen.init(this)
BigImageViewer.initialize(GlideImageLoader.with(applicationContext))
EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
registerActivityLifecycleCallbacks(VectorActivityLifecycleCallbacks(popupAlertManager))
@ -137,8 +128,7 @@ class VectorApplication :
if (authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!!
activeSessionHolder.setActiveSession(lastAuthenticatedSession)
lastAuthenticatedSession.configureAndStart(applicationContext, pushRuleTriggerListener, sessionListener)
lastAuthenticatedSession.callSignalingService().addCallListener(webRtcPeerConnectionManager)
lastAuthenticatedSession.configureAndStart(applicationContext)
}
ProcessLifecycleOwner.get().lifecycle.addObserver(object : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)

View file

@ -20,8 +20,12 @@ import arrow.core.Option
import im.vector.matrix.android.api.auth.AuthenticationService
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.ActiveSessionDataSource
import im.vector.riotx.features.call.WebRtcPeerConnectionManager
import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler
import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler
import im.vector.riotx.features.notifications.PushRuleTriggerListener
import im.vector.riotx.features.session.SessionListener
import timber.log.Timber
import java.util.concurrent.atomic.AtomicReference
import javax.inject.Inject
import javax.inject.Singleton
@ -30,23 +34,42 @@ import javax.inject.Singleton
class ActiveSessionHolder @Inject constructor(private val authenticationService: AuthenticationService,
private val sessionObservableStore: ActiveSessionDataSource,
private val keyRequestHandler: KeyRequestHandler,
private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler
private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler,
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
private val pushRuleTriggerListener: PushRuleTriggerListener,
private val sessionListener: SessionListener,
private val imageManager: ImageManager
) {
private var activeSession: AtomicReference<Session?> = AtomicReference()
fun setActiveSession(session: Session) {
Timber.w("setActiveSession of ${session.myUserId}")
activeSession.set(session)
sessionObservableStore.post(Option.just(session))
keyRequestHandler.start(session)
incomingVerificationRequestHandler.start(session)
session.addListener(sessionListener)
pushRuleTriggerListener.startWithSession(session)
session.callSignalingService().addCallListener(webRtcPeerConnectionManager)
imageManager.onSessionStarted(session)
}
fun clearActiveSession() {
// Do some cleanup first
getSafeActiveSession()?.let {
Timber.w("clearActiveSession of ${it.myUserId}")
it.callSignalingService().removeCallListener(webRtcPeerConnectionManager)
it.removeListener(sessionListener)
}
activeSession.set(null)
sessionObservableStore.post(Option.empty())
keyRequestHandler.stop()
incomingVerificationRequestHandler.stop()
pushRuleTriggerListener.stop()
}
fun hasActiveSession(): Boolean {

View file

@ -0,0 +1,47 @@
/*
* 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.riotx.core.di
import android.content.Context
import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
import com.github.piasy.biv.BigImageViewer
import com.github.piasy.biv.loader.glide.GlideImageLoader
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.ActiveSessionDataSource
import im.vector.riotx.core.glide.FactoryUrl
import java.io.InputStream
import javax.inject.Inject
/**
* This class is used to configure the library we use for images
*/
class ImageManager @Inject constructor(
private val context: Context,
private val activeSessionDataSource: ActiveSessionDataSource
) {
fun onSessionStarted(session: Session) {
// Do this call first
BigImageViewer.initialize(GlideImageLoader.with(context, session.getOkHttpClient()))
val glide = Glide.get(context)
// And this one. FIXME But are losing what BigImageViewer has done to add a Progress listener
glide.registry.replace(GlideUrl::class.java, InputStream::class.java, FactoryUrl(activeSessionDataSource))
}
}

View file

@ -24,20 +24,14 @@ import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.riotx.core.services.VectorSyncService
import im.vector.riotx.features.notifications.PushRuleTriggerListener
import im.vector.riotx.features.session.SessionListener
import timber.log.Timber
fun Session.configureAndStart(context: Context,
pushRuleTriggerListener: PushRuleTriggerListener,
sessionListener: SessionListener) {
fun Session.configureAndStart(context: Context) {
Timber.i("Configure and start session for $myUserId")
open()
addListener(sessionListener)
setFilter(FilterService.FilterPreset.RiotFilter)
Timber.i("Configure and start session for ${this.myUserId}")
startSyncing(context)
refreshPushers()
pushRuleTriggerListener.startWithSession(this)
}
fun Session.startSyncing(context: Context) {

View file

@ -0,0 +1,38 @@
/*
* 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.riotx.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.riotx.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.
}
}

View file

@ -65,7 +65,7 @@ class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolde
private val height: Int)
: DataFetcher<InputStream> {
val client = OkHttpClient()
private val client = activeSessionHolder.getSafeActiveSession()?.getOkHttpClient() ?: OkHttpClient()
override fun getDataClass(): Class<InputStream> {
return InputStream::class.java

View file

@ -36,6 +36,9 @@ open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableD
private val behaviorRelay = createRelay()
val currentValue: T?
get() = behaviorRelay.value
override fun observe(): Observable<T> {
return behaviorRelay.hide().observeOn(AndroidSchedulers.mainThread())
}

View file

@ -22,6 +22,7 @@ import android.os.Build
import androidx.annotation.RequiresApi
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.extensions.tryThis
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.call.CallState
import im.vector.matrix.android.api.session.call.CallsListener
import im.vector.matrix.android.api.session.call.EglUtils
@ -31,7 +32,7 @@ import im.vector.matrix.android.api.session.room.model.call.CallAnswerContent
import im.vector.matrix.android.api.session.room.model.call.CallCandidatesContent
import im.vector.matrix.android.api.session.room.model.call.CallHangupContent
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.ActiveSessionDataSource
import im.vector.riotx.core.services.BluetoothHeadsetReceiver
import im.vector.riotx.core.services.CallService
import im.vector.riotx.core.services.WiredHeadsetStateReceiver
@ -71,9 +72,12 @@ import javax.inject.Singleton
@Singleton
class WebRtcPeerConnectionManager @Inject constructor(
private val context: Context,
private val sessionHolder: ActiveSessionHolder
private val activeSessionDataSource: ActiveSessionDataSource
) : CallsListener {
private val currentSession: Session?
get() = activeSessionDataSource.currentValue?.orNull()
interface CurrentCallListener {
fun onCurrentCallChange(call: MxCall?)
fun onCaptureStateChanged(mgr: WebRtcPeerConnectionManager) {}
@ -288,7 +292,8 @@ class WebRtcPeerConnectionManager @Inject constructor(
}
private fun getTurnServer(callback: ((TurnServerResponse?) -> Unit)) {
sessionHolder.getActiveSession().callSignalingService().getTurnServer(object : MatrixCallback<TurnServerResponse?> {
currentSession?.callSignalingService()
?.getTurnServer(object : MatrixCallback<TurnServerResponse?> {
override fun onSuccess(data: TurnServerResponse?) {
callback(data)
}
@ -310,7 +315,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
currentCall?.mxCall
?.takeIf { it.state is CallState.Connected }
?.let { mxCall ->
val name = sessionHolder.getSafeActiveSession()?.getUser(mxCall.otherUserId)?.getBestName()
val name = currentSession?.getUser(mxCall.otherUserId)?.getBestName()
?: mxCall.roomId
// Start background service with notification
CallService.onPendingCall(
@ -318,7 +323,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
isVideo = mxCall.isVideoCall,
roomName = name,
roomId = mxCall.roomId,
matrixId = sessionHolder.getSafeActiveSession()?.myUserId ?: "",
matrixId = currentSession?.myUserId ?: "",
callId = mxCall.callId)
}
@ -373,14 +378,14 @@ class WebRtcPeerConnectionManager @Inject constructor(
val mxCall = callContext.mxCall
// Update service state
val name = sessionHolder.getSafeActiveSession()?.getUser(mxCall.otherUserId)?.getBestName()
val name = currentSession?.getUser(mxCall.otherUserId)?.getBestName()
?: mxCall.roomId
CallService.onPendingCall(
context = context,
isVideo = mxCall.isVideoCall,
roomName = name,
roomId = mxCall.roomId,
matrixId = sessionHolder.getSafeActiveSession()?.myUserId ?: "",
matrixId = currentSession?.myUserId ?: "",
callId = mxCall.callId
)
executor.execute {
@ -563,14 +568,14 @@ class WebRtcPeerConnectionManager @Inject constructor(
?.let { mxCall ->
// Start background service with notification
val name = sessionHolder.getSafeActiveSession()?.getUser(mxCall.otherUserId)?.getBestName()
val name = currentSession?.getUser(mxCall.otherUserId)?.getBestName()
?: mxCall.otherUserId
CallService.onOnGoingCallBackground(
context = context,
isVideo = mxCall.isVideoCall,
roomName = name,
roomId = mxCall.roomId,
matrixId = sessionHolder.getSafeActiveSession()?.myUserId ?: "",
matrixId = currentSession?.myUserId ?: "",
callId = mxCall.callId
)
}
@ -631,20 +636,20 @@ class WebRtcPeerConnectionManager @Inject constructor(
}
Timber.v("## VOIP startOutgoingCall in room $signalingRoomId to $otherUserId isVideo $isVideoCall")
val createdCall = sessionHolder.getSafeActiveSession()?.callSignalingService()?.createOutgoingCall(signalingRoomId, otherUserId, isVideoCall) ?: return
val createdCall = currentSession?.callSignalingService()?.createOutgoingCall(signalingRoomId, otherUserId, isVideoCall) ?: return
val callContext = CallContext(createdCall)
audioManager.startForCall(createdCall)
currentCall = callContext
val name = sessionHolder.getSafeActiveSession()?.getUser(createdCall.otherUserId)?.getBestName()
val name = currentSession?.getUser(createdCall.otherUserId)?.getBestName()
?: createdCall.otherUserId
CallService.onOutgoingCallRinging(
context = context.applicationContext,
isVideo = createdCall.isVideoCall,
roomName = name,
roomId = createdCall.roomId,
matrixId = sessionHolder.getSafeActiveSession()?.myUserId ?: "",
matrixId = currentSession?.myUserId ?: "",
callId = createdCall.callId)
executor.execute {
@ -693,14 +698,14 @@ class WebRtcPeerConnectionManager @Inject constructor(
}
// Start background service with notification
val name = sessionHolder.getSafeActiveSession()?.getUser(mxCall.otherUserId)?.getBestName()
val name = currentSession?.getUser(mxCall.otherUserId)?.getBestName()
?: mxCall.otherUserId
CallService.onIncomingCallRinging(
context = context,
isVideo = mxCall.isVideoCall,
roomName = name,
roomId = mxCall.roomId,
matrixId = sessionHolder.getSafeActiveSession()?.myUserId ?: "",
matrixId = currentSession?.myUserId ?: "",
callId = mxCall.callId
)
@ -818,14 +823,14 @@ class WebRtcPeerConnectionManager @Inject constructor(
}
val mxCall = call.mxCall
// Update service state
val name = sessionHolder.getSafeActiveSession()?.getUser(mxCall.otherUserId)?.getBestName()
val name = currentSession?.getUser(mxCall.otherUserId)?.getBestName()
?: mxCall.otherUserId
CallService.onPendingCall(
context = context,
isVideo = mxCall.isVideoCall,
roomName = name,
roomId = mxCall.roomId,
matrixId = sessionHolder.getSafeActiveSession()?.myUserId ?: "",
matrixId = currentSession?.myUserId ?: "",
callId = mxCall.callId
)
executor.execute {

View file

@ -65,19 +65,19 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
@UiThread
fun render(context: Context,
glideRequest: GlideRequests,
glideRequests: GlideRequests,
matrixItem: MatrixItem,
target: Target<Drawable>) {
val placeholder = getPlaceholderDrawable(context, matrixItem)
buildGlideRequest(glideRequest, matrixItem.avatarUrl)
buildGlideRequest(glideRequests, matrixItem.avatarUrl)
.placeholder(placeholder)
.into(target)
}
@AnyThread
@Throws
fun shortcutDrawable(context: Context, glideRequest: GlideRequests, matrixItem: MatrixItem, iconSize: Int): Bitmap {
return glideRequest
fun shortcutDrawable(context: Context, glideRequests: GlideRequests, matrixItem: MatrixItem, iconSize: Int): Bitmap {
return glideRequests
.asBitmap()
.apply {
val resolvedUrl = resolvedUrl(matrixItem.avatarUrl)
@ -98,8 +98,8 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
}
@AnyThread
fun getCachedDrawable(glideRequest: GlideRequests, matrixItem: MatrixItem): Drawable {
return buildGlideRequest(glideRequest, matrixItem.avatarUrl)
fun getCachedDrawable(glideRequests: GlideRequests, matrixItem: MatrixItem): Drawable {
return buildGlideRequest(glideRequests, matrixItem.avatarUrl)
.onlyRetrieveFromCache(true)
.submit()
.get()
@ -117,9 +117,9 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
// PRIVATE API *********************************************************************************
private fun buildGlideRequest(glideRequest: GlideRequests, avatarUrl: String?): GlideRequest<Drawable> {
private fun buildGlideRequest(glideRequests: GlideRequests, avatarUrl: String?): GlideRequest<Drawable> {
val resolvedUrl = resolvedUrl(avatarUrl)
return glideRequest
return glideRequests
.load(resolvedUrl)
.apply(RequestOptions.circleCropTransform())
}

View file

@ -40,17 +40,20 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.api.session.widgets.model.WidgetContent
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import im.vector.matrix.android.internal.crypto.model.event.EncryptionEventContent
import im.vector.riotx.ActiveSessionDataSource
import im.vector.riotx.R
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.resources.StringProvider
import timber.log.Timber
import javax.inject.Inject
class NoticeEventFormatter @Inject constructor(private val sessionHolder: ActiveSessionHolder,
class NoticeEventFormatter @Inject constructor(private val activeSessionDataSource: ActiveSessionDataSource,
private val roomHistoryVisibilityFormatter: RoomHistoryVisibilityFormatter,
private val sp: StringProvider) {
private fun Event.isSentByCurrentUser() = senderId != null && senderId == sessionHolder.getSafeActiveSession()?.myUserId
private val currentUserId: String?
get() = activeSessionDataSource.currentValue?.orNull()?.myUserId
private fun Event.isSentByCurrentUser() = senderId != null && senderId == currentUserId
fun format(timelineEvent: TimelineEvent): CharSequence? {
return when (val type = timelineEvent.root.getClearType()) {
@ -449,7 +452,6 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
val targetDisplayName = eventContent?.displayName ?: prevEventContent?.displayName ?: event.stateKey ?: ""
return when (eventContent?.membership) {
Membership.INVITE -> {
val selfUserId = sessionHolder.getSafeActiveSession()?.myUserId
when {
eventContent.thirdPartyInvite != null -> {
val userWhoHasAccepted = eventContent.thirdPartyInvite?.signed?.mxid ?: event.stateKey
@ -466,7 +468,7 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
sp.getString(R.string.notice_room_third_party_registered_invite, userWhoHasAccepted, threePidDisplayName)
}
}
event.stateKey == selfUserId ->
event.stateKey == currentUserId ->
eventContent.safeReason?.let { reason ->
sp.getString(R.string.notice_room_invite_you_with_reason, senderDisplayName, reason)
} ?: sp.getString(R.string.notice_room_invite_you, senderDisplayName)

View file

@ -49,9 +49,6 @@ import im.vector.riotx.core.extensions.exhaustive
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.ensureTrailingSlash
import im.vector.riotx.features.call.WebRtcPeerConnectionManager
import im.vector.riotx.features.notifications.PushRuleTriggerListener
import im.vector.riotx.features.session.SessionListener
import im.vector.riotx.features.signout.soft.SoftLogoutActivity
import timber.log.Timber
import java.util.concurrent.CancellationException
@ -64,13 +61,10 @@ class LoginViewModel @AssistedInject constructor(
private val applicationContext: Context,
private val authenticationService: AuthenticationService,
private val activeSessionHolder: ActiveSessionHolder,
private val pushRuleTriggerListener: PushRuleTriggerListener,
private val homeServerConnectionConfigFactory: HomeServerConnectionConfigFactory,
private val sessionListener: SessionListener,
private val reAuthHelper: ReAuthHelper,
private val stringProvider: StringProvider,
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager)
: VectorViewModel<LoginViewState, LoginAction, LoginViewEvents>(initialState) {
private val stringProvider: StringProvider
) : VectorViewModel<LoginViewState, LoginAction, LoginViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
@ -667,8 +661,7 @@ class LoginViewModel @AssistedInject constructor(
private fun onSessionCreated(session: Session) {
activeSessionHolder.setActiveSession(session)
session.configureAndStart(applicationContext, pushRuleTriggerListener, sessionListener)
session.callSignalingService().addCallListener(webRtcPeerConnectionManager)
session.configureAndStart(applicationContext)
setState {
copy(
asyncLoginAction = Success(Unit)

View file

@ -22,10 +22,11 @@ import android.os.HandlerThread
import androidx.annotation.WorkerThread
import androidx.core.app.NotificationCompat
import androidx.core.app.Person
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.riotx.ActiveSessionDataSource
import im.vector.riotx.BuildConfig
import im.vector.riotx.R
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.settings.VectorPreferences
import me.gujun.android.span.span
@ -46,7 +47,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
private val notificationUtils: NotificationUtils,
private val vectorPreferences: VectorPreferences,
private val stringProvider: StringProvider,
private val activeSessionHolder: ActiveSessionHolder,
private val activeSessionDataSource: ActiveSessionDataSource,
private val iconLoader: IconLoader,
private val bitmapLoader: BitmapLoader,
private val outdatedDetector: OutdatedEventDetector?) {
@ -68,6 +69,10 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
private var currentRoomId: String? = null
// TODO Multi-session: this will have to be improved
private val currentSession: Session?
get() = activeSessionDataSource.currentValue?.orNull()
/**
Should be called as soon as a new event is ready to be displayed.
The notification corresponding to this event will not be displayed until
@ -204,7 +209,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
private fun refreshNotificationDrawerBg() {
Timber.v("refreshNotificationDrawerBg()")
val session = activeSessionHolder.getSafeActiveSession() ?: return
val session = currentSession ?: return
val user = session.getUser(session.myUserId)
// myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash
@ -474,7 +479,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
if (!file.exists()) file.createNewFile()
FileOutputStream(file).use {
activeSessionHolder.getSafeActiveSession()?.securelyStoreObject(eventList, KEY_ALIAS_SECRET_STORAGE, it)
currentSession?.securelyStoreObject(eventList, KEY_ALIAS_SECRET_STORAGE, it)
}
} catch (e: Throwable) {
Timber.e(e, "## Failed to save cached notification info")
@ -487,7 +492,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
if (file.exists()) {
FileInputStream(file).use {
val events: ArrayList<NotifiableEvent>? = activeSessionHolder.getSafeActiveSession()?.loadSecureSecret(it, KEY_ALIAS_SECRET_STORAGE)
val events: ArrayList<NotifiableEvent>? = currentSession?.loadSecureSecret(it, KEY_ALIAS_SECRET_STORAGE)
if (events != null) {
return events.toMutableList()
}

View file

@ -15,10 +15,12 @@
*/
package im.vector.riotx.features.notifications
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.ActiveSessionDataSource
import javax.inject.Inject
class OutdatedEventDetector @Inject constructor(private val activeSessionHolder: ActiveSessionHolder) {
class OutdatedEventDetector @Inject constructor(
private val activeSessionDataSource: ActiveSessionDataSource
) {
/**
* Returns true if the given event is outdated.
@ -26,10 +28,12 @@ class OutdatedEventDetector @Inject constructor(private val activeSessionHolder:
* other device.
*/
fun isMessageOutdated(notifiableEvent: NotifiableEvent): Boolean {
val session = activeSessionDataSource.currentValue?.orNull() ?: return false
if (notifiableEvent is NotifiableMessageEvent) {
val eventID = notifiableEvent.eventId
val roomID = notifiableEvent.roomId
val room = activeSessionHolder.getSafeActiveSession()?.getRoom(roomID) ?: return false
val room = session.getRoom(roomID) ?: return false
return room.isEventRead(eventID)
}
return false

View file

@ -30,17 +30,17 @@ class PushRuleTriggerListener @Inject constructor(
private val notificationDrawerManager: NotificationDrawerManager
) : PushRuleService.PushRuleListener {
var session: Session? = null
private var session: Session? = null
override fun onMatchRule(event: Event, actions: List<Action>) {
Timber.v("Push rule match for event ${event.eventId}")
if (session == null) {
val safeSession = session ?: return Unit.also {
Timber.e("Called without active session")
return
}
val notificationAction = actions.toNotificationAction()
if (notificationAction.shouldNotify) {
val notifiableEvent = resolver.resolveEvent(event, session!!)
val notifiableEvent = resolver.resolveEvent(event, safeSession)
if (notifiableEvent == null) {
Timber.v("## Failed to resolve event")
// TODO