From 8efd389a3cf5f2686331fafea171a35fcd53fce5 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Wed, 9 Mar 2022 13:40:05 +0100 Subject: [PATCH 001/168] Fix a case of missing read markers Case: bottom-most loaded event has read marker, but there are messages below it that haven't been loaded yet. --- .../app/features/home/room/detail/TimelineViewModel.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index 3bdcbc6529..07c25ce326 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -1120,6 +1120,11 @@ class TimelineViewModel @AssistedInject constructor( } else { UnreadState.Unknown } + // If the read marker is at the bottom-most event, this doesn't mean we read all, in case we just haven't loaded more events. + // Avoid incorrectly returning HasNoUnread in this case. + if (firstDisplayableEventIndex == 0 && timeline.hasMoreToLoad(Timeline.Direction.FORWARDS)) { + return UnreadState.Unknown + } for (i in (firstDisplayableEventIndex - 1) downTo 0) { val timelineEvent = events.getOrNull(i) ?: return UnreadState.Unknown val eventId = timelineEvent.root.eventId ?: return UnreadState.Unknown From 1206c31e3ab01501b02953b28140bd25c65017ee Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Wed, 9 Mar 2022 13:43:52 +0100 Subject: [PATCH 002/168] Fix another case of missing read markers HasUnread might not be correct on the first try while loading the timeline. --- .../vector/app/features/home/room/detail/TimelineViewModel.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index 07c25ce326..78e3469a58 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -1099,9 +1099,11 @@ class TimelineViewModel @AssistedInject constructor( computeUnreadState(timelineEvents, roomSummary) } // We don't want live update of unread so we skip when we already had a HasUnread or HasNoUnread + // However, we want to update an existing HasUnread, as we might get additional information during loading of events. .distinctUntilChanged { previous, current -> when { previous is UnreadState.Unknown || previous is UnreadState.ReadMarkerNotLoaded -> false + previous is UnreadState.HasUnread && current is UnreadState.HasUnread -> false current is UnreadState.HasUnread || current is UnreadState.HasNoUnread -> true else -> false } From 884ae1cedd8144e470a1055019d55a4c9eeb7c85 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Wed, 9 Mar 2022 13:50:49 +0100 Subject: [PATCH 003/168] Add changelog.d/5475.bugfix --- changelog.d/5475.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5475.bugfix diff --git a/changelog.d/5475.bugfix b/changelog.d/5475.bugfix new file mode 100644 index 0000000000..03364f6a73 --- /dev/null +++ b/changelog.d/5475.bugfix @@ -0,0 +1 @@ +Fix some cases where the read marker line would not show up From 682f4c35d2956efe1e1827ee6834466494ca4b71 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Wed, 16 Mar 2022 13:39:19 +0100 Subject: [PATCH 004/168] Fix endless loading timeline due to conflicting chunks --- changelog.d/5554.bugfix | 1 + .../database/query/ChunkEntityQueries.kt | 11 ++++++++++ .../room/timeline/TokenChunkEventPersistor.kt | 22 ++++++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 changelog.d/5554.bugfix diff --git a/changelog.d/5554.bugfix b/changelog.d/5554.bugfix new file mode 100644 index 0000000000..ee69f0dbfe --- /dev/null +++ b/changelog.d/5554.bugfix @@ -0,0 +1 @@ +Fix sometimes endless loading timeline diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt index ece46555a7..a33ba82f7a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt @@ -40,6 +40,17 @@ internal fun ChunkEntity.Companion.find(realm: Realm, roomId: String, prevToken: return query.findFirst() } +internal fun ChunkEntity.Companion.findAll(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): RealmResults? { + val query = where(realm, roomId) + if (prevToken != null) { + query.equalTo(ChunkEntityFields.PREV_TOKEN, prevToken) + } + if (nextToken != null) { + query.equalTo(ChunkEntityFields.NEXT_TOKEN, nextToken) + } + return query.findAll() +} + internal fun ChunkEntity.Companion.findLastForwardChunkOfRoom(realm: Realm, roomId: String): ChunkEntity? { return where(realm, roomId) .equalTo(ChunkEntityFields.IS_LAST_FORWARD, true) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt index 63383a99b3..874915a6f0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -38,6 +38,7 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore import org.matrix.android.sdk.internal.database.query.create import org.matrix.android.sdk.internal.database.query.find +import org.matrix.android.sdk.internal.database.query.findAll import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.UserId @@ -80,7 +81,26 @@ internal class TokenChunkEventPersistor @Inject constructor( val existingChunk = ChunkEntity.find(realm, roomId, prevToken = prevToken, nextToken = nextToken) if (existingChunk != null) { - Timber.v("This chunk is already in the db, returns") + Timber.v("This chunk is already in the db, checking if this might be caused by broken links") + if (direction == PaginationDirection.FORWARDS) { + val prevChunks = ChunkEntity.findAll(realm, roomId, nextToken = prevToken) + Timber.v("Found ${prevChunks?.size} prevChunks") + prevChunks?.forEach { + if (it.nextChunk != existingChunk) { + Timber.i("Set nextChunk for ${it.identifier()} from ${it.nextChunk?.identifier()} to ${existingChunk.identifier()}") + it.nextChunk = existingChunk + } + } + } else { + val nextChunks = ChunkEntity.findAll(realm, roomId, prevToken = nextToken) + Timber.v("Found ${nextChunks?.size} nextChunks") + nextChunks?.forEach { + if (it.prevChunk != existingChunk) { + Timber.i("Set prevChunk for ${it.identifier()} from ${it.prevChunk?.identifier()} to ${existingChunk.identifier()}") + it.prevChunk = existingChunk + } + } + } return@awaitTransaction } val prevChunk = ChunkEntity.find(realm, roomId, nextToken = prevToken) From 6878a973ed48056b4982cea5232ab129f7a49810 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Fri, 18 Mar 2022 07:59:32 +0100 Subject: [PATCH 005/168] TokenChunkEventPersistor: always link all matching chunks The previous fix only works around the issue when it is detected. This may require re-entering the room once when it gets stuck. If we ensure proper linking from the beginning, hopefully we don't run into any issues at all. --- .../session/room/timeline/TokenChunkEventPersistor.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt index 874915a6f0..7aceeb4a49 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -109,8 +109,14 @@ internal class TokenChunkEventPersistor @Inject constructor( this.nextChunk = nextChunk this.prevChunk = prevChunk } - nextChunk?.prevChunk = currentChunk - prevChunk?.nextChunk = currentChunk + val allNextChunks = ChunkEntity.findAll(realm, roomId, prevToken = nextToken) + val allPrevChunks = ChunkEntity.findAll(realm, roomId, nextToken = prevToken) + allNextChunks?.forEach { + it.prevChunk = currentChunk + } + allPrevChunks?.forEach { + it.nextChunk = currentChunk + } if (receivedChunk.events.isEmpty() && !receivedChunk.hasMore()) { handleReachEnd(roomId, direction, currentChunk) } else { From 47dddd706c660c071c8b55e29f2aeb613ef752f3 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Mon, 21 Mar 2022 11:23:03 +0100 Subject: [PATCH 006/168] Only show HasUnread -> HasUnread updates for same readMarker --- .../app/features/home/room/detail/RoomDetailViewState.kt | 2 +- .../app/features/home/room/detail/TimelineViewModel.kt | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt index e2b97b0900..5d545ef4b5 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt @@ -36,7 +36,7 @@ sealed class UnreadState { object Unknown : UnreadState() object HasNoUnread : UnreadState() data class ReadMarkerNotLoaded(val readMarkerId: String) : UnreadState() - data class HasUnread(val firstUnreadEventId: String) : UnreadState() + data class HasUnread(val firstUnreadEventId: String, val readMarkerId: String) : UnreadState() } data class JitsiState( diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index 78e3469a58..4caad1bb5e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -1099,11 +1099,13 @@ class TimelineViewModel @AssistedInject constructor( computeUnreadState(timelineEvents, roomSummary) } // We don't want live update of unread so we skip when we already had a HasUnread or HasNoUnread - // However, we want to update an existing HasUnread, as we might get additional information during loading of events. + // However, we want to update an existing HasUnread, if the readMarkerId hasn't changed, + // as we might be loading new events to fill gaps in the timeline. .distinctUntilChanged { previous, current -> when { previous is UnreadState.Unknown || previous is UnreadState.ReadMarkerNotLoaded -> false - previous is UnreadState.HasUnread && current is UnreadState.HasUnread -> false + previous is UnreadState.HasUnread && current is UnreadState.HasUnread && + previous.readMarkerId == current.readMarkerId -> false current is UnreadState.HasUnread || current is UnreadState.HasNoUnread -> true else -> false } @@ -1132,7 +1134,7 @@ class TimelineViewModel @AssistedInject constructor( val eventId = timelineEvent.root.eventId ?: return UnreadState.Unknown val isFromMe = timelineEvent.root.senderId == session.myUserId if (!isFromMe) { - return UnreadState.HasUnread(eventId) + return UnreadState.HasUnread(eventId, readMarkerIdSnapshot) } } return UnreadState.HasNoUnread From 7e930472e8233e7b26bc4c99748a6dbae6ca69f1 Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 25 Mar 2022 22:51:34 +0000 Subject: [PATCH 007/168] Align with web implementation --- .../sdk/api/session/LiveEventListener.kt | 8 +- .../algorithms/megolm/MXMegolmDecryption.kt | 2 +- .../internal/session/StreamEventsManager.kt | 30 +---- .../room/timeline/TokenChunkEventPersistor.kt | 2 +- .../sync/handler/room/RoomSyncHandler.kt | 1 - .../main/java/im/vector/app/AutoRageShaker.kt | 40 ++++--- .../main/java/im/vector/app/UISIDetector.kt | 105 ++++++------------ 7 files changed, 66 insertions(+), 122 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt index 6fda65953a..65e3e94d2d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt @@ -21,13 +21,9 @@ import org.matrix.android.sdk.api.util.JsonDict interface LiveEventListener { - fun onLiveEvent(roomId: String, event: Event) + fun onEventDecrypted(event: Event) - fun onPaginatedEvent(roomId: String, event: Event) - - fun onEventDecrypted(eventId: String, roomId: String, clearEvent: JsonDict) - - fun onEventDecryptionError(eventId: String, roomId: String, throwable: Throwable) + fun onEventDecryptionError(event: Event, throwable: Throwable) fun onLiveToDeviceEvent(event: Event) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt index e94daa0e76..22180dce86 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt @@ -113,7 +113,7 @@ internal class MXMegolmDecryption(private val userId: String, forwardingCurve25519KeyChain = olmDecryptionResult.forwardingCurve25519KeyChain .orEmpty() ).also { - liveEventManager.get().dispatchLiveEventDecrypted(event, it) + liveEventManager.get().dispatchLiveEventDecrypted(event) } } else { throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt index bb0ca11445..9876e265bf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt @@ -42,36 +42,12 @@ internal class StreamEventsManager @Inject constructor() { listeners.remove(listener) } - fun dispatchLiveEventReceived(event: Event, roomId: String, initialSync: Boolean) { - Timber.v("## dispatchLiveEventReceived ${event.eventId}") - coroutineScope.launch { - if (!initialSync) { - listeners.forEach { - tryOrNull { - it.onLiveEvent(roomId, event) - } - } - } - } - } - - fun dispatchPaginatedEventReceived(event: Event, roomId: String) { - Timber.v("## dispatchPaginatedEventReceived ${event.eventId}") - coroutineScope.launch { - listeners.forEach { - tryOrNull { - it.onPaginatedEvent(roomId, event) - } - } - } - } - - fun dispatchLiveEventDecrypted(event: Event, result: MXEventDecryptionResult) { + fun dispatchLiveEventDecrypted(event: Event) { Timber.v("## dispatchLiveEventDecrypted ${event.eventId}") coroutineScope.launch { listeners.forEach { tryOrNull { - it.onEventDecrypted(event.eventId ?: "", event.roomId ?: "", result.clearEvent) + it.onEventDecrypted(event) } } } @@ -82,7 +58,7 @@ internal class StreamEventsManager @Inject constructor() { coroutineScope.launch { listeners.forEach { tryOrNull { - it.onEventDecryptionError(event.eventId ?: "", event.roomId ?: "", error) + it.onEventDecryptionError(event, error) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt index 63383a99b3..4e940bb445 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -186,7 +186,7 @@ internal class TokenChunkEventPersistor @Inject constructor( } roomMemberContentsByUser[event.stateKey] = contentToUse.toModel() } - liveEventManager.get().dispatchPaginatedEventReceived(event, roomId) + currentChunk.addTimelineEvent( roomId = roomId, eventEntity = eventEntity, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt index 8fe85f0d31..1cb476d03a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt @@ -382,7 +382,6 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle } eventIds.add(event.eventId) - liveEventService.get().dispatchLiveEventReceived(event, roomId, insertType == EventInsertType.INITIAL_SYNC) val isInitialSync = insertType == EventInsertType.INITIAL_SYNC diff --git a/vector/src/main/java/im/vector/app/AutoRageShaker.kt b/vector/src/main/java/im/vector/app/AutoRageShaker.kt index 43283254b1..836e44f57b 100644 --- a/vector/src/main/java/im/vector/app/AutoRageShaker.kt +++ b/vector/src/main/java/im/vector/app/AutoRageShaker.kt @@ -17,23 +17,31 @@ package im.vector.app import android.content.SharedPreferences +import androidx.lifecycle.asFlow import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.features.rageshake.BugReporter import im.vector.app.features.rageshake.ReportType +import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.cancellable import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.subscribe import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.initsync.SyncStatusService +import org.matrix.android.sdk.api.session.sync.SyncState +import org.matrix.android.sdk.flow.flow import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton @@ -62,10 +70,11 @@ class AutoRageShaker @Inject constructor( private val e2eDetectedFlow = MutableSharedFlow(replay = 0) private val matchingRSRequestFlow = MutableSharedFlow(replay = 0) - + var hasSynced = false + var preferenceEnabled = false fun initialize() { observeActiveSession() - enable(vectorPreferences.labsAutoReportUISI()) + preferenceEnabled = vectorPreferences.labsAutoReportUISI() // It's a singleton... vectorPreferences.subscribeToChanges(this) @@ -74,7 +83,7 @@ class AutoRageShaker @Inject constructor( e2eDetectedFlow .onEach { sendRageShake(it) - delay(2_000) + delay(60_000) } .catch { cause -> Timber.w(cause, "Failed to RS") @@ -84,7 +93,7 @@ class AutoRageShaker @Inject constructor( matchingRSRequestFlow .onEach { sendMatchingRageShake(it) - delay(2_000) + delay(60_000) } .catch { cause -> Timber.w(cause, "Failed to send matching rageshake") @@ -93,14 +102,7 @@ class AutoRageShaker @Inject constructor( } override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - enable(vectorPreferences.labsAutoReportUISI()) - } - - var _enabled = false - fun enable(enabled: Boolean) { - if (enabled == _enabled) return - _enabled = enabled - detector.enabled = enabled + preferenceEnabled = vectorPreferences.labsAutoReportUISI() } private fun observeActiveSession() { @@ -115,7 +117,6 @@ class AutoRageShaker @Inject constructor( } fun decryptionErrorDetected(target: E2EMessageDetected) { - if (target.source == UISIEventSource.INITIAL_SYNC) return if (activeSessionHolder.getSafeActiveSession()?.sessionId != currentActiveSessionId) return val shouldSendRS = synchronized(alreadyReportedUisi) { val reportInfo = ReportInfo(target.roomId, target.sessionId) @@ -148,7 +149,6 @@ class AutoRageShaker @Inject constructor( append("\"room_id\": \"${target.roomId}\",") append("\"sender_key\": \"${target.senderKey}\",") append("\"device_id\": \"${target.senderDeviceId}\",") - append("\"source\": \"${target.source}\",") append("\"user_id\": \"${target.senderUserId}\",") append("\"session_id\": \"${target.sessionId}\"") append("}") @@ -245,6 +245,9 @@ class AutoRageShaker @Inject constructor( override val reciprocateToDeviceEventType: String get() = AUTO_RS_REQUEST + override val enabled: Boolean + get() = this@AutoRageShaker.preferenceEnabled && this@AutoRageShaker.hasSynced + override fun uisiDetected(source: E2EMessageDetected) { decryptionErrorDetected(source) } @@ -261,7 +264,14 @@ class AutoRageShaker @Inject constructor( return } this.currentActiveSessionId = sessionId - this.detector.enabled = _enabled + + hasSynced = session.hasAlreadySynced() + session.getSyncStatusLive() + .asFlow() + .onEach { + hasSynced = it !is SyncStatusService.Status.Progressing + } + .launchIn(session.coroutineScope) activeSessionIds.add(sessionId) session.addListener(this) session.addEventStreamListener(detector) diff --git a/vector/src/main/java/im/vector/app/UISIDetector.kt b/vector/src/main/java/im/vector/app/UISIDetector.kt index d6a4805e78..f7c6725bd8 100644 --- a/vector/src/main/java/im/vector/app/UISIDetector.kt +++ b/vector/src/main/java/im/vector/app/UISIDetector.kt @@ -16,6 +16,7 @@ package im.vector.app +import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.LiveEventListener import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toModel @@ -26,23 +27,17 @@ import java.util.Timer import java.util.TimerTask import java.util.concurrent.Executors -enum class UISIEventSource { - INITIAL_SYNC, - INCREMENTAL_SYNC, - PAGINATION -} - data class E2EMessageDetected( val eventId: String, val roomId: String, val senderUserId: String, val senderDeviceId: String, val senderKey: String, - val sessionId: String, - val source: UISIEventSource) { + val sessionId: String + ) { companion object { - fun fromEvent(event: Event, roomId: String, source: UISIEventSource): E2EMessageDetected { + fun fromEvent(event: Event, roomId: String): E2EMessageDetected { val encryptedContent = event.content.toModel() return E2EMessageDetected( @@ -51,8 +46,7 @@ data class E2EMessageDetected( senderUserId = event.senderId ?: "", senderDeviceId = encryptedContent?.deviceId ?: "", senderKey = encryptedContent?.senderKey ?: "", - sessionId = encryptedContent?.sessionId ?: "", - source = source + sessionId = encryptedContent?.sessionId ?: "" ) } } @@ -61,6 +55,7 @@ data class E2EMessageDetected( class UISIDetector : LiveEventListener { interface UISIDetectorCallback { + val enabled: Boolean val reciprocateToDeviceEventType: String fun uisiDetected(source: E2EMessageDetected) fun uisiReciprocateRequest(source: Event) @@ -68,30 +63,16 @@ class UISIDetector : LiveEventListener { var callback: UISIDetectorCallback? = null - private val trackedEvents = mutableListOf>() + private val trackedEvents = mutableMapOf() private val executor = Executors.newSingleThreadExecutor() private val timer = Timer() private val timeoutMillis = 30_000L - var enabled = false + val enabled: Boolean get() = callback?.enabled.orFalse() - override fun onLiveEvent(roomId: String, event: Event) { - if (!enabled) return - if (!event.isEncrypted()) return - executor.execute { - handleEventReceived(E2EMessageDetected.fromEvent(event, roomId, UISIEventSource.INCREMENTAL_SYNC)) - } - } - - override fun onPaginatedEvent(roomId: String, event: Event) { - if (!enabled) return - if (!event.isEncrypted()) return - executor.execute { - handleEventReceived(E2EMessageDetected.fromEvent(event, roomId, UISIEventSource.PAGINATION)) - } - } - - override fun onEventDecrypted(eventId: String, roomId: String, clearEvent: JsonDict) { - if (!enabled) return + override fun onEventDecrypted(event: Event) { + val eventId = event.eventId + val roomId = event.roomId + if (!enabled || eventId == null || roomId == null) return executor.execute { unTrack(eventId, roomId) } @@ -104,57 +85,39 @@ class UISIDetector : LiveEventListener { } } - override fun onEventDecryptionError(eventId: String, roomId: String, throwable: Throwable) { - if (!enabled) return - executor.execute { - unTrack(eventId, roomId)?.let { - triggerUISI(it) - } -// if (throwable is MXCryptoError.OlmError) { -// if (throwable.olmException.message == "UNKNOWN_MESSAGE_INDEX") { -// unTrack(eventId, roomId)?.let { -// triggerUISI(it) -// } -// } -// } - } - } + override fun onEventDecryptionError(event: Event, throwable: Throwable) { + val eventId = event.eventId + val roomId = event.roomId + if (!enabled || eventId == null || roomId == null) return - private fun handleEventReceived(detectorEvent: E2EMessageDetected) { - if (!enabled) return - if (trackedEvents.any { it.first == detectorEvent }) { - Timber.w("## UISIDetector: Event ${detectorEvent.eventId} is already tracked") - } else { - // track it and start timer - val timeoutTask = object : TimerTask() { - override fun run() { - executor.execute { - unTrack(detectorEvent.eventId, detectorEvent.roomId) - Timber.v("## UISIDetector: Timeout on ${detectorEvent.eventId} ") - triggerUISI(detectorEvent) - } + val trackerId: String = trackerId(eventId, roomId) + if (trackedEvents.containsKey(trackerId)) { + Timber.w("## UISIDetector: Event $eventId is already tracked") + return + } + // track it and start timer + val timeoutTask = object : TimerTask() { + override fun run() { + executor.execute { + unTrack(eventId, roomId) + Timber.v("## UISIDetector: Timeout on $eventId") + triggerUISI(E2EMessageDetected.fromEvent(event, roomId)) } } - trackedEvents.add(detectorEvent to timeoutTask) - timer.schedule(timeoutTask, timeoutMillis) } + trackedEvents[trackerId] = timeoutTask + timer.schedule(timeoutTask, timeoutMillis) } + private fun trackerId(eventId: String, roomId: String): String = "$roomId-$eventId" + private fun triggerUISI(source: E2EMessageDetected) { if (!enabled) return Timber.i("## UISIDetector: Unable To Decrypt $source") callback?.uisiDetected(source) } - private fun unTrack(eventId: String, roomId: String): E2EMessageDetected? { - val index = trackedEvents.indexOfFirst { it.first.eventId == eventId && it.first.roomId == roomId } - return if (index != -1) { - trackedEvents.removeAt(index).let { - it.second.cancel() - it.first - } - } else { - null - } + private fun unTrack(eventId: String, roomId: String) { + trackedEvents.remove(trackerId(eventId, roomId))?.cancel() } } From 531b62f634ae2b4b728e7cefce74c97b0adacdda Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 25 Mar 2022 23:00:47 +0000 Subject: [PATCH 008/168] Make properties private --- vector/src/main/java/im/vector/app/AutoRageShaker.kt | 4 ++-- vector/src/main/java/im/vector/app/UISIDetector.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/AutoRageShaker.kt b/vector/src/main/java/im/vector/app/AutoRageShaker.kt index 836e44f57b..b7578f8b89 100644 --- a/vector/src/main/java/im/vector/app/AutoRageShaker.kt +++ b/vector/src/main/java/im/vector/app/AutoRageShaker.kt @@ -70,8 +70,8 @@ class AutoRageShaker @Inject constructor( private val e2eDetectedFlow = MutableSharedFlow(replay = 0) private val matchingRSRequestFlow = MutableSharedFlow(replay = 0) - var hasSynced = false - var preferenceEnabled = false + private var hasSynced = false + private var preferenceEnabled = false fun initialize() { observeActiveSession() preferenceEnabled = vectorPreferences.labsAutoReportUISI() diff --git a/vector/src/main/java/im/vector/app/UISIDetector.kt b/vector/src/main/java/im/vector/app/UISIDetector.kt index f7c6725bd8..0dcc94516f 100644 --- a/vector/src/main/java/im/vector/app/UISIDetector.kt +++ b/vector/src/main/java/im/vector/app/UISIDetector.kt @@ -67,7 +67,7 @@ class UISIDetector : LiveEventListener { private val executor = Executors.newSingleThreadExecutor() private val timer = Timer() private val timeoutMillis = 30_000L - val enabled: Boolean get() = callback?.enabled.orFalse() + private val enabled: Boolean get() = callback?.enabled.orFalse() override fun onEventDecrypted(event: Event) { val eventId = event.eventId From f38bf2548f86efc679cb9bfd5e0b219e91701f0b Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 25 Mar 2022 23:18:45 +0000 Subject: [PATCH 009/168] lint --- .../org/matrix/android/sdk/api/session/LiveEventListener.kt | 1 - .../android/sdk/internal/session/StreamEventsManager.kt | 1 - vector/src/main/java/im/vector/app/AutoRageShaker.kt | 5 ----- vector/src/main/java/im/vector/app/UISIDetector.kt | 1 - 4 files changed, 8 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt index 65e3e94d2d..def3ecbfca 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt @@ -17,7 +17,6 @@ package org.matrix.android.sdk.api.session import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.api.util.JsonDict interface LiveEventListener { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt index 9876e265bf..7c1ca1f630 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt @@ -23,7 +23,6 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.LiveEventListener import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.internal.crypto.MXEventDecryptionResult import timber.log.Timber import javax.inject.Inject diff --git a/vector/src/main/java/im/vector/app/AutoRageShaker.kt b/vector/src/main/java/im/vector/app/AutoRageShaker.kt index b7578f8b89..46390f30b8 100644 --- a/vector/src/main/java/im/vector/app/AutoRageShaker.kt +++ b/vector/src/main/java/im/vector/app/AutoRageShaker.kt @@ -25,23 +25,18 @@ import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.cancellable import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.subscribe import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.initsync.SyncStatusService -import org.matrix.android.sdk.api.session.sync.SyncState -import org.matrix.android.sdk.flow.flow import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton diff --git a/vector/src/main/java/im/vector/app/UISIDetector.kt b/vector/src/main/java/im/vector/app/UISIDetector.kt index 0dcc94516f..2b6974eefb 100644 --- a/vector/src/main/java/im/vector/app/UISIDetector.kt +++ b/vector/src/main/java/im/vector/app/UISIDetector.kt @@ -20,7 +20,6 @@ import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.LiveEventListener import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toModel -import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent import timber.log.Timber import java.util.Timer From 4fe86503879379237231dd4d676b328d9971380a Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 28 Mar 2022 10:07:29 +0100 Subject: [PATCH 010/168] Add changelog --- changelog.d/5596.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5596.bugfix diff --git a/changelog.d/5596.bugfix b/changelog.d/5596.bugfix new file mode 100644 index 0000000000..f51794c352 --- /dev/null +++ b/changelog.d/5596.bugfix @@ -0,0 +1 @@ +Align auto-reporting of decryption errors implementation with web client. \ No newline at end of file From b4885629af493cd5fbe726d0e81dc01cd7d7cb82 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 28 Mar 2022 17:23:05 +0100 Subject: [PATCH 011/168] Keep live event/pagination listeners. --- changelog.d/5639.sdk | 1 + .../sdk/api/session/LiveEventListener.kt | 7 ++++- .../algorithms/megolm/MXMegolmDecryption.kt | 2 +- .../internal/session/StreamEventsManager.kt | 29 +++++++++++++++++-- .../room/timeline/TokenChunkEventPersistor.kt | 2 +- .../sync/handler/room/RoomSyncHandler.kt | 1 + .../main/java/im/vector/app/UISIDetector.kt | 7 ++++- 7 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 changelog.d/5639.sdk diff --git a/changelog.d/5639.sdk b/changelog.d/5639.sdk new file mode 100644 index 0000000000..96b495f809 --- /dev/null +++ b/changelog.d/5639.sdk @@ -0,0 +1 @@ +Include original event in decryption live decryption listeners. \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt index def3ecbfca..b4b283c86a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/LiveEventListener.kt @@ -17,10 +17,15 @@ package org.matrix.android.sdk.api.session import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.util.JsonDict interface LiveEventListener { - fun onEventDecrypted(event: Event) + fun onLiveEvent(roomId: String, event: Event) + + fun onPaginatedEvent(roomId: String, event: Event) + + fun onEventDecrypted(event: Event, clearEvent: JsonDict) fun onEventDecryptionError(event: Event, throwable: Throwable) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt index 22180dce86..e94daa0e76 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt @@ -113,7 +113,7 @@ internal class MXMegolmDecryption(private val userId: String, forwardingCurve25519KeyChain = olmDecryptionResult.forwardingCurve25519KeyChain .orEmpty() ).also { - liveEventManager.get().dispatchLiveEventDecrypted(event) + liveEventManager.get().dispatchLiveEventDecrypted(event, it) } } else { throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt index 7c1ca1f630..8ae9772714 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/StreamEventsManager.kt @@ -23,6 +23,7 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.LiveEventListener import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.internal.crypto.MXEventDecryptionResult import timber.log.Timber import javax.inject.Inject @@ -41,12 +42,36 @@ internal class StreamEventsManager @Inject constructor() { listeners.remove(listener) } - fun dispatchLiveEventDecrypted(event: Event) { + fun dispatchLiveEventReceived(event: Event, roomId: String, initialSync: Boolean) { + Timber.v("## dispatchLiveEventReceived ${event.eventId}") + coroutineScope.launch { + if (!initialSync) { + listeners.forEach { + tryOrNull { + it.onLiveEvent(roomId, event) + } + } + } + } + } + + fun dispatchPaginatedEventReceived(event: Event, roomId: String) { + Timber.v("## dispatchPaginatedEventReceived ${event.eventId}") + coroutineScope.launch { + listeners.forEach { + tryOrNull { + it.onPaginatedEvent(roomId, event) + } + } + } + } + + fun dispatchLiveEventDecrypted(event: Event, result: MXEventDecryptionResult) { Timber.v("## dispatchLiveEventDecrypted ${event.eventId}") coroutineScope.launch { listeners.forEach { tryOrNull { - it.onEventDecrypted(event) + it.onEventDecrypted(event, result.clearEvent) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt index 4e940bb445..63383a99b3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -186,7 +186,7 @@ internal class TokenChunkEventPersistor @Inject constructor( } roomMemberContentsByUser[event.stateKey] = contentToUse.toModel() } - + liveEventManager.get().dispatchPaginatedEventReceived(event, roomId) currentChunk.addTimelineEvent( roomId = roomId, eventEntity = eventEntity, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt index 1cb476d03a..8fe85f0d31 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt @@ -382,6 +382,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle } eventIds.add(event.eventId) + liveEventService.get().dispatchLiveEventReceived(event, roomId, insertType == EventInsertType.INITIAL_SYNC) val isInitialSync = insertType == EventInsertType.INITIAL_SYNC diff --git a/vector/src/main/java/im/vector/app/UISIDetector.kt b/vector/src/main/java/im/vector/app/UISIDetector.kt index 2b6974eefb..bb76a96b92 100644 --- a/vector/src/main/java/im/vector/app/UISIDetector.kt +++ b/vector/src/main/java/im/vector/app/UISIDetector.kt @@ -20,6 +20,7 @@ import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.LiveEventListener import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent import timber.log.Timber import java.util.Timer @@ -68,7 +69,7 @@ class UISIDetector : LiveEventListener { private val timeoutMillis = 30_000L private val enabled: Boolean get() = callback?.enabled.orFalse() - override fun onEventDecrypted(event: Event) { + override fun onEventDecrypted(event: Event, clearEvent: JsonDict) { val eventId = event.eventId val roomId = event.roomId if (!enabled || eventId == null || roomId == null) return @@ -108,6 +109,10 @@ class UISIDetector : LiveEventListener { timer.schedule(timeoutTask, timeoutMillis) } + override fun onLiveEvent(roomId: String, event: Event) { } + + override fun onPaginatedEvent(roomId: String, event: Event) { } + private fun trackerId(eventId: String, roomId: String): String = "$roomId-$eventId" private fun triggerUISI(source: E2EMessageDetected) { From 3ae4303ecd4d28b8194bfe16025866957ee5ecb6 Mon Sep 17 00:00:00 2001 From: David Langley Date: Mon, 28 Mar 2022 17:28:33 +0100 Subject: [PATCH 012/168] Fix changelog wording --- changelog.d/5639.sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/5639.sdk b/changelog.d/5639.sdk index 96b495f809..1ff8b4c053 100644 --- a/changelog.d/5639.sdk +++ b/changelog.d/5639.sdk @@ -1 +1 @@ -Include original event in decryption live decryption listeners. \ No newline at end of file +Include original event in live decryption listeners. \ No newline at end of file From aae281a7eaec2c8ead6d9ade6f8cffcada4dcab2 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 6 Apr 2022 16:34:30 +0300 Subject: [PATCH 013/168] Support aggregation of live location beacon events. --- .../room/model/livelocation/LiveLocationBeaconContent.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt index a4551d462e..022176b02d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt @@ -20,6 +20,7 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.session.room.model.message.LocationAsset import org.matrix.android.sdk.api.session.room.model.message.LocationAssetType +import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent @JsonClass(generateAdapter = true) data class LiveLocationBeaconContent( @@ -37,7 +38,13 @@ data class LiveLocationBeaconContent( * Live location asset type. */ @Json(name = "org.matrix.msc3488.asset") val unstableLocationAsset: LocationAsset = LocationAsset(LocationAssetType.SELF), - @Json(name = "m.asset") val locationAsset: LocationAsset? = null + @Json(name = "m.asset") val locationAsset: LocationAsset? = null, + + /** + * Client side tracking of the last location + */ + @Transient + val lastLocationContent: MessageLiveLocationContent? = null ) { fun getBestBeaconInfo() = beaconInfo ?: unstableBeaconInfo From 197b5420306c94abe68aea534d8acbeb47466ee4 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 6 Apr 2022 17:31:56 +0300 Subject: [PATCH 014/168] Check if live location data is valid. --- .../EventRelationsAggregationProcessor.kt | 81 ++++++++++++++++--- 1 file changed, 68 insertions(+), 13 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index 8bbe3a9ac6..ed7fc5b721 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -32,8 +32,10 @@ import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent import org.matrix.android.sdk.api.session.room.model.VoteInfo import org.matrix.android.sdk.api.session.room.model.VoteSummary +import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent +import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent @@ -47,6 +49,7 @@ import org.matrix.android.sdk.internal.crypto.verification.toState import org.matrix.android.sdk.internal.database.helper.findRootThreadEvent import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.database.mapper.EventMapper +import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntity import org.matrix.android.sdk.internal.database.model.EditionOfEvent import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity @@ -60,7 +63,9 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.query.create import org.matrix.android.sdk.internal.database.query.getOrCreate +import org.matrix.android.sdk.internal.database.query.getOrNull import org.matrix.android.sdk.internal.database.query.where +import org.matrix.android.sdk.internal.database.query.whereStateKey import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor @@ -88,7 +93,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( // EventType.KEY_VERIFICATION_READY, EventType.KEY_VERIFICATION_KEY, EventType.ENCRYPTED - ) + EventType.POLL_START + EventType.POLL_RESPONSE + EventType.POLL_END + ) + EventType.POLL_START + EventType.POLL_RESPONSE + EventType.POLL_END + EventType.BEACON_LOCATION_DATA override fun shouldProcess(eventId: String, eventType: String, insertType: EventInsertType): Boolean { return allowedTypes.contains(eventType) @@ -103,12 +108,12 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "") when (event.type) { - EventType.REACTION -> { + EventType.REACTION -> { // we got a reaction!! Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}") handleReaction(realm, event, roomId, isLocalEcho) } - EventType.MESSAGE -> { + EventType.MESSAGE -> { if (event.unsignedData?.relations?.annotations != null) { Timber.v("###REACTION Aggregation in room $roomId for event ${event.eventId}") handleInitialAggregatedRelations(realm, event, roomId, event.unsignedData.relations.annotations) @@ -134,7 +139,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_MAC, EventType.KEY_VERIFICATION_READY, - EventType.KEY_VERIFICATION_KEY -> { + EventType.KEY_VERIFICATION_KEY -> { Timber.v("## SAS REF in room $roomId for event ${event.eventId}") event.content.toModel()?.relatesTo?.let { if (it.type == RelationType.REFERENCE && it.eventId != null) { @@ -143,7 +148,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } - EventType.ENCRYPTED -> { + EventType.ENCRYPTED -> { // Relation type is in clear val encryptedEventContent = event.content.toModel() if (encryptedEventContent?.relatesTo?.type == RelationType.REPLACE || @@ -169,22 +174,27 @@ internal class EventRelationsAggregationProcessor @Inject constructor( EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_MAC, EventType.KEY_VERIFICATION_READY, - EventType.KEY_VERIFICATION_KEY -> { + EventType.KEY_VERIFICATION_KEY -> { Timber.v("## SAS REF in room $roomId for event ${event.eventId}") encryptedEventContent.relatesTo.eventId?.let { handleVerification(realm, event, roomId, isLocalEcho, it) } } - in EventType.POLL_RESPONSE -> { + in EventType.POLL_RESPONSE -> { event.getClearContent().toModel(catchError = true)?.let { handleResponse(realm, event, it, roomId, isLocalEcho, event.getRelationContent()?.eventId) } } - in EventType.POLL_END -> { + in EventType.POLL_END -> { event.content.toModel(catchError = true)?.let { handleEndPoll(realm, event, it, roomId, isLocalEcho) } } + in EventType.BEACON_LOCATION_DATA -> { + event.content.toModel(catchError = true)?.let { + handleLiveLocation(realm, event, it, roomId, isLocalEcho) + } + } } } else if (encryptedEventContent?.relatesTo?.type == RelationType.ANNOTATION) { // Reaction @@ -205,7 +215,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( // } // } } - EventType.REDACTION -> { + EventType.REDACTION -> { val eventToPrune = event.redacts?.let { EventEntity.where(realm, eventId = it).findFirst() } ?: return when (eventToPrune.type) { @@ -225,7 +235,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } } - in EventType.POLL_START -> { + in EventType.POLL_START -> { val content: MessagePollContent? = event.content.toModel() if (content?.relatesTo?.type == RelationType.REPLACE) { Timber.v("###REPLACE in room $roomId for event ${event.eventId}") @@ -233,17 +243,22 @@ internal class EventRelationsAggregationProcessor @Inject constructor( handleReplace(realm, event, content, roomId, isLocalEcho) } } - in EventType.POLL_RESPONSE -> { + in EventType.POLL_RESPONSE -> { event.content.toModel(catchError = true)?.let { handleResponse(realm, event, it, roomId, isLocalEcho) } } - in EventType.POLL_END -> { + in EventType.POLL_END -> { event.content.toModel(catchError = true)?.let { handleEndPoll(realm, event, it, roomId, isLocalEcho) } } - else -> Timber.v("UnHandled event ${event.eventId}") + in EventType.BEACON_LOCATION_DATA -> { + event.content.toModel(catchError = true)?.let { + handleLiveLocation(realm, event, it, roomId, isLocalEcho) + } + } + else -> Timber.v("UnHandled event ${event.eventId}") } } catch (t: Throwable) { Timber.e(t, "## Should not happen ") @@ -532,6 +547,46 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } + private fun handleLiveLocation(realm: Realm, + event: Event, + content: MessageLiveLocationContent, + roomId: String, + isLocalEcho: Boolean) { + val beaconInfoEventId = event.getRelationContent()?.eventId ?: return + val locationSenderId = event.senderId ?: return + + // We shouldn't process local echos + if (isLocalEcho) { + return + } + + // A beacon info state event has to be sent before sending location + val beaconInfoEntity = CurrentStateEventEntity.getOrNull(realm, roomId, locationSenderId, EventType.STATE_ROOM_BEACON_INFO.first()) + if (beaconInfoEntity == null) { + Timber.v("## LIVE LOCATION. There is not any beacon info which should be emitted before sending location updates") + return + } + val beaconInfoContent = ContentMapper.map(beaconInfoEntity.root?.content)?.toModel(catchError = true) + if (beaconInfoContent == null) { + Timber.v("## LIVE LOCATION. Beacon info content is invalid") + return + } + + // Check if beacon info is outdated + if (isBeaconInfoOutdated(beaconInfoContent, content)) { + Timber.v("## LIVE LOCATION. Beacon info content is invalid") + return + } + } + + private fun isBeaconInfoOutdated(beaconInfoContent: LiveLocationBeaconContent, + liveLocationContent: MessageLiveLocationContent): Boolean { + val beaconInfoStartTime = beaconInfoContent.getBestTimestampAsMilliseconds() ?: 0 + val liveLocationEventTime = liveLocationContent.getBestTs() ?: 0 + val timeout = beaconInfoContent.getBestBeaconInfo()?.timeout ?: 0 + return liveLocationEventTime - beaconInfoStartTime > timeout + } + private fun handleInitialAggregatedRelations(realm: Realm, event: Event, roomId: String, From faa07513eca566835d654840a908e655d4a53d0e Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 6 Apr 2022 19:01:25 +0300 Subject: [PATCH 015/168] Update last location content of beacon info state event. --- .../room/model/livelocation/LiveLocationBeaconContent.kt | 3 +-- .../session/room/EventRelationsAggregationProcessor.kt | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt index 022176b02d..a3faee0568 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationBeaconContent.kt @@ -43,8 +43,7 @@ data class LiveLocationBeaconContent( /** * Client side tracking of the last location */ - @Transient - val lastLocationContent: MessageLiveLocationContent? = null + var lastLocationContent: MessageLiveLocationContent? = null ) { fun getBestBeaconInfo() = beaconInfo ?: unstableBeaconInfo diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index ed7fc5b721..76e757d895 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -552,7 +552,6 @@ internal class EventRelationsAggregationProcessor @Inject constructor( content: MessageLiveLocationContent, roomId: String, isLocalEcho: Boolean) { - val beaconInfoEventId = event.getRelationContent()?.eventId ?: return val locationSenderId = event.senderId ?: return // We shouldn't process local echos @@ -577,6 +576,10 @@ internal class EventRelationsAggregationProcessor @Inject constructor( Timber.v("## LIVE LOCATION. Beacon info content is invalid") return } + + // Update last location info of the beacon state event + beaconInfoContent.lastLocationContent = content + beaconInfoEntity.root?.content = ContentMapper.map(beaconInfoContent.toContent()) } private fun isBeaconInfoOutdated(beaconInfoContent: LiveLocationBeaconContent, From 6708ed8b345ec94448a2e370a87fc7f1906bed51 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 6 Apr 2022 19:02:50 +0300 Subject: [PATCH 016/168] Lint fixes. --- .../internal/session/room/EventRelationsAggregationProcessor.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index 76e757d895..74c4ab9d68 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -65,7 +65,6 @@ import org.matrix.android.sdk.internal.database.query.create import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.database.query.getOrNull import org.matrix.android.sdk.internal.database.query.where -import org.matrix.android.sdk.internal.database.query.whereStateKey import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor From 44c6d88c444d2427c769f274182b9cf7e305a6a9 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 6 Apr 2022 19:24:20 +0300 Subject: [PATCH 017/168] Changelog added. --- changelog.d/5711.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5711.feature diff --git a/changelog.d/5711.feature b/changelog.d/5711.feature new file mode 100644 index 0000000000..76c6b23b69 --- /dev/null +++ b/changelog.d/5711.feature @@ -0,0 +1 @@ +Live Location Sharing - Attach location data to beacon info state event \ No newline at end of file From 90616de89df71ba4ce0e0b486b8ba7f0d97a37dd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 7 Apr 2022 09:30:18 +0200 Subject: [PATCH 018/168] Those log must be visible in the rageshake, even when verbose log is not enabled --- .../main/java/im/vector/app/VectorApplication.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index a3f4ffcfcd..e12eecfefc 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -230,13 +230,13 @@ class VectorApplication : val sdkVersion = Matrix.getSdkVersion() val date = SimpleDateFormat("MM-dd HH:mm:ss.SSSZ", Locale.US).format(Date()) - Timber.v("----------------------------------------------------------------") - Timber.v("----------------------------------------------------------------") - Timber.v(" Application version: $appVersion") - Timber.v(" SDK version: $sdkVersion") - Timber.v(" Local time: $date") - Timber.v("----------------------------------------------------------------") - Timber.v("----------------------------------------------------------------\n\n\n\n") + Timber.d("----------------------------------------------------------------") + Timber.d("----------------------------------------------------------------") + Timber.d(" Application version: $appVersion") + Timber.d(" SDK version: $sdkVersion") + Timber.d(" Local time: $date") + Timber.d("----------------------------------------------------------------") + Timber.d("----------------------------------------------------------------\n\n\n\n") } override fun attachBaseContext(base: Context) { From d4add052d95448e31a8a850e6e240fc1afac23ad Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 7 Apr 2022 09:30:42 +0200 Subject: [PATCH 019/168] This log was quite useless --- .../sdk/internal/session/sync/handler/room/RoomSyncHandler.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt index 8fe85f0d31..e7fee7a42d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt @@ -107,7 +107,6 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle isInitialSync: Boolean, aggregator: SyncResponsePostTreatmentAggregator, reporter: ProgressReporter? = null) { - Timber.v("Execute transaction from $this") handleRoomSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), isInitialSync, aggregator, reporter) handleRoomSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), isInitialSync, aggregator, reporter) handleRoomSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), isInitialSync, aggregator, reporter) From 1a53d2c8da33f126cea9b4c7478e84967b487d37 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 7 Apr 2022 09:30:52 +0200 Subject: [PATCH 020/168] python3 --- tools/hs_diag.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/hs_diag.py b/tools/hs_diag.py index 7d7a947c4c..50f117bc8e 100755 --- a/tools/hs_diag.py +++ b/tools/hs_diag.py @@ -65,6 +65,6 @@ for item in items: print("# " + item[0] + " (" + item[1] + ")") print("====================================================================================================") if item[2]: - os.system("curl -s -X GET '" + item[1] + "' | python -m json.tool") + os.system("curl -s -X GET '" + item[1] + "' | python3 -m json.tool") else: - os.system("curl -s -X POST --data $'{}' '" + item[1] + "' | python -m json.tool") + os.system("curl -s -X POST --data $'{}' '" + item[1] + "' | python3 -m json.tool") From dbf10a222ff0ff84e54f21c15b41ff440c3b5c4e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 7 Apr 2022 10:15:21 +0200 Subject: [PATCH 021/168] Privacy: does not log reaction (it is a `v`log, so not critical) --- .../session/room/EventRelationsAggregationProcessor.kt | 10 +++++----- .../room/relation/threads/FetchThreadTimelineTask.kt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index 8bbe3a9ac6..72fc9a4b04 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -584,11 +584,11 @@ internal class EventRelationsAggregationProcessor @Inject constructor( sum.key = reaction sum.firstTimestamp = event.originServerTs ?: 0 if (isLocalEcho) { - Timber.v("Adding local echo reaction $reaction") + Timber.v("Adding local echo reaction") sum.sourceLocalEcho.add(txId) sum.count = 1 } else { - Timber.v("Adding synced reaction $reaction") + Timber.v("Adding synced reaction") sum.count = 1 sum.sourceEvents.add(reactionEventId) } @@ -600,16 +600,16 @@ internal class EventRelationsAggregationProcessor @Inject constructor( // check if it's not the sync of a local echo if (!isLocalEcho && sum.sourceLocalEcho.contains(txId)) { // ok it has already been counted, just sync the list, do not touch count - Timber.v("Ignoring synced of local echo for reaction $reaction") + Timber.v("Ignoring synced of local echo for reaction") sum.sourceLocalEcho.remove(txId) sum.sourceEvents.add(reactionEventId) } else { sum.count += 1 if (isLocalEcho) { - Timber.v("Adding local echo reaction $reaction") + Timber.v("Adding local echo reaction") sum.sourceLocalEcho.add(txId) } else { - Timber.v("Adding synced reaction $reaction") + Timber.v("Adding synced reaction") sum.sourceEvents.add(reactionEventId) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt index a46bbe8d9f..15f70a8b4d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt @@ -251,7 +251,7 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor( sum = realm.createObject(ReactionAggregatedSummaryEntity::class.java) sum.key = reaction sum.firstTimestamp = event.originServerTs ?: 0 - Timber.v("Adding synced reaction $reaction") + Timber.v("Adding synced reaction") sum.count = 1 // reactionEventId not included in the /relations API // sum.sourceEvents.add(reactionEventId) From eab3e5aefa11fd07a91c60fd61219e2e0bec5da9 Mon Sep 17 00:00:00 2001 From: fedrunov <66663241+fedrunov@users.noreply.github.com> Date: Thu, 7 Apr 2022 15:16:12 +0200 Subject: [PATCH 022/168] don't leave DMs when leaving all rooms in space (#5720) --- changelog.d/5609.bugfix | 1 + .../java/im/vector/app/features/spaces/SpaceMenuViewModel.kt | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 changelog.d/5609.bugfix diff --git a/changelog.d/5609.bugfix b/changelog.d/5609.bugfix new file mode 100644 index 0000000000..001b4bf400 --- /dev/null +++ b/changelog.d/5609.bugfix @@ -0,0 +1 @@ +Choosing "leave all rooms and spaces" while leaving Space won't cause leaving DMs in this Space anymore \ No newline at end of file diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt index 9b95b5328f..cf3d01681b 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt @@ -35,6 +35,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.ActiveSpaceFilter +import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.room.model.Membership @@ -140,6 +141,7 @@ class SpaceMenuViewModel @AssistedInject constructor( excludeType = null activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(initialState.spaceId) memberships = listOf(Membership.JOIN) + roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS } ).forEach { try { From 504a2427757576efb32a92fbc3639985ae0ea72a Mon Sep 17 00:00:00 2001 From: fedrunov <66663241+fedrunov@users.noreply.github.com> Date: Thu, 7 Apr 2022 16:43:41 +0200 Subject: [PATCH 023/168] tracking number of spaces user joined (#5300) --- .../java/im/vector/app/AppStateHandler.kt | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/AppStateHandler.kt b/vector/src/main/java/im/vector/app/AppStateHandler.kt index 1ff3d97576..cc3aed03fb 100644 --- a/vector/src/main/java/im/vector/app/AppStateHandler.kt +++ b/vector/src/main/java/im/vector/app/AppStateHandler.kt @@ -18,9 +18,12 @@ package im.vector.app import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.asFlow import arrow.core.Option import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.utils.BehaviorDataSource +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.UserProperties import im.vector.app.features.session.coroutineScope import im.vector.app.features.ui.UiStateRepository import kotlinx.coroutines.CoroutineScope @@ -28,12 +31,15 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.group.model.GroupSummary +import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.room.model.RoomSummary import javax.inject.Inject import javax.inject.Singleton @@ -55,7 +61,8 @@ 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 activeSessionHolder: ActiveSessionHolder, + private val analyticsTracker: AnalyticsTracker ) : DefaultLifecycleObserver { private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) @@ -125,11 +132,23 @@ class AppStateHandler @Inject constructor( } else { setCurrentGroup(uiStateRepository.getSelectedGroup(session.sessionId), session) } + observeSyncStatus(session) } } .launchIn(coroutineScope) } + private fun observeSyncStatus(session: Session) { + session.getSyncStatusLive() + .asFlow() + .filterIsInstance() + .map { session.spaceService().getRootSpaceSummaries().size } + .distinctUntilChanged() + .onEach { spacesNumber -> + analyticsTracker.updateUserProperties(UserProperties(numSpaces = spacesNumber)) + }.launchIn(session.coroutineScope) + } + fun safeActiveSpaceId(): String? { return (selectedSpaceDataSource.currentValue?.orNull() as? RoomGroupingMethod.BySpace)?.spaceSummary?.roomId } From 190a425aa6aa068c3405cd88a3a2e564f24100e6 Mon Sep 17 00:00:00 2001 From: NIkita Fedrunov Date: Thu, 7 Apr 2022 14:22:13 +0200 Subject: [PATCH 024/168] don't leave DMs when leaving all rooms in space --- changelog.d/5609.bugfix | 1 + .../java/im/vector/app/features/spaces/SpaceMenuViewModel.kt | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 changelog.d/5609.bugfix diff --git a/changelog.d/5609.bugfix b/changelog.d/5609.bugfix new file mode 100644 index 0000000000..001b4bf400 --- /dev/null +++ b/changelog.d/5609.bugfix @@ -0,0 +1 @@ +Choosing "leave all rooms and spaces" while leaving Space won't cause leaving DMs in this Space anymore \ No newline at end of file diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt index 9b95b5328f..cf3d01681b 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt @@ -35,6 +35,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.ActiveSpaceFilter +import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.room.model.Membership @@ -140,6 +141,7 @@ class SpaceMenuViewModel @AssistedInject constructor( excludeType = null activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(initialState.spaceId) memberships = listOf(Membership.JOIN) + roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS } ).forEach { try { From 4a2b573ef4a0dc9e044376911028f2980ce4fbc3 Mon Sep 17 00:00:00 2001 From: NIkita Fedrunov Date: Thu, 7 Apr 2022 14:22:13 +0200 Subject: [PATCH 025/168] Towncrier --- CHANGES.md | 8 ++++++++ changelog.d/5609.bugfix | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) delete mode 100644 changelog.d/5609.bugfix diff --git a/CHANGES.md b/CHANGES.md index 16202e60b8..47b8c57041 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,11 @@ +Changes in Element v1.4.11 (2022-04-07) +======================================= + +Bugfixes 🐛 +---------- + - Choosing "leave all rooms and spaces" while leaving Space won't cause leaving DMs in this Space anymore ([#5609](https://github.com/vector-im/element-android/issues/5609)) + + Changes in Element v1.4.10 (2022-04-05) ======================================= diff --git a/changelog.d/5609.bugfix b/changelog.d/5609.bugfix deleted file mode 100644 index 001b4bf400..0000000000 --- a/changelog.d/5609.bugfix +++ /dev/null @@ -1 +0,0 @@ -Choosing "leave all rooms and spaces" while leaving Space won't cause leaving DMs in this Space anymore \ No newline at end of file From 0e1c587effb4ea329e4ff46c876f951ccdd89cc8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 7 Apr 2022 17:58:25 +0200 Subject: [PATCH 026/168] Version 1.4.11 --- matrix-sdk-android/build.gradle | 2 +- vector/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 748bae8ff2..788fdaff55 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -31,7 +31,7 @@ android { // that the app's state is completely cleared between tests. testInstrumentationRunnerArguments clearPackageData: 'true' - buildConfigField "String", "SDK_VERSION", "\"1.4.10\"" + buildConfigField "String", "SDK_VERSION", "\"1.4.11\"" buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\"" diff --git a/vector/build.gradle b/vector/build.gradle index a7e347949b..e222012c49 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -18,7 +18,7 @@ ext.versionMinor = 4 // Note: even values are reserved for regular release, odd values for hotfix release. // When creating a hotfix, you should decrease the value, since the current value // is the value for the next regular release. -ext.versionPatch = 10 +ext.versionPatch = 11 static def getGitTimestamp() { def cmd = 'git show -s --format=%ct' From c2bdfe0f199cc0c8e4259da258859621b3f32c9a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 7 Apr 2022 17:59:03 +0200 Subject: [PATCH 027/168] Fastlane --- fastlane/metadata/android/en-US/changelogs/40104110.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/en-US/changelogs/40104110.txt diff --git a/fastlane/metadata/android/en-US/changelogs/40104110.txt b/fastlane/metadata/android/en-US/changelogs/40104110.txt new file mode 100644 index 0000000000..217bbe0b39 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40104110.txt @@ -0,0 +1,2 @@ +Main changes in this version: Various bug fixes and stability improvements. +Full changelog: https://github.com/vector-im/element-android/releases \ No newline at end of file From 15e1c7bc3713e8643f18b0e962066219fc557ece Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 8 Apr 2022 13:18:17 +0300 Subject: [PATCH 028/168] Code review fixes. --- .../sdk/internal/session/SessionModule.kt | 5 ++ .../EventRelationsAggregationProcessor.kt | 54 ++----------- ...DefaultLiveLocationAggregationProcessor.kt | 80 +++++++++++++++++++ .../LiveLocationAggregationProcessor.kt | 29 +++++++ 4 files changed, 119 insertions(+), 49 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index 531dea1d5a..6e71a5393b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -87,6 +87,8 @@ import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationMan 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.room.EventRelationsAggregationProcessor +import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.DefaultLiveLocationAggregationProcessor +import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.LiveLocationAggregationProcessor import org.matrix.android.sdk.internal.session.room.create.RoomCreateEventProcessor import org.matrix.android.sdk.internal.session.room.prune.RedactionEventProcessor import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor @@ -390,4 +392,7 @@ internal abstract class SessionModule { @Binds abstract fun bindEventSenderProcessor(processor: EventSenderProcessorCoroutine): EventSenderProcessor + + @Binds + abstract fun bindLiveLocationAggregationProcessor(processor: DefaultLiveLocationAggregationProcessor): LiveLocationAggregationProcessor } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index 74c4ab9d68..27a70b27b4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -32,7 +32,6 @@ import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent import org.matrix.android.sdk.api.session.room.model.VoteInfo import org.matrix.android.sdk.api.session.room.model.VoteSummary -import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent @@ -49,7 +48,6 @@ import org.matrix.android.sdk.internal.crypto.verification.toState import org.matrix.android.sdk.internal.database.helper.findRootThreadEvent import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.database.mapper.EventMapper -import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntity import org.matrix.android.sdk.internal.database.model.EditionOfEvent import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity @@ -63,11 +61,11 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.query.create import org.matrix.android.sdk.internal.database.query.getOrCreate -import org.matrix.android.sdk.internal.database.query.getOrNull import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor +import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.LiveLocationAggregationProcessor import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource import timber.log.Timber import javax.inject.Inject @@ -76,7 +74,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor( @UserId private val userId: String, private val stateEventDataSource: StateEventDataSource, @SessionId private val sessionId: String, - private val sessionManager: SessionManager + private val sessionManager: SessionManager, + private val liveLocationAggregationProcessor: LiveLocationAggregationProcessor ) : EventInsertLiveProcessor { private val allowedTypes = listOf( @@ -191,7 +190,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } in EventType.BEACON_LOCATION_DATA -> { event.content.toModel(catchError = true)?.let { - handleLiveLocation(realm, event, it, roomId, isLocalEcho) + liveLocationAggregationProcessor.handleLiveLocation(realm, event, it, roomId, isLocalEcho) } } } @@ -254,7 +253,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } in EventType.BEACON_LOCATION_DATA -> { event.content.toModel(catchError = true)?.let { - handleLiveLocation(realm, event, it, roomId, isLocalEcho) + liveLocationAggregationProcessor.handleLiveLocation(realm, event, it, roomId, isLocalEcho) } } else -> Timber.v("UnHandled event ${event.eventId}") @@ -546,49 +545,6 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } - private fun handleLiveLocation(realm: Realm, - event: Event, - content: MessageLiveLocationContent, - roomId: String, - isLocalEcho: Boolean) { - val locationSenderId = event.senderId ?: return - - // We shouldn't process local echos - if (isLocalEcho) { - return - } - - // A beacon info state event has to be sent before sending location - val beaconInfoEntity = CurrentStateEventEntity.getOrNull(realm, roomId, locationSenderId, EventType.STATE_ROOM_BEACON_INFO.first()) - if (beaconInfoEntity == null) { - Timber.v("## LIVE LOCATION. There is not any beacon info which should be emitted before sending location updates") - return - } - val beaconInfoContent = ContentMapper.map(beaconInfoEntity.root?.content)?.toModel(catchError = true) - if (beaconInfoContent == null) { - Timber.v("## LIVE LOCATION. Beacon info content is invalid") - return - } - - // Check if beacon info is outdated - if (isBeaconInfoOutdated(beaconInfoContent, content)) { - Timber.v("## LIVE LOCATION. Beacon info content is invalid") - return - } - - // Update last location info of the beacon state event - beaconInfoContent.lastLocationContent = content - beaconInfoEntity.root?.content = ContentMapper.map(beaconInfoContent.toContent()) - } - - private fun isBeaconInfoOutdated(beaconInfoContent: LiveLocationBeaconContent, - liveLocationContent: MessageLiveLocationContent): Boolean { - val beaconInfoStartTime = beaconInfoContent.getBestTimestampAsMilliseconds() ?: 0 - val liveLocationEventTime = liveLocationContent.getBestTs() ?: 0 - val timeout = beaconInfoContent.getBestBeaconInfo()?.timeout ?: 0 - return liveLocationEventTime - beaconInfoStartTime > timeout - } - private fun handleInitialAggregatedRelations(realm: Realm, event: Event, roomId: String, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt new file mode 100644 index 0000000000..54bfe45cb9 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2022 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.room.aggregation.livelocation + +import io.realm.Realm +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent +import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent +import org.matrix.android.sdk.internal.database.mapper.ContentMapper +import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity +import org.matrix.android.sdk.internal.database.query.getOrNull +import timber.log.Timber +import javax.inject.Inject + +internal class DefaultLiveLocationAggregationProcessor @Inject constructor() : LiveLocationAggregationProcessor { + + override fun handleLiveLocation(realm: Realm, event: Event, content: MessageLiveLocationContent, roomId: String, isLocalEcho: Boolean) { + val locationSenderId = event.senderId ?: return + + // We shouldn't process local echos + if (isLocalEcho) { + return + } + + // A beacon info state event has to be sent before sending location + val beaconInfoEntity = CurrentStateEventEntity.getOrNull(realm, roomId, locationSenderId, EventType.STATE_ROOM_BEACON_INFO.first()) + ?: CurrentStateEventEntity.getOrNull(realm, roomId, locationSenderId, EventType.STATE_ROOM_BEACON_INFO.last()) + if (beaconInfoEntity == null) { + Timber.v("## LIVE LOCATION. There is not any beacon info which should be emitted before sending location updates") + return + } + val beaconInfoContent = ContentMapper.map(beaconInfoEntity.root?.content)?.toModel(catchError = true) + if (beaconInfoContent == null) { + Timber.v("## LIVE LOCATION. Beacon info content is invalid") + return + } + + // Check if live location is ended + if (!beaconInfoContent.getBestBeaconInfo()?.isLive.orFalse()) { + Timber.v("## LIVE LOCATION. Beacon info is not live anymore") + return + } + + // Check if beacon info is outdated + if (isBeaconInfoOutdated(beaconInfoContent, content)) { + Timber.v("## LIVE LOCATION. Beacon info has timeout") + return + } + + // Update last location info of the beacon state event + beaconInfoContent.lastLocationContent = content + beaconInfoEntity.root?.content = ContentMapper.map(beaconInfoContent.toContent()) + } + + private fun isBeaconInfoOutdated(beaconInfoContent: LiveLocationBeaconContent, + liveLocationContent: MessageLiveLocationContent): Boolean { + val beaconInfoStartTime = beaconInfoContent.getBestTimestampAsMilliseconds() ?: 0 + val liveLocationEventTime = liveLocationContent.getBestTs() ?: 0 + val timeout = beaconInfoContent.getBestBeaconInfo()?.timeout ?: 0 + return liveLocationEventTime - beaconInfoStartTime > timeout + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt new file mode 100644 index 0000000000..447eed21b0 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2022 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.room.aggregation.livelocation + +import io.realm.Realm +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent + +interface LiveLocationAggregationProcessor { + fun handleLiveLocation(realm: Realm, + event: Event, + content: MessageLiveLocationContent, + roomId: String, + isLocalEcho: Boolean) +} From 28f483870f67c9c1330dd3313425b79a2b06cc8b Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 8 Apr 2022 13:26:36 +0300 Subject: [PATCH 029/168] Code review fixes. --- .../room/model/message/MessageLiveLocationContent.kt | 6 +++--- .../livelocation/DefaultLiveLocationAggregationProcessor.kt | 2 +- .../sdk/internal/session/room/send/LocalEchoEventFactory.kt | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLiveLocationContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLiveLocationContent.kt index e5de46b3ef..548dc85369 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLiveLocationContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLiveLocationContent.kt @@ -42,11 +42,11 @@ data class MessageLiveLocationContent( /** * Exact time that the data in the event refers to (milliseconds since the UNIX epoch) */ - @Json(name = "org.matrix.msc3488.ts") val unstableTs: Long? = null, - @Json(name = "m.ts") val ts: Long? = null + @Json(name = "org.matrix.msc3488.ts") val unstableTimestampAsMilliseconds: Long? = null, + @Json(name = "m.ts") val timestampAsMilliseconds: Long? = null ) : MessageContent { fun getBestLocationInfo() = locationInfo ?: unstableLocationInfo - fun getBestTs() = ts ?: unstableTs + fun getBestTimestampAsMilliseconds() = timestampAsMilliseconds ?: unstableTimestampAsMilliseconds } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt index 54bfe45cb9..7d37ddc22b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt @@ -73,7 +73,7 @@ internal class DefaultLiveLocationAggregationProcessor @Inject constructor() : L private fun isBeaconInfoOutdated(beaconInfoContent: LiveLocationBeaconContent, liveLocationContent: MessageLiveLocationContent): Boolean { val beaconInfoStartTime = beaconInfoContent.getBestTimestampAsMilliseconds() ?: 0 - val liveLocationEventTime = liveLocationContent.getBestTs() ?: 0 + val liveLocationEventTime = liveLocationContent.getBestTimestampAsMilliseconds() ?: 0 val timeout = beaconInfoContent.getBestBeaconInfo()?.timeout ?: 0 return liveLocationEventTime - beaconInfoStartTime > timeout } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt index d7d74ca601..ba98bfc25b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt @@ -256,7 +256,7 @@ internal class LocalEchoEventFactory @Inject constructor( eventId = beaconInfoEventId ), unstableLocationInfo = LocationInfo(geoUri = geoUri, description = geoUri), - unstableTs = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()), + unstableTimestampAsMilliseconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()), ) val localId = LocalEcho.createLocalEchoId() return Event( From c3cf22158b539434f21f90a80f63bc81c0bd58d0 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 30 Mar 2022 17:08:51 +0100 Subject: [PATCH 030/168] adding barebones server selection UI --- .../FtueAuthCombinedRegisterFragment.kt | 10 + ...FtueAuthCombinedServerSelectionFragment.kt | 44 +++ .../main/res/drawable/ic_choose_server.xml | 9 + vector/src/main/res/drawable/ic_ems_logo.xml | 22 ++ ...ragment_ftue_server_selection_combined.xml | 256 ++++++++++++++++++ .../layout/fragment_ftue_sign_up_combined.xml | 1 - vector/src/main/res/values/donottranslate.xml | 8 + 7 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt create mode 100644 vector/src/main/res/drawable/ic_choose_server.xml create mode 100644 vector/src/main/res/drawable/ic_ems_logo.xml create mode 100644 vector/src/main/res/layout/fragment_ftue_server_selection_combined.xml diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt index 3a7d51d14b..5096598386 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt @@ -22,6 +22,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.inputmethod.EditorInfo +import androidx.appcompat.app.AppCompatActivity import androidx.autofill.HintConstants import androidx.core.text.isDigitsOnly import androidx.core.view.isVisible @@ -29,6 +30,8 @@ import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.withState import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.R +import im.vector.app.core.extensions.addFragment +import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.content import im.vector.app.core.extensions.editText import im.vector.app.core.extensions.hasContentFlow @@ -36,6 +39,7 @@ import im.vector.app.core.extensions.hasSurroundingSpaces import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.hidePassword import im.vector.app.core.extensions.realignPercentagesToParent +import im.vector.app.core.extensions.toMvRxBundle import im.vector.app.databinding.FragmentFtueSignUpCombinedBinding import im.vector.app.features.login.LoginMode import im.vector.app.features.login.SSORedirectRouterActivity @@ -67,6 +71,12 @@ class FtueAuthCombinedRegisterFragment @Inject constructor() : AbstractSSOFtueAu views.createAccountRoot.realignPercentagesToParent() + views.editServerButton.debouncedClicks { + requireActivity().supportFragmentManager.commitTransaction(true) { + add(R.id.loginFragmentContainer, FtueAuthCombinedServerSelectionFragment(), null) + } + } + views.createAccountPasswordInput.editText().setOnEditorActionListener { _, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_DONE) { submit() diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt new file mode 100644 index 0000000000..fdd81b99c0 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 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.features.onboarding.ftueauth + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import im.vector.app.databinding.FragmentFtueServerSelectionCombinedBinding +import im.vector.app.features.onboarding.OnboardingAction +import im.vector.app.features.onboarding.OnboardingViewEvents +import javax.inject.Inject + +class FtueAuthCombinedServerSelectionFragment @Inject constructor() : AbstractSSOFtueAuthFragment() { + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueServerSelectionCombinedBinding { + return FragmentFtueServerSelectionCombinedBinding.inflate(inflater, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + views.chooseServerToolbar.setNavigationOnClickListener { + viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnBack)) + } + } + + override fun resetViewModel() { + + } +} diff --git a/vector/src/main/res/drawable/ic_choose_server.xml b/vector/src/main/res/drawable/ic_choose_server.xml new file mode 100644 index 0000000000..26c8e75222 --- /dev/null +++ b/vector/src/main/res/drawable/ic_choose_server.xml @@ -0,0 +1,9 @@ + + + diff --git a/vector/src/main/res/drawable/ic_ems_logo.xml b/vector/src/main/res/drawable/ic_ems_logo.xml new file mode 100644 index 0000000000..68c2aeb190 --- /dev/null +++ b/vector/src/main/res/drawable/ic_ems_logo.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/vector/src/main/res/layout/fragment_ftue_server_selection_combined.xml b/vector/src/main/res/layout/fragment_ftue_server_selection_combined.xml new file mode 100644 index 0000000000..8da4958007 --- /dev/null +++ b/vector/src/main/res/layout/fragment_ftue_server_selection_combined.xml @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +