feat(deeplink): point deeplinks at HealthChat hosts

Claims app.healthchat.ch and to.healthchat.ch as App Links, registers the
healthchat:// scheme, and drops the unreachable mobile.element.io handling.
This commit is contained in:
2026-08-03 10:53:35 +02:00
parent d6ea73140e
commit 57a2e585ba
15 changed files with 155 additions and 168 deletions
@@ -8,23 +8,18 @@
package io.element.android.features.login.impl
import androidx.core.net.toUri
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.login.api.LoginIntentResolver
import io.element.android.features.login.api.LoginParams
/**
* HealthChat does not support mobile configuration links: the account provider is fixed to the
* HealthChat homeserver (see DefaultEnterpriseService.defaultHomeserverList), so there is nothing
* for such a link to configure. The matching intent-filter has been removed from the manifest as
* well, which means nothing can deliver such an intent in the first place.
*/
@ContributesBinding(AppScope::class)
class DefaultLoginIntentResolver : LoginIntentResolver {
override fun parse(uriString: String): LoginParams? {
val uri = uriString.toUri()
if (uri.host != "mobile.element.io") return null
if (uri.path.orEmpty().startsWith("/element").not()) return null
val accountProvider = uri.getQueryParameter("account_provider") ?: return null
val loginHint = uri.getQueryParameter("login_hint")
return LoginParams(
accountProvider = accountProvider,
loginHint = loginHint,
)
}
override fun parse(uriString: String): LoginParams? = null
}
@@ -9,72 +9,20 @@
package io.element.android.features.login.impl
import com.google.common.truth.Truth.assertThat
import io.element.android.features.login.api.LoginParams
import io.element.android.tests.testutils.robolectric.RobolectricTest
import org.junit.Test
class DefaultLoginIntentResolverTest : RobolectricTest() {
@Test
fun `nominal case`() {
fun `mobile configuration links are not supported`() {
val sut = DefaultLoginIntentResolver()
val uriString = "https://mobile.element.io/element/?account_provider=example.org&login_hint=mxid:@alice:example.org"
assertThat(sut.parse(uriString)).isEqualTo(
LoginParams(
accountProvider = "example.org",
loginHint = "mxid:@alice:example.org",
)
)
}
@Test
fun `extra unknown param`() {
val sut = DefaultLoginIntentResolver()
val uriString = "https://mobile.element.io/element/?account_provider=example.org&login_hint=mxid:@alice:example.org&extra=uknown"
assertThat(sut.parse(uriString)).isEqualTo(
LoginParams(
accountProvider = "example.org",
loginHint = "mxid:@alice:example.org",
)
)
}
@Test
fun `no account provider`() {
val sut = DefaultLoginIntentResolver()
val uriString = "https://mobile.element.io/element/?login_hint=mxid:@alice:example.org"
assertThat(sut.parse(uriString)).isNull()
}
@Test
fun `no path`() {
fun `an arbitrary uri returns null`() {
val sut = DefaultLoginIntentResolver()
val uriString = "https://mobile.element.io?account_provider=example.org&login_hint=mxid:@alice:example.org"
assertThat(sut.parse(uriString)).isNull()
}
@Test
fun `wrong path`() {
val sut = DefaultLoginIntentResolver()
val uriString = "https://mobile.element.io/wrong?account_provider=example.org&login_hint=mxid:@alice:example.org"
assertThat(sut.parse(uriString)).isNull()
}
@Test
fun `wrong host`() {
val sut = DefaultLoginIntentResolver()
val uriString = "https://wrong.element.io/element/?account_provider=example.org&login_hint=mxid:@alice:example.org"
assertThat(sut.parse(uriString)).isNull()
}
@Test
fun `no login_hint param`() {
val sut = DefaultLoginIntentResolver()
val uriString = "https://mobile.element.io/element/?account_provider=example.org"
assertThat(sut.parse(uriString)).isEqualTo(
LoginParams(
accountProvider = "example.org",
loginHint = null,
)
)
assertThat(sut.parse("https://app.healthchat.ch/#/room/#room:healthchat.ch")).isNull()
}
}