From 48fa9e1a5e83469058eb69de6492da4a8a1cde95 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 21 Jun 2021 17:57:47 +0200 Subject: [PATCH] Clean after benoits review --- .../java/im/vector/app/AppStateHandler.kt | 15 +++-- .../java/im/vector/app/VectorApplication.kt | 3 + .../app/features/home/HomeDetailViewModel.kt | 3 +- .../room/list/GroupRoomListSectionBuilder.kt | 7 ++- .../room/list/SpaceRoomListSectionBuilder.kt | 7 ++- .../app/features/invite/AutoAcceptInvites.kt | 18 +++++- .../app/features/invite/InvitesAcceptor.kt | 58 +++++++++++++++++-- 7 files changed, 89 insertions(+), 22 deletions(-) diff --git a/vector/src/main/java/im/vector/app/AppStateHandler.kt b/vector/src/main/java/im/vector/app/AppStateHandler.kt index 3822bd6c08..06174b9573 100644 --- a/vector/src/main/java/im/vector/app/AppStateHandler.kt +++ b/vector/src/main/java/im/vector/app/AppStateHandler.kt @@ -22,7 +22,6 @@ import androidx.lifecycle.OnLifecycleEvent import arrow.core.Option import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.utils.BehaviorDataSource -import im.vector.app.features.invite.InvitesAcceptor import im.vector.app.features.session.coroutineScope import im.vector.app.features.ui.UiStateRepository import io.reactivex.disposables.CompositeDisposable @@ -52,8 +51,7 @@ fun RoomGroupingMethod.group() = (this as? RoomGroupingMethod.ByLegacyGroup)?.gr class AppStateHandler @Inject constructor( private val sessionDataSource: ActiveSessionDataSource, private val uiStateRepository: UiStateRepository, - private val activeSessionHolder: ActiveSessionHolder, - private val invitesAcceptor: InvitesAcceptor + private val activeSessionHolder: ActiveSessionHolder ) : LifecycleObserver { private val compositeDisposable = CompositeDisposable() @@ -63,10 +61,6 @@ class AppStateHandler @Inject constructor( fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? = selectedSpaceDataSource.currentValue?.orNull() - init { - observeActiveSession() - } - fun setCurrentSpace(spaceId: String?, session: Session? = null) { val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.BySpace @@ -103,7 +97,6 @@ class AppStateHandler @Inject constructor( .subscribe { // sessionDataSource could already return a session while activeSession holder still returns null it.orNull()?.let { session -> - invitesAcceptor.onSessionActive(session) if (uiStateRepository.isGroupingMethodSpace(session.sessionId)) { setCurrentSpace(uiStateRepository.getSelectedSpace(session.sessionId), session) } else { @@ -123,8 +116,14 @@ class AppStateHandler @Inject constructor( return (selectedSpaceDataSource.currentValue?.orNull() as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId } + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + fun entersForeground() { + observeActiveSession() + } + @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun entersBackground() { + compositeDisposable.clear() val session = activeSessionHolder.getSafeActiveSession() ?: return when (val currentMethod = selectedSpaceDataSource.currentValue?.orNull() ?: RoomGroupingMethod.BySpace(null)) { is RoomGroupingMethod.BySpace -> { diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index f3e2f8740e..4791c2e499 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -47,6 +47,7 @@ import im.vector.app.core.rx.RxConfig import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.configuration.VectorConfiguration import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog +import im.vector.app.features.invite.InvitesAcceptor import im.vector.app.features.lifecycle.VectorActivityLifecycleCallbacks import im.vector.app.features.notifications.NotificationDrawerManager import im.vector.app.features.notifications.NotificationUtils @@ -95,6 +96,7 @@ class VectorApplication : @Inject lateinit var popupAlertManager: PopupAlertManager @Inject lateinit var pinLocker: PinLocker @Inject lateinit var callManager: WebRtcCallManager + @Inject lateinit var invitesAcceptor: InvitesAcceptor lateinit var vectorComponent: VectorComponent @@ -116,6 +118,7 @@ class VectorApplication : appContext = this vectorComponent = DaggerVectorComponent.factory().create(this) vectorComponent.inject(this) + invitesAcceptor.initialize() vectorUncaughtExceptionHandler.activate(this) rxConfig.setupRxPlugin() diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt index 3614b345c6..b960402f90 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt @@ -32,6 +32,7 @@ import im.vector.app.features.call.lookup.CallProtocolsChecker import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.createdirect.DirectRoomHelper import im.vector.app.features.invite.AutoAcceptInvites +import im.vector.app.features.invite.showInvites import im.vector.app.features.ui.UiStateRepository import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.Dispatchers @@ -208,7 +209,7 @@ private val autoAcceptInvites: AutoAcceptInvites) val activeSpaceRoomId = groupingMethod.spaceSummary?.roomId var dmInvites = 0 var roomsInvite = 0 - if (!autoAcceptInvites.hideInvites) { + if (autoAcceptInvites.showInvites()) { dmInvites = session.getRoomSummaries( roomSummaryQueryParams { memberships = listOf(Membership.INVITE) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt index a23251510f..106a02cd3c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt @@ -23,6 +23,7 @@ import im.vector.app.RoomGroupingMethod import im.vector.app.core.resources.StringProvider import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.invite.AutoAcceptInvites +import im.vector.app.features.invite.showInvites import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.CoroutineScope @@ -75,7 +76,7 @@ class GroupRoomListSectionBuilder( ) } RoomListDisplayMode.NOTIFICATIONS -> { - if (!autoAcceptInvites.hideInvites) { + if (autoAcceptInvites.showInvites()) { addSection( sections, activeGroupAwareQueries, @@ -118,7 +119,7 @@ class GroupRoomListSectionBuilder( private fun buildRoomsSections(sections: MutableList, activeSpaceAwareQueries: MutableList, actualGroupId: String?) { - if (!autoAcceptInvites.hideInvites) { + if (autoAcceptInvites.showInvites()) { addSection( sections, activeSpaceAwareQueries, @@ -185,7 +186,7 @@ class GroupRoomListSectionBuilder( activeSpaceAwareQueries: MutableList, actualGroupId: String? ) { - if (!autoAcceptInvites.hideInvites) { + if (autoAcceptInvites.showInvites()) { addSection(sections, activeSpaceAwareQueries, R.string.invitations_header, diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt index 7d3816af26..5a296ce7ed 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt @@ -27,6 +27,7 @@ import im.vector.app.R import im.vector.app.core.resources.StringProvider import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.invite.AutoAcceptInvites +import im.vector.app.features.invite.showInvites import im.vector.app.space import io.reactivex.Observable import io.reactivex.disposables.Disposable @@ -90,7 +91,7 @@ class SpaceRoomListSectionBuilder( ) } RoomListDisplayMode.NOTIFICATIONS -> { - if (!autoAcceptInvites.hideInvites) { + if (autoAcceptInvites.showInvites()) { addSection( sections = sections, activeSpaceUpdaters = activeSpaceAwareQueries, @@ -140,7 +141,7 @@ class SpaceRoomListSectionBuilder( } private fun buildRoomsSections(sections: MutableList, activeSpaceAwareQueries: MutableList) { - if (!autoAcceptInvites.hideInvites) { + if (autoAcceptInvites.showInvites()) { addSection( sections = sections, activeSpaceUpdaters = activeSpaceAwareQueries, @@ -259,7 +260,7 @@ class SpaceRoomListSectionBuilder( } private fun buildDmSections(sections: MutableList, activeSpaceAwareQueries: MutableList) { - if (!autoAcceptInvites.hideInvites) { + if (autoAcceptInvites.showInvites()) { addSection(sections = sections, activeSpaceUpdaters = activeSpaceAwareQueries, nameRes = R.string.invitations_header, diff --git a/vector/src/main/java/im/vector/app/features/invite/AutoAcceptInvites.kt b/vector/src/main/java/im/vector/app/features/invite/AutoAcceptInvites.kt index 4f39ee0925..87febb37bc 100644 --- a/vector/src/main/java/im/vector/app/features/invite/AutoAcceptInvites.kt +++ b/vector/src/main/java/im/vector/app/features/invite/AutoAcceptInvites.kt @@ -18,12 +18,28 @@ package im.vector.app.features.invite import javax.inject.Inject +/** + * This interface defines 2 flags so you can handle auto accept invites. + * At the moment we only have [CompileTimeAutoAcceptInvites] implementation. + */ interface AutoAcceptInvites { + /** + * Enable auto-accept invites. It means, as soon as you got an invite from the sync, it will try to join it. + */ val isEnabled: Boolean + + /** + * Hide invites from the UI (from notifications, notification count and room list). By default invites are hidden when [isEnabled] is true + */ val hideInvites: Boolean + get() = isEnabled } +fun AutoAcceptInvites.showInvites() = !hideInvites + +/** + * Simple compile time implementation of AutoAcceptInvites flags. + */ class CompileTimeAutoAcceptInvites @Inject constructor() : AutoAcceptInvites { override val isEnabled = false - override val hideInvites = isEnabled } diff --git a/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt b/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt index f084eb9bb4..6e7de1c35b 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt @@ -16,6 +16,7 @@ package im.vector.app.features.invite +import im.vector.app.ActiveSessionDataSource import im.vector.app.features.session.coroutineScope import io.reactivex.Observable import io.reactivex.disposables.Disposable @@ -23,7 +24,10 @@ import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams @@ -39,16 +43,35 @@ import javax.inject.Singleton * This mechanism will be on only if AutoAcceptInvites.isEnabled is true. */ @Singleton -class InvitesAcceptor @Inject constructor(private val autoAcceptInvites: AutoAcceptInvites) : Session.Listener { +class InvitesAcceptor @Inject constructor( + private val sessionDataSource: ActiveSessionDataSource, + private val autoAcceptInvites: AutoAcceptInvites +) : Session.Listener { - private val disposables = HashMap() + private lateinit var activeSessionDisposable: Disposable + private val shouldRejectRoomIds = mutableSetOf() + private val invitedRoomDisposables = HashMap() private val semaphore = Semaphore(1) - fun onSessionActive(session: Session) { + fun initialize() { + observeActiveSession() + } + + private fun observeActiveSession() { + activeSessionDisposable = sessionDataSource.observe() + .distinctUntilChanged() + .subscribe { + it.orNull()?.let { session -> + onSessionActive(session) + } + } + } + + private fun onSessionActive(session: Session) { if (!autoAcceptInvites.isEnabled) { return } - if (disposables.containsKey(session.sessionId)) { + if (invitedRoomDisposables.containsKey(session.sessionId)) { return } session.addListener(this) @@ -74,11 +97,15 @@ class InvitesAcceptor @Inject constructor(private val autoAcceptInvites: AutoAcc } } .also { - disposables[session.sessionId] = it + invitedRoomDisposables[session.sessionId] = it } } private suspend fun Session.joinRoomSafely(roomId: String) { + if (shouldRejectRoomIds.contains(roomId)) { + getRoom(roomId)?.rejectInviteSafely() + return + } val roomMembershipChanged = getChangeMemberships(roomId) if (roomMembershipChanged != ChangeMembershipState.Joined && !roomMembershipChanged.isInProgress()) { try { @@ -86,12 +113,31 @@ class InvitesAcceptor @Inject constructor(private val autoAcceptInvites: AutoAcc joinRoom(roomId) } catch (failure: Throwable) { Timber.v("Failed auto join room: $roomId") + // if we got 404 on invites, the inviting user have left or the hs is off. + if (failure is Failure.ServerError && failure.httpCode == 404) { + val room = getRoom(roomId) ?: return + val inviterId = room.roomSummary()?.inviterId + // if the inviting user is on the same HS, there can only be one cause: they left, so we try to reject the invite. + if (inviterId?.endsWith(sessionParams.credentials.homeServer.orEmpty()).orFalse()) { + shouldRejectRoomIds.add(roomId) + room.rejectInviteSafely() + } + } } } } + private suspend fun Room.rejectInviteSafely() { + try { + leave(null) + shouldRejectRoomIds.remove(roomId) + } catch (failure: Throwable) { + Timber.v("Fail rejecting invite for room: $roomId") + } + } + override fun onSessionStopped(session: Session) { session.removeListener(this) - disposables.remove(session.sessionId)?.dispose() + invitedRoomDisposables.remove(session.sessionId)?.dispose() } }