Repository: element-hq/element-x-android (language: kotlin)

Issue:
KeyBackup: do not show the "Message history" banner if key backup is set up.
Show all the messages instead, even if they cannot be decrypted.


Discussion hints:
nan

Pull request: Show full history if key backup is enabled.
<!-- Please read [CONTRIBUTING.md](https://github.com/vector-im/element-x-android/blob/develop/CONTRIBUTING.md) before submitting your pull request -->
 
## Type of change

- [ ] Feature
- [x] Bugfix
- [ ] Technical
- [ ] Other :

## Content

<!-- Describe shortly what has been changed -->
If KeyBackup is enabled, do not show the no history banner in encrypted room.

## Motivation and context

<!-- Provide link to the corresponding issue if applicable or explain the context -->
Closes #1768 

## Screenshots / GIFs

<!--
We have screenshot tests in the project, so attaching screenshots to a PR is not mandatory, as far as there
is a Composable Preview covering the changes. In this case, the change will appear in the file diff.
Note that all the UI composables should be covered by a Composable Preview.

Providing a video of the change is still very useful for the reviewer and for the history of the project.

You can use a table like this to show screenshots comparison.
Uncomment this markdown table below and edit the last line `|||`:
|copy screenshot of before here|copy screenshot of after here|

|Before|After|
|-|-|
|||
 -->

## Tests

<!-- Explain how you tested your development -->

- Log in to an account with a e2e room RoomA with messages.
- Verify the session
- Open RoomA and see that the banner is displayed
- From the setting, enter the recovery key to unlock the chat backup
- open the RoomA
- observe that the history of the room is visible (and decrypted if the keys are in the backup)

Before this PR, the banner was always displayed, event if the history was present and decrypted.

## Tested devices

- [ ] Physical
- [x] Emulator
- OS version(s):

## Checklist

<!-- Depending on the Pull Request content, it can be acceptable if some of the following checkboxes stay unchecked. -->

- [ ] Changes have been tested on an Android device or Android emulator with API 23
- [ ] UI change has been tested on both light and dark themes
- [ ] Accessibility has been taken into account. See https://github.com/vector-im/element-x-android/blob/develop/CONTRIBUTING.md#accessibility
- [ ] Pull request is based on the develop branch
- [ ] Pull request includes a new file under ./changelog.d. See https://github.com/vector-im/element-x-android/blob/develop/CONTRIBUTING.md#changelog
- [ ] Pull request includes screenshots or videos if containing UI changes
- [ ] Pull request includes a [sign off](https://matrix-org.github.io/synapse/latest/development/contributing_guide.html#sign-off)
- [ ] You've made a self review of your PR


Test command: ./gradlew :libraries:matrix:impl:testDebugUnitTest --tests "io.element.android.libraries.matrix.impl.timeline.postprocessor.TimelineEncryptedHistoryPostProcessorTest"

Fix patch:
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt
index 99dd0af8fd7..035add9ab2c 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt
@@ -72,6 +72,7 @@ import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import kotlinx.coroutines.withTimeout
+import org.matrix.rustcomponents.sdk.BackupState
 import org.matrix.rustcomponents.sdk.Client
 import org.matrix.rustcomponents.sdk.ClientDelegate
 import org.matrix.rustcomponents.sdk.NotificationProcessSetup
@@ -200,6 +201,7 @@ class RustMatrixClient constructor(
         cachedPairOfRoom?.let { (roomListItem, fullRoom) ->
             RustMatrixRoom(
                 sessionId = sessionId,
+                isKeyBackupEnabled = client.encryption().backupState() == BackupState.ENABLED,
                 roomListItem = roomListItem,
                 innerRoom = fullRoom,
                 roomNotificationSettingsService = notificationSettingsService,
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt
index 6e47e90dcd8..ab7317590e7 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt
@@ -86,6 +86,7 @@ import java.io.File
 @OptIn(ExperimentalCoroutinesApi::class)
 class RustMatrixRoom(
     override val sessionId: SessionId,
+    isKeyBackupEnabled: Boolean,
     private val roomListItem: RoomListItem,
     private val innerRoom: Room,
     private val roomNotificationSettingsService: RustNotificationSettingsService,
@@ -126,6 +127,7 @@ class RustMatrixRoom(
     override val roomNotificationSettingsStateFlow: StateFlow<MatrixRoomNotificationSettingsState> = _roomNotificationSettingsStateFlow
 
     override val timeline = RustMatrixTimeline(
+        isKeyBackupEnabled = isKeyBackupEnabled,
         matrixRoom = this,
         innerRoom = innerRoom,
         roomCoroutineScope = roomCoroutineScope,
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
index 74ad10ad26a..53ae41d887d 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
@@ -57,6 +57,7 @@ private const val INITIAL_MAX_SIZE = 50
 
 class RustMatrixTimeline(
     roomCoroutineScope: CoroutineScope,
+    isKeyBackupEnabled: Boolean,
     private val matrixRoom: MatrixRoom,
     private val innerRoom: Room,
     private val dispatcher: CoroutineDispatcher,
@@ -77,6 +78,7 @@ class RustMatrixTimeline(
     private val encryptedHistoryPostProcessor = TimelineEncryptedHistoryPostProcessor(
         lastLoginTimestamp = lastLoginTimestamp,
         isRoomEncrypted = matrixRoom.isEncrypted,
+        isKeyBackupEnabled = isKeyBackupEnabled,
         paginationStateFlow = _paginationState,
         dispatcher = dispatcher,
     )
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessor.kt
index b273bef21bc..60de981780a 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessor.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessor.kt
@@ -30,12 +30,13 @@ class TimelineEncryptedHistoryPostProcessor(
     private val dispatcher: CoroutineDispatcher,
     private val lastLoginTimestamp: Date?,
     private val isRoomEncrypted: Boolean,
+    private val isKeyBackupEnabled: Boolean,
     private val paginationStateFlow: MutableStateFlow<MatrixTimeline.PaginationState>,
 ) {
 
     suspend fun process(items: List<MatrixTimelineItem>): List<MatrixTimelineItem> = withContext(dispatcher) {
         Timber.d("Process on Thread=${Thread.currentThread()}")
-        if (!isRoomEncrypted || lastLoginTimestamp == null) return@withContext items
+        if (!isRoomEncrypted || isKeyBackupEnabled || lastLoginTimestamp == null) return@withContext items
 
         val filteredItems = replaceWithEncryptionHistoryBannerIfNeeded(items)
         // Disable back pagination


Test patch:
diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt
index 63920cd6cef..d3af9a56707 100644
--- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt
+++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt
@@ -41,6 +41,15 @@ class TimelineEncryptedHistoryPostProcessorTest {
         assertThat(processor.process(items)).isSameInstanceAs(items)
     }
 
+    @Test
+    fun `given an encrypted room, and key backup enabled, nothing is done`() = runTest {
+        val processor = createPostProcessor(isKeyBackupEnabled = true)
+        val items = listOf(
+            MatrixTimelineItem.Event(0L, anEventTimelineItem())
+        )
+        assertThat(processor.process(items)).isSameInstanceAs(items)
+    }
+
     @Test
     fun `given a null lastLoginTimestamp, nothing is done`() = runTest {
         val processor = createPostProcessor(lastLoginTimestamp = null)
@@ -108,11 +117,13 @@ class TimelineEncryptedHistoryPostProcessorTest {
     private fun TestScope.createPostProcessor(
         lastLoginTimestamp: Date? = defaultLastLoginTimestamp,
         isRoomEncrypted: Boolean = true,
+        isKeyBackupEnabled: Boolean = false,
         paginationStateFlow: MutableStateFlow<MatrixTimeline.PaginationState> =
             MutableStateFlow(MatrixTimeline.PaginationState(hasMoreToLoadBackwards = true, isBackPaginating = false))
     ) = TimelineEncryptedHistoryPostProcessor(
         lastLoginTimestamp = lastLoginTimestamp,
         isRoomEncrypted = isRoomEncrypted,
+        isKeyBackupEnabled = isKeyBackupEnabled,
         paginationStateFlow = paginationStateFlow,
         dispatcher = StandardTestDispatcher(testScheduler)
     )