Skip to content

Commit 091d41b

Browse files
committed
Merge branch 'develop' into feature/fga/fix_left_room_membership_change
2 parents 2b87281 + 4572419 commit 091d41b

File tree

153 files changed

+2894
-1097
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

153 files changed

+2894
-1097
lines changed

.github/workflows/maestro-local.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ env:
1111
CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true --no-configuration-cache
1212
ARCH: x86_64
1313
DEVICE: pixel_7_pro
14-
API_LEVEL: 35
14+
API_LEVEL: 33
1515
TARGET: google_apis
1616

1717
jobs:

.maestro/allTests.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
appId: ${MAESTRO_APP_ID}
2+
androidWebViewHierarchy: devtools
23
---
34
## Check that all env variables required in the whole test suite are declared (to fail faster)
45
- runScript: ./scripts/checkEnv.js

.maestro/tests/account/login.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,22 @@ appId: ${MAESTRO_APP_ID}
1414
visible: 'Use without an account'
1515
commands:
1616
- tapOn: "Use without an account"
17+
## For older chrome versions
18+
- runFlow:
19+
when:
20+
visible: 'Accept & continue'
21+
commands:
22+
- tapOn: "Accept & continue"
23+
- runFlow:
24+
when:
25+
visible: 'No thanks'
26+
commands:
27+
- tapOn: "No thanks"
1728
## Working when running Maestro locally, but not on the CI yet.
29+
- extendedWaitUntil:
30+
visible:
31+
id: "form-1"
32+
timeout: 10000
1833
- tapOn:
1934
id: "form-1"
2035
- inputText: ${MAESTRO_USERNAME}

app/build.gradle.kts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,3 +354,12 @@ fun Project.configureLicensesTasks(reportingExtension: ReportingExtension) {
354354
}
355355
}
356356
}
357+
358+
configurations.all {
359+
resolutionStrategy {
360+
dependencySubstitution {
361+
val tink = libs.google.tink.get()
362+
substitute(module("com.google.crypto.tink:tink")).using(module("${tink.group}:${tink.name}:${tink.version}"))
363+
}
364+
}
365+
}

appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
3636
import io.element.android.libraries.matrix.api.core.UserId
3737
import io.element.android.libraries.matrix.api.permalink.PermalinkData
3838
import io.element.android.libraries.matrix.api.room.JoinedRoom
39+
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
3940
import io.element.android.services.appnavstate.api.AppNavigationStateService
4041
import kotlinx.coroutines.CoroutineScope
4142
import kotlinx.coroutines.launch
@@ -51,6 +52,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor(
5152
private val appNavigationStateService: AppNavigationStateService,
5253
private val appCoroutineScope: CoroutineScope,
5354
private val matrixClient: MatrixClient,
55+
private val activeRoomsHolder: ActiveRoomsHolder,
5456
roomComponentFactory: RoomComponentFactory,
5557
) : BaseFlowNode<JoinedRoomLoadedFlowNode.NavTarget>(
5658
backstack = BackStack(
@@ -85,6 +87,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor(
8587
onCreate = {
8688
Timber.v("OnCreate => ${inputs.room.roomId}")
8789
appNavigationStateService.onNavigateToRoom(id, inputs.room.roomId)
90+
activeRoomsHolder.addRoom(inputs.room)
8891
fetchRoomMembers()
8992
trackVisitedRoom()
9093
},
@@ -95,6 +98,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor(
9598
},
9699
onDestroy = {
97100
Timber.v("OnDestroy")
101+
activeRoomsHolder.removeRoom(inputs.room.sessionId, inputs.room.roomId)
98102
inputs.room.destroy()
99103
appNavigationStateService.onLeavingRoom(id)
100104
}

appnav/src/test/kotlin/io/element/android/appnav/JoinBaseRoomLoadedFlowNodeTest.kt renamed to appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@ import io.element.android.features.messages.api.MessagesEntryPoint
2424
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
2525
import io.element.android.libraries.architecture.childNode
2626
import io.element.android.libraries.matrix.api.room.JoinedRoom
27+
import io.element.android.libraries.matrix.test.A_SESSION_ID
2728
import io.element.android.libraries.matrix.test.FakeMatrixClient
2829
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
2930
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
31+
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
3032
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
31-
import kotlinx.coroutines.CoroutineScope
33+
import kotlinx.coroutines.test.TestScope
3234
import kotlinx.coroutines.test.runTest
3335
import org.junit.Rule
3436
import org.junit.Test
3537

36-
class JoinBaseRoomLoadedFlowNodeTest {
38+
class JoinedRoomLoadedFlowNodeTest {
3739
@get:Rule
3840
val instantTaskExecutorRule = InstantTaskExecutorRule()
3941

@@ -96,20 +98,21 @@ class JoinBaseRoomLoadedFlowNodeTest {
9698
}
9799
}
98100

99-
private fun createJoinedRoomLoadedFlowNode(
101+
private fun TestScope.createJoinedRoomLoadedFlowNode(
100102
plugins: List<Plugin>,
101103
messagesEntryPoint: MessagesEntryPoint = FakeMessagesEntryPoint(),
102104
roomDetailsEntryPoint: RoomDetailsEntryPoint = FakeRoomDetailsEntryPoint(),
103-
coroutineScope: CoroutineScope,
105+
activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(),
104106
) = JoinedRoomLoadedFlowNode(
105107
buildContext = BuildContext.root(savedStateMap = null),
106108
plugins = plugins,
107109
messagesEntryPoint = messagesEntryPoint,
108110
roomDetailsEntryPoint = roomDetailsEntryPoint,
109111
appNavigationStateService = FakeAppNavigationStateService(),
110-
appCoroutineScope = coroutineScope,
112+
appCoroutineScope = this,
111113
roomComponentFactory = FakeRoomComponentFactory(),
112114
matrixClient = FakeMatrixClient(),
115+
activeRoomsHolder = activeRoomsHolder,
113116
)
114117

115118
@Test
@@ -121,7 +124,6 @@ class JoinBaseRoomLoadedFlowNodeTest {
121124
val roomFlowNode = createJoinedRoomLoadedFlowNode(
122125
plugins = listOf(inputs),
123126
messagesEntryPoint = fakeMessagesEntryPoint,
124-
coroutineScope = this
125127
)
126128
// WHEN
127129
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()
@@ -144,7 +146,6 @@ class JoinBaseRoomLoadedFlowNodeTest {
144146
plugins = listOf(inputs),
145147
messagesEntryPoint = fakeMessagesEntryPoint,
146148
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
147-
coroutineScope = this
148149
)
149150
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()
150151
// WHEN
@@ -154,4 +155,53 @@ class JoinBaseRoomLoadedFlowNodeTest {
154155
val roomDetailsNode = roomFlowNode.childNode(JoinedRoomLoadedFlowNode.NavTarget.RoomDetails)!!
155156
assertThat(roomDetailsNode.id).isEqualTo(fakeRoomDetailsEntryPoint.nodeId)
156157
}
158+
159+
@Test
160+
fun `the ActiveRoomsHolder will be updated with the loaded room on create`() = runTest {
161+
// GIVEN
162+
val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {}))
163+
val fakeMessagesEntryPoint = FakeMessagesEntryPoint()
164+
val fakeRoomDetailsEntryPoint = FakeRoomDetailsEntryPoint()
165+
val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Messages())
166+
val activeRoomsHolder = ActiveRoomsHolder()
167+
val roomFlowNode = createJoinedRoomLoadedFlowNode(
168+
plugins = listOf(inputs),
169+
messagesEntryPoint = fakeMessagesEntryPoint,
170+
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
171+
activeRoomsHolder = activeRoomsHolder,
172+
)
173+
174+
assertThat(activeRoomsHolder.getActiveRoom(A_SESSION_ID)).isNull()
175+
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()
176+
// WHEN
177+
roomFlowNodeTestHelper.assertChildHasLifecycle(JoinedRoomLoadedFlowNode.NavTarget.Messages(null), Lifecycle.State.CREATED)
178+
// THEN
179+
assertThat(activeRoomsHolder.getActiveRoom(A_SESSION_ID)).isNotNull()
180+
}
181+
182+
@Test
183+
fun `the ActiveRoomsHolder will be removed on destroy`() = runTest {
184+
// GIVEN
185+
val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {}))
186+
val fakeMessagesEntryPoint = FakeMessagesEntryPoint()
187+
val fakeRoomDetailsEntryPoint = FakeRoomDetailsEntryPoint()
188+
val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Messages())
189+
val activeRoomsHolder = ActiveRoomsHolder().apply {
190+
addRoom(room)
191+
}
192+
val roomFlowNode = createJoinedRoomLoadedFlowNode(
193+
plugins = listOf(inputs),
194+
messagesEntryPoint = fakeMessagesEntryPoint,
195+
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
196+
activeRoomsHolder = activeRoomsHolder,
197+
)
198+
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()
199+
roomFlowNodeTestHelper.assertChildHasLifecycle(JoinedRoomLoadedFlowNode.NavTarget.Messages(null), Lifecycle.State.CREATED)
200+
assertThat(activeRoomsHolder.getActiveRoom(A_SESSION_ID)).isNotNull()
201+
// WHEN
202+
roomFlowNode.updateLifecycleState(Lifecycle.State.DESTROYED)
203+
// THEN
204+
roomFlowNodeTestHelper.assertChildHasLifecycle(JoinedRoomLoadedFlowNode.NavTarget.Messages(null), Lifecycle.State.DESTROYED)
205+
assertThat(activeRoomsHolder.getActiveRoom(A_SESSION_ID)).isNull()
206+
}
157207
}

enterprise

features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import io.element.android.libraries.matrix.api.sync.SyncState
3939
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
4040
import io.element.android.libraries.network.useragent.UserAgentProvider
4141
import io.element.android.services.analytics.api.ScreenTracker
42+
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
4243
import io.element.android.services.appnavstate.api.AppForegroundStateService
4344
import io.element.android.services.toolbox.api.systemclock.SystemClock
4445
import kotlinx.coroutines.CoroutineScope
@@ -62,6 +63,7 @@ class CallScreenPresenter @AssistedInject constructor(
6263
private val activeCallManager: ActiveCallManager,
6364
private val languageTagProvider: LanguageTagProvider,
6465
private val appForegroundStateService: AppForegroundStateService,
66+
private val activeRoomsHolder: ActiveRoomsHolder,
6567
private val appCoroutineScope: CoroutineScope,
6668
) : Presenter<CallScreenState> {
6769
@AssistedFactory
@@ -241,8 +243,10 @@ class CallScreenPresenter @AssistedInject constructor(
241243

242244
private suspend fun MatrixClient.notifyCallStartIfNeeded(roomId: RoomId) {
243245
if (!notifiedCallStart) {
244-
getJoinedRoom(roomId)?.use { it.sendCallNotificationIfNeeded() }
245-
?.onSuccess { notifiedCallStart = true }
246+
val activeRoomForSession = activeRoomsHolder.getActiveRoomMatching(sessionId, roomId)
247+
val sendCallNotificationResult = activeRoomForSession?.sendCallNotificationIfNeeded()
248+
?: getJoinedRoom(roomId)?.use { it.sendCallNotificationIfNeeded() }
249+
sendCallNotificationResult?.onSuccess { notifiedCallStart = true }
246250
}
247251
}
248252

features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
1414
import io.element.android.libraries.matrix.api.core.SessionId
1515
import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider
1616
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
17+
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
1718
import kotlinx.coroutines.flow.firstOrNull
1819
import javax.inject.Inject
1920

@@ -24,6 +25,7 @@ class DefaultCallWidgetProvider @Inject constructor(
2425
private val matrixClientsProvider: MatrixClientProvider,
2526
private val appPreferencesStore: AppPreferencesStore,
2627
private val callWidgetSettingsProvider: CallWidgetSettingsProvider,
28+
private val activeRoomsHolder: ActiveRoomsHolder,
2729
) : CallWidgetProvider {
2830
override suspend fun getWidget(
2931
sessionId: SessionId,
@@ -33,7 +35,9 @@ class DefaultCallWidgetProvider @Inject constructor(
3335
theme: String?,
3436
): Result<CallWidgetProvider.GetWidgetResult> = runCatching {
3537
val matrixClient = matrixClientsProvider.getOrRestore(sessionId).getOrThrow()
36-
val room = matrixClient.getJoinedRoom(roomId) ?: error("Room not found")
38+
val room = activeRoomsHolder.getActiveRoomMatching(sessionId, roomId)
39+
?: matrixClient.getJoinedRoom(roomId)
40+
?: error("Room not found")
3741

3842
val customBaseUrl = appPreferencesStore.getCustomElementCallBaseUrlFlow().firstOrNull()
3943
val baseUrl = customBaseUrl ?: EMBEDDED_CALL_WIDGET_BASE_URL

features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import io.element.android.libraries.matrix.test.widget.FakeMatrixWidgetDriver
3232
import io.element.android.libraries.network.useragent.UserAgentProvider
3333
import io.element.android.services.analytics.api.ScreenTracker
3434
import io.element.android.services.analytics.test.FakeScreenTracker
35+
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
3536
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
3637
import io.element.android.services.toolbox.api.systemclock.SystemClock
3738
import io.element.android.tests.testutils.WarmUpRule
@@ -367,6 +368,7 @@ import kotlin.time.Duration.Companion.seconds
367368
activeCallManager: FakeActiveCallManager = FakeActiveCallManager(),
368369
screenTracker: ScreenTracker = FakeScreenTracker(),
369370
appForegroundStateService: FakeAppForegroundStateService = FakeAppForegroundStateService(),
371+
activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(),
370372
): CallScreenPresenter {
371373
val userAgentProvider = object : UserAgentProvider {
372374
override fun provide(): String {
@@ -387,6 +389,7 @@ import kotlin.time.Duration.Companion.seconds
387389
languageTagProvider = FakeLanguageTagProvider("en-US"),
388390
appForegroundStateService = appForegroundStateService,
389391
appCoroutineScope = backgroundScope,
392+
activeRoomsHolder = activeRoomsHolder,
390393
)
391394
}
392395
}

0 commit comments

Comments
 (0)