Skip to content

Commit d5a9da4

Browse files
authored
Merge branch 'develop' into renovate/com.google.firebase-firebase-bom-33.x
2 parents 5016193 + 3588259 commit d5a9da4

File tree

60 files changed

+1164
-369
lines changed

Some content is hidden

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

60 files changed

+1164
-369
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}

CHANGES.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,50 @@
1+
<!-- Release notes generated using configuration in .github/release.yml at v25.05.4 -->
2+
3+
Changes in Element X v25.05.4
4+
=============================
5+
6+
Rust SDK: https://github.com/matrix-org/matrix-rust-sdk/releases/tag/matrix-sdk-ffi%2F20250521
7+
8+
## What's Changed
9+
### 🙌 Improvements
10+
* Change (report room) : check if server supports the report room api by @ganfra in https://github.com/element-hq/element-x-android/pull/4718
11+
### 🐛 Bugfixes
12+
* Improve audio focus management by @bmarty in https://github.com/element-hq/element-x-android/pull/4707
13+
* When transcoding a video fails, send it as a file by @jmartinesp in https://github.com/element-hq/element-x-android/pull/4257
14+
* Disable mutliple click (parallel or serial) on a room by @bmarty in https://github.com/element-hq/element-x-android/pull/4683
15+
* Fix generic mime type used when externally sharing several files by @jmartinesp in https://github.com/element-hq/element-x-android/pull/4715
16+
* Fix issues on JoinedRoom / BaseRoom by @bmarty in https://github.com/element-hq/element-x-android/pull/4724
17+
* Use the right live timeline instance in `RustRoomFactory` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/4745
18+
### 🗣 Translations
19+
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/4739
20+
### 🧱 Build
21+
* Ensure the CI is marked as failed when Maestro test is failing by @bmarty in https://github.com/element-hq/element-x-android/pull/4700
22+
* Trigger pipeline build when a release tag is pushed by @bmarty in https://github.com/element-hq/element-x-android/pull/4741
23+
* Fix compilation issues. by @bmarty in https://github.com/element-hq/element-x-android/pull/4750
24+
### 📄 Documentation
25+
* README.md: fix broken link by @richvdh in https://github.com/element-hq/element-x-android/pull/4728
26+
### Dependency upgrades
27+
* chore(config): migrate renovate config by @renovate in https://github.com/element-hq/element-x-android/pull/4688
28+
* fix(deps): update dependency org.matrix.rustcomponents:sdk-android to v25.5.13 by @renovate in https://github.com/element-hq/element-x-android/pull/4716
29+
* fix(deps): update dependency io.sentry:sentry-android to v8.12.0 by @renovate in https://github.com/element-hq/element-x-android/pull/4717
30+
* chore(deps): update plugin sonarqube to v6.2.0.5505 by @renovate in https://github.com/element-hq/element-x-android/pull/4725
31+
* fix(deps): update dependency com.posthog:posthog-android to v3.15.0 by @renovate in https://github.com/element-hq/element-x-android/pull/4723
32+
* fix(deps): update dependency com.squareup.retrofit2:retrofit-bom to v2.12.0 by @renovate in https://github.com/element-hq/element-x-android/pull/4727
33+
* chore(deps): update codecov/codecov-action action to v5.4.3 by @renovate in https://github.com/element-hq/element-x-android/pull/4730
34+
* fix(deps): update kotlin by @renovate in https://github.com/element-hq/element-x-android/pull/4713
35+
* fix(deps): update dependency com.squareup.retrofit2:retrofit-bom to v3 by @renovate in https://github.com/element-hq/element-x-android/pull/4729
36+
* fix(deps): update kotlinpoet to v2.2.0 by @renovate in https://github.com/element-hq/element-x-android/pull/4732
37+
* fix(deps): update dependency org.matrix.rustcomponents:sdk-android to v25.5.21 by @renovate in https://github.com/element-hq/element-x-android/pull/4759
38+
### Others
39+
* Remove event cache feature flag by @jmartinesp in https://github.com/element-hq/element-x-android/pull/4719
40+
* Check homeserver when login using qr code by @bmarty in https://github.com/element-hq/element-x-android/pull/4708
41+
* Merge on boarding module to login module by @bmarty in https://github.com/element-hq/element-x-android/pull/4746
42+
* Allow configuration to provide multiple account providers. by @bmarty in https://github.com/element-hq/element-x-android/pull/4742
43+
* Reduce API of JoinedRoom, caller must use the Timeline API from liveTimeline instead by @bmarty in https://github.com/element-hq/element-x-android/pull/4731
44+
45+
46+
**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v25.05.3...v25.05.4
47+
148
Changes in Element X v25.05.3
249
=============================
350

app/src/main/AndroidManifest.xml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,17 @@
3434
android:value='androidx.startup' />
3535
</provider>
3636

37+
<!--
38+
Using launchMode singleTask to avoid multiple instances of the Activity
39+
when the app is already open. This is important for incoming share (see
40+
https://github.com/element-hq/element-x-android/issues/4074) and for opening
41+
the application from a mobile.element.io link.
42+
-->
3743
<activity
3844
android:name=".MainActivity"
3945
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|uiMode"
4046
android:exported="true"
41-
android:launchMode="singleTop"
47+
android:launchMode="singleTask"
4248
android:theme="@style/Theme.ElementX.Splash"
4349
android:windowSoftInputMode="adjustResize">
4450
<intent-filter>
@@ -54,6 +60,9 @@
5460
android:host="open"
5561
android:scheme="elementx" />
5662
</intent-filter>
63+
<!--
64+
Oidc redirection
65+
-->
5766
<intent-filter>
5867
<action android:name="android.intent.action.VIEW" />
5968

@@ -80,6 +89,21 @@
8089
<!-- Matching asset file: https://staging.element.io/.well-known/assetlinks.json -->
8190
<data android:host="staging.element.io" />
8291
</intent-filter>
92+
<!--
93+
Element mobile links
94+
Example: https://mobile.element.io/element?account_provider=example.org&login_hint=mxid:@alice:example.org
95+
-->
96+
<intent-filter android:autoVerify="true">
97+
<action android:name="android.intent.action.VIEW" />
98+
99+
<category android:name="android.intent.category.DEFAULT" />
100+
<category android:name="android.intent.category.BROWSABLE" />
101+
102+
<data android:scheme="https" />
103+
<!-- Matching asset file: https://mobile.element.io/.well-known/assetlinks.json -->
104+
<data android:host="mobile.element.io" />
105+
<data android:path="/element" />
106+
</intent-filter>
83107
<!--
84108
matrix.to links
85109
Note: On Android 12 and higher clicking a web link (that is not an Android App Link) always shows content in a web browser

appnav/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ dependencies {
5353
testImplementation(libs.molecule.runtime)
5454
testImplementation(libs.test.truth)
5555
testImplementation(libs.test.turbine)
56+
testImplementation(projects.features.login.test)
5657
testImplementation(projects.libraries.matrix.test)
5758
testImplementation(projects.libraries.oidc.impl)
5859
testImplementation(projects.libraries.preferences.test)

appnav/src/main/kotlin/io/element/android/appnav/NotLoggedInFlowNode.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ import dagger.assisted.Assisted
2424
import dagger.assisted.AssistedInject
2525
import io.element.android.anvilannotations.ContributesNode
2626
import io.element.android.features.login.api.LoginEntryPoint
27+
import io.element.android.features.login.api.LoginParams
2728
import io.element.android.libraries.architecture.BackstackView
2829
import io.element.android.libraries.architecture.BaseFlowNode
30+
import io.element.android.libraries.architecture.NodeInputs
31+
import io.element.android.libraries.architecture.inputs
2932
import io.element.android.libraries.designsystem.utils.ForceOrientationInMobileDevices
3033
import io.element.android.libraries.designsystem.utils.ScreenOrientation
3134
import io.element.android.libraries.di.AppScope
@@ -46,10 +49,16 @@ class NotLoggedInFlowNode @AssistedInject constructor(
4649
buildContext = buildContext,
4750
plugins = plugins,
4851
) {
52+
data class Params(
53+
val loginParams: LoginParams?,
54+
) : NodeInputs
55+
4956
interface Callback : Plugin {
5057
fun onOpenBugReport()
5158
}
5259

60+
private val inputs = inputs<Params>()
61+
5362
override fun onBuilt() {
5463
super.onBuilt()
5564
lifecycle.subscribe(
@@ -74,6 +83,12 @@ class NotLoggedInFlowNode @AssistedInject constructor(
7483
}
7584
loginEntryPoint
7685
.nodeBuilder(this, buildContext)
86+
.params(
87+
LoginEntryPoint.Params(
88+
accountProvider = inputs.loginParams?.accountProvider,
89+
loginHint = inputs.loginParams?.loginHint,
90+
)
91+
)
7792
.callback(callback)
7893
.build()
7994
}

appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,16 @@ import io.element.android.appnav.intent.ResolvedIntent
3333
import io.element.android.appnav.root.RootNavStateFlowFactory
3434
import io.element.android.appnav.root.RootPresenter
3535
import io.element.android.appnav.root.RootView
36+
import io.element.android.features.enterprise.api.EnterpriseService
37+
import io.element.android.features.login.api.LoginParams
3638
import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint
3739
import io.element.android.features.signedout.api.SignedOutEntryPoint
3840
import io.element.android.features.viewfolder.api.ViewFolderEntryPoint
3941
import io.element.android.libraries.architecture.BackstackView
4042
import io.element.android.libraries.architecture.BaseFlowNode
4143
import io.element.android.libraries.architecture.createNode
4244
import io.element.android.libraries.architecture.waitForChildAttached
45+
import io.element.android.libraries.core.uri.ensureProtocol
4346
import io.element.android.libraries.deeplink.DeeplinkData
4447
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
4548
import io.element.android.libraries.di.AppScope
@@ -61,6 +64,7 @@ class RootFlowNode @AssistedInject constructor(
6164
@Assisted val buildContext: BuildContext,
6265
@Assisted plugins: List<Plugin>,
6366
private val authenticationService: MatrixAuthenticationService,
67+
private val enterpriseService: EnterpriseService,
6468
private val navStateFlowFactory: RootNavStateFlowFactory,
6569
private val matrixSessionCache: MatrixSessionCache,
6670
private val presenter: RootPresenter,
@@ -99,14 +103,14 @@ class RootFlowNode @AssistedInject constructor(
99103
if (navState.loggedInState.isTokenValid) {
100104
tryToRestoreLatestSession(
101105
onSuccess = { sessionId -> switchToLoggedInFlow(sessionId, navState.cacheIndex) },
102-
onFailure = { switchToNotLoggedInFlow() }
106+
onFailure = { switchToNotLoggedInFlow(null) }
103107
)
104108
} else {
105109
switchToSignedOutFlow(SessionId(navState.loggedInState.sessionId))
106110
}
107111
}
108112
LoggedInState.NotLoggedIn -> {
109-
switchToNotLoggedInFlow()
113+
switchToNotLoggedInFlow(null)
110114
}
111115
}
112116
}
@@ -117,9 +121,9 @@ class RootFlowNode @AssistedInject constructor(
117121
backstack.safeRoot(NavTarget.LoggedInFlow(sessionId, navId))
118122
}
119123

120-
private fun switchToNotLoggedInFlow() {
124+
private fun switchToNotLoggedInFlow(params: LoginParams?) {
121125
matrixSessionCache.removeAll()
122-
backstack.safeRoot(NavTarget.NotLoggedInFlow)
126+
backstack.safeRoot(NavTarget.NotLoggedInFlow(params))
123127
}
124128

125129
private fun switchToSignedOutFlow(sessionId: SessionId) {
@@ -175,7 +179,9 @@ class RootFlowNode @AssistedInject constructor(
175179
data object SplashScreen : NavTarget
176180

177181
@Parcelize
178-
data object NotLoggedInFlow : NavTarget
182+
data class NotLoggedInFlow(
183+
val params: LoginParams?
184+
) : NavTarget
179185

180186
@Parcelize
181187
data class LoggedInFlow(
@@ -211,13 +217,16 @@ class RootFlowNode @AssistedInject constructor(
211217
}
212218
createNode<LoggedInAppScopeFlowNode>(buildContext, plugins = listOf(inputs, callback))
213219
}
214-
NavTarget.NotLoggedInFlow -> {
220+
is NavTarget.NotLoggedInFlow -> {
215221
val callback = object : NotLoggedInFlowNode.Callback {
216222
override fun onOpenBugReport() {
217223
backstack.push(NavTarget.BugReport)
218224
}
219225
}
220-
createNode<NotLoggedInFlowNode>(buildContext, plugins = listOf(callback))
226+
val params = NotLoggedInFlowNode.Params(
227+
loginParams = navTarget.params,
228+
)
229+
createNode<NotLoggedInFlowNode>(buildContext, plugins = listOf(params, callback))
221230
}
222231
is NavTarget.SignedOutFlow -> {
223232
signedOutEntryPoint.nodeBuilder(this, buildContext)
@@ -272,18 +281,36 @@ class RootFlowNode @AssistedInject constructor(
272281
val resolvedIntent = intentResolver.resolve(intent) ?: return
273282
when (resolvedIntent) {
274283
is ResolvedIntent.Navigation -> navigateTo(resolvedIntent.deeplinkData)
284+
is ResolvedIntent.Login -> onLoginLink(resolvedIntent.params)
275285
is ResolvedIntent.Oidc -> onOidcAction(resolvedIntent.oidcAction)
276286
is ResolvedIntent.Permalink -> navigateTo(resolvedIntent.permalinkData)
277287
is ResolvedIntent.IncomingShare -> onIncomingShare(resolvedIntent.intent)
278288
}
279289
}
280290

291+
private suspend fun onLoginLink(params: LoginParams) {
292+
// Is there a session already?
293+
val latestSessionId = authenticationService.getLatestSessionId()
294+
if (latestSessionId == null) {
295+
// No session, open login
296+
if (enterpriseService.isAllowedToConnectToHomeserver(params.accountProvider.ensureProtocol())) {
297+
switchToNotLoggedInFlow(params)
298+
} else {
299+
Timber.w("Login link ignored, we are not allowed to connect to the homeserver")
300+
switchToNotLoggedInFlow(null)
301+
}
302+
} else {
303+
// Just ignore the login link if we already have a session
304+
Timber.w("Login link ignored, we already have a session")
305+
}
306+
}
307+
281308
private suspend fun onIncomingShare(intent: Intent) {
282309
// Is there a session already?
283310
val latestSessionId = authenticationService.getLatestSessionId()
284311
if (latestSessionId == null) {
285312
// No session, open login
286-
switchToNotLoggedInFlow()
313+
switchToNotLoggedInFlow(null)
287314
} else {
288315
attachSession(latestSessionId)
289316
.attachIncomingShare(intent)

appnav/src/main/kotlin/io/element/android/appnav/intent/IntentResolver.kt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
package io.element.android.appnav.intent
99

1010
import android.content.Intent
11+
import io.element.android.features.login.api.LoginIntentResolver
12+
import io.element.android.features.login.api.LoginParams
1113
import io.element.android.libraries.deeplink.DeeplinkData
1214
import io.element.android.libraries.deeplink.DeeplinkParser
1315
import io.element.android.libraries.matrix.api.permalink.PermalinkData
@@ -21,11 +23,13 @@ sealed interface ResolvedIntent {
2123
data class Navigation(val deeplinkData: DeeplinkData) : ResolvedIntent
2224
data class Oidc(val oidcAction: OidcAction) : ResolvedIntent
2325
data class Permalink(val permalinkData: PermalinkData) : ResolvedIntent
26+
data class Login(val params: LoginParams) : ResolvedIntent
2427
data class IncomingShare(val intent: Intent) : ResolvedIntent
2528
}
2629

2730
class IntentResolver @Inject constructor(
2831
private val deeplinkParser: DeeplinkParser,
32+
private val loginIntentResolver: LoginIntentResolver,
2933
private val oidcIntentResolver: OidcIntentResolver,
3034
private val permalinkParser: PermalinkParser,
3135
) {
@@ -40,10 +44,17 @@ class IntentResolver @Inject constructor(
4044
val oidcAction = oidcIntentResolver.resolve(intent)
4145
if (oidcAction != null) return ResolvedIntent.Oidc(oidcAction)
4246

43-
// External link clicked? (matrix.to, element.io, etc.)
44-
val permalinkData = intent
47+
val actionViewData = intent
4548
.takeIf { it.action == Intent.ACTION_VIEW }
4649
?.dataString
50+
51+
// Mobile configuration link clicked? (mobile.element.io)
52+
val mobileLoginData = actionViewData
53+
?.let { loginIntentResolver.parse(it) }
54+
if (mobileLoginData != null) return ResolvedIntent.Login(mobileLoginData)
55+
56+
// External link clicked? (matrix.to, element.io, etc.)
57+
val permalinkData = actionViewData
4758
?.let { permalinkParser.parse(it) }
4859
?.takeIf { it !is PermalinkData.FallbackLink }
4960
if (permalinkData != null) return ResolvedIntent.Permalink(permalinkData)

0 commit comments

Comments
 (0)