From 57a2e585ba2086379c660f0d3acdf5f1218807bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl?= Date: Mon, 3 Aug 2026 10:53:35 +0200 Subject: [PATCH] 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. --- app/src/main/AndroidManifest.xml | 40 ++++--------- .../android/appconfig/MatrixConfiguration.kt | 14 +++++ docs/deeplink.md | 60 ++++++++++++------- .../login/impl/DefaultLoginIntentResolver.kt | 19 +++--- .../impl/DefaultLoginIntentResolverTest.kt | 58 +----------------- .../libraries/deeplink/impl/Constants.kt | 4 +- .../impl/DefaultDeepLinkCreatorTest.kt | 18 +++--- .../impl/DefaultDeeplinkParserTest.kt | 20 +++---- .../permalink/DefaultMatrixToConverter.kt | 24 ++++---- .../permalink/DefaultMatrixToConverterTest.kt | 35 ++++++++++- tools/adb/deeplink.sh | 12 ++-- ...nk_element.sh => deeplink_customscheme.sh} | 2 +- tools/adb/deeplink_external.sh | 2 +- tools/adb/deeplink_matrixto.sh | 2 +- tools/adb/deeplink_mobile.sh | 13 ---- 15 files changed, 155 insertions(+), 168 deletions(-) rename tools/adb/{deeplink_element.sh => deeplink_customscheme.sh} (82%) delete mode 100755 tools/adb/deeplink_mobile.sh diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d63e18ec1a..292d1e6ebe 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -52,7 +52,7 @@ Using launchMode singleTask to avoid multiple instances of the Activity when the app is already open. This is important for incoming share (see https://github.com/element-hq/element-x-android/issues/4074) and for opening - the application from a mobile.element.io link. + the application from a permalink. --> + android:scheme="healthchat" /> @@ -95,28 +97,12 @@ - - - - - - - - - - - - - - - - - - - + + + + + + @@ -138,7 +124,7 @@ - + diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/MatrixConfiguration.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/MatrixConfiguration.kt index 76b96bf398..2232aca942 100644 --- a/appconfig/src/main/kotlin/io/element/android/appconfig/MatrixConfiguration.kt +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/MatrixConfiguration.kt @@ -10,5 +10,19 @@ package io.element.android.appconfig object MatrixConfiguration { const val MATRIX_TO_PERMALINK_BASE_URL: String = "https://matrix.to/#/" + + /** + * HealthChat's own matrix.to deployment (https://github.com/Novaloop-AG/healthchat-matrix.to). + * It uses the exact same URL format as matrix.to, so links can be translated by swapping the + * base URL. Used both to recognise incoming links and to build links shared outside of Matrix. + */ + const val HEALTHCHAT_TO_PERMALINK_BASE_URL: String = "https://to.healthchat.ch/#/" + + /** + * Base URL of the HealthChat web client, which is what the healthchat:// custom scheme + * handed out by [HEALTHCHAT_TO_PERMALINK_BASE_URL] points to. + */ + const val HEALTHCHAT_WEB_BASE_URL: String = "https://app.healthchat.ch/#/" + val clientPermalinkBaseUrl: String? = null } diff --git a/docs/deeplink.md b/docs/deeplink.md index 1350b2f736..651769b6c2 100644 --- a/docs/deeplink.md +++ b/docs/deeplink.md @@ -1,4 +1,4 @@ -# Element X Android deeplink +# HealthChat Android deeplink @@ -12,31 +12,45 @@ ## Introduction -Element X Android supports deep linking to specific screens in the application. This document explains how to use deep links in Element X Android. +HealthChat Android supports deep linking to specific screens in the application. This document explains how to use deep links in HealthChat Android. ### Asset Links -The asset links file is available at https://element.io/.well-known/assetlinks.json +Two hosts are claimed as verified Android App Links, and each one must serve a matching asset links +file listing `ch.healthchat.element` and the SHA-256 of the Play app signing certificate: + +| Host | Asset links file | Served from | +|---|---|---| +| `app.healthchat.ch` | https://app.healthchat.ch/.well-known/assetlinks.json | the `element-web` fork (`apps/web/res/.well-known/assetlinks.json`) | +| `to.healthchat.ch` | https://to.healthchat.ch/.well-known/assetlinks.json | the `healthchat-matrix.to` fork (generated by `scripts/build.js`) | ### Supported links -Element Call link: -> https://call.element.io/Example - Link to a user: -> https://app.element.io/#/user/@alice:matrix.org +> https://to.healthchat.ch/#/@alice:healthchat.ch +> https://app.healthchat.ch/#/user/@alice:healthchat.ch Link to a room by id or alias: -> https://app.element.io/#/room/!roomid:matrix.org -> https://app.element.io/#/room/#element-x-android:matrix.org +> https://to.healthchat.ch/#/!roomid:healthchat.ch +> https://app.healthchat.ch/#/room/#healthchat:healthchat.ch Link to a room with a specific event: -> https://app.element.io/#/room/!roomid:matrix.org/$eventid +> https://app.healthchat.ch/#/room/!roomid:healthchat.ch/$eventid -Note that it will also work with other domain such as: -> https://mobile.element.io -> https://develop.element.io -> https://staging.element.io +The HealthChat matrix.to deployment hands out a custom scheme to Android, which is registered too: +> healthchat://room/%23healthchat%3Ahealthchat.ch +> healthchat://user/%40alice%3Ahealthchat.ch + +Standard Matrix URIs also work: +> matrix:r/healthchat:healthchat.ch + +Only the two hosts above are declared in the manifest, so only those open the app from a browser. +`DefaultMatrixToConverter` is host-agnostic though: any URL using the `/#/room/`, `/#/user/` or +`/#/group/` path, as well as plain matrix.to links, are still resolved once they reach the app +(for instance when tapped inside a message). + +Finally, notifications use an internal deep link that is not browsable: +> healthchat://open/{sessionId}/{roomId}/{eventId} ## Developer tools @@ -44,28 +58,34 @@ Using an Android 12 or higher emulator Ensure links verification is enabled ```bash -adb shell am compat enable 175408749 io.element.android.x.debug +adb shell am compat enable 175408749 ch.healthchat.element.debug ``` Reset link verifications for the given package id ```bash -adb shell pm set-app-links --package io.element.android.x.debug 0 all +adb shell pm set-app-links --package ch.healthchat.element.debug 0 all ``` Force the package id links to be verified ```bash -adb shell pm verify-app-links --re-verify io.element.android.x.debug +adb shell pm verify-app-links --re-verify ch.healthchat.element.debug ``` Print the link verification of the package id ```bash -adb shell pm get-app-links io.element.android.x.debug +adb shell pm get-app-links ch.healthchat.element.debug ``` ``` - io.element.android.x.debug: + ch.healthchat.element.debug: ID: e2ece472-c266-4bf0-829c-be79959a6270 Signatures: [B0:B0:51:DC:56:5C:81:2F:E1:7F:6F:3E:94:5B:4D:79:04:71:23:AB:0D:A6:12:86:76:9E:B2:94:91:97:13:0E] Domain verification state: - *.element.io: 1024 + app.healthchat.ch: verified + to.healthchat.ch: verified ``` + +Verification only succeeds if the signature above is listed in the asset links files. Release builds +are signed by Google Play, so use the app signing certificate SHA-256 from the Play Console. For a +debug build, add the fingerprint of `app/signature/debug.keystore` (alias `androiddebugkey`) to both +files, or test with `healthchat://` links instead, which need no verification. diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolver.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolver.kt index 26f0f1737e..1f28a22ce1 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolver.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolver.kt @@ -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 } diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolverTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolverTest.kt index feeeb982c4..4467f9a00b 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolverTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolverTest.kt @@ -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() } } diff --git a/libraries/deeplink/impl/src/main/kotlin/io/element/android/libraries/deeplink/impl/Constants.kt b/libraries/deeplink/impl/src/main/kotlin/io/element/android/libraries/deeplink/impl/Constants.kt index 5bea982f43..72cb77ae03 100644 --- a/libraries/deeplink/impl/src/main/kotlin/io/element/android/libraries/deeplink/impl/Constants.kt +++ b/libraries/deeplink/impl/src/main/kotlin/io/element/android/libraries/deeplink/impl/Constants.kt @@ -8,5 +8,7 @@ package io.element.android.libraries.deeplink.impl -internal const val SCHEME = "elementx" +// Internal deep link, only used to build the notification PendingIntents. The "open" host keeps +// it distinct from the healthchat://room|user links handed out by the HealthChat matrix.to site. +internal const val SCHEME = "healthchat" internal const val HOST = "open" diff --git a/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeepLinkCreatorTest.kt b/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeepLinkCreatorTest.kt index b27a645802..a912f2f095 100644 --- a/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeepLinkCreatorTest.kt +++ b/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeepLinkCreatorTest.kt @@ -28,15 +28,15 @@ class DefaultDeepLinkCreatorTest { val threadId = A_THREAD_ID val eventId = AN_EVENT_ID assertThat(sut.create(sessionId, null, null, null)) - .isEqualTo("elementx://open/%40alice%3Aserver.org") + .isEqualTo("healthchat://open/%40alice%3Aserver.org") assertThat(sut.create(sessionId, roomId, null, null)) - .isEqualTo("elementx://open/%40alice%3Aserver.org/%21aRoomId%3Adomain") + .isEqualTo("healthchat://open/%40alice%3Aserver.org/%21aRoomId%3Adomain") assertThat(sut.create(sessionId, roomId, threadId, null)) - .isEqualTo("elementx://open/%40alice%3Aserver.org/%21aRoomId%3Adomain/%24aThreadId") + .isEqualTo("healthchat://open/%40alice%3Aserver.org/%21aRoomId%3Adomain/%24aThreadId") assertThat(sut.create(sessionId, roomId, threadId, eventId)) - .isEqualTo("elementx://open/%40alice%3Aserver.org/%21aRoomId%3Adomain/%24aThreadId/%24anEventId") + .isEqualTo("healthchat://open/%40alice%3Aserver.org/%21aRoomId%3Adomain/%24aThreadId/%24anEventId") assertThat(sut.create(sessionId, roomId, null, eventId)) - .isEqualTo("elementx://open/%40alice%3Aserver.org/%21aRoomId%3Adomain//%24anEventId") + .isEqualTo("healthchat://open/%40alice%3Aserver.org/%21aRoomId%3Adomain//%24anEventId") } @Test @@ -47,12 +47,12 @@ class DefaultDeepLinkCreatorTest { val threadId = ThreadId("\$a/ThreadId") val eventId = EventId("\$an/EventId") assertThat(sut.create(sessionId, roomId, null, null)) - .isEqualTo("elementx://open/%40a%2F%3Adomain/%21a%2FRoomId%3Adomain") + .isEqualTo("healthchat://open/%40a%2F%3Adomain/%21a%2FRoomId%3Adomain") assertThat(sut.create(sessionId, roomId, threadId, null)) - .isEqualTo("elementx://open/%40a%2F%3Adomain/%21a%2FRoomId%3Adomain/%24a%2FThreadId") + .isEqualTo("healthchat://open/%40a%2F%3Adomain/%21a%2FRoomId%3Adomain/%24a%2FThreadId") assertThat(sut.create(sessionId, roomId, threadId, eventId)) - .isEqualTo("elementx://open/%40a%2F%3Adomain/%21a%2FRoomId%3Adomain/%24a%2FThreadId/%24an%2FEventId") + .isEqualTo("healthchat://open/%40a%2F%3Adomain/%21a%2FRoomId%3Adomain/%24a%2FThreadId/%24an%2FEventId") assertThat(sut.create(sessionId, roomId, null, eventId)) - .isEqualTo("elementx://open/%40a%2F%3Adomain/%21a%2FRoomId%3Adomain//%24an%2FEventId") + .isEqualTo("healthchat://open/%40a%2F%3Adomain/%21a%2FRoomId%3Adomain//%24an%2FEventId") } } diff --git a/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeeplinkParserTest.kt b/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeeplinkParserTest.kt index a6502aabf1..dcd2707b87 100644 --- a/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeeplinkParserTest.kt +++ b/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeeplinkParserTest.kt @@ -27,17 +27,17 @@ import org.junit.Test class DefaultDeeplinkParserTest : RobolectricTest() { companion object { const val A_URI = - "elementx://open/@alice:server.org" + "healthchat://open/@alice:server.org" const val A_URI_WITH_ROOM = - "elementx://open/@alice:server.org/!aRoomId:domain" + "healthchat://open/@alice:server.org/!aRoomId:domain" const val A_URI_WITH_ROOM_WITH_THREAD = - "elementx://open/@alice:server.org/!aRoomId:domain/\$aThreadId" + "healthchat://open/@alice:server.org/!aRoomId:domain/\$aThreadId" const val A_URI_WITH_ROOM_WITH_THREAD_AND_EVENT = - "elementx://open/@alice:server.org/!aRoomId:domain/\$aThreadId/\$anEventId" + "healthchat://open/@alice:server.org/!aRoomId:domain/\$aThreadId/\$anEventId" const val A_URI_WITH_ROOM_WITH_EVENT_AND_NO_THREAD = - "elementx://open/@alice:server.org/!aRoomId:domain//\$anEventId" + "healthchat://open/@alice:server.org/!aRoomId:domain//\$anEventId" const val A_URI_WITH_ROOM_WITH_THREAD_AND_EVENT_AND_INVALID_CHARACTERS = - "elementx://open/@a%2Flice:server.org/!a%2FRoomId:domain/\$a%2FThreadId/\$an%2FEventId" + "healthchat://open/@a%2Flice:server.org/!a%2FRoomId:domain/\$a%2FThreadId/\$an%2FEventId" } @Test @@ -70,17 +70,17 @@ class DefaultDeeplinkParserTest : RobolectricTest() { // Bad scheme assertThat(sut.getFromIntent(createIntent("x://open/@alice:server.org"))).isNull() // Bad host - assertThat(sut.getFromIntent(createIntent("elementx://close/@alice:server.org"))).isNull() + assertThat(sut.getFromIntent(createIntent("healthchat://close/@alice:server.org"))).isNull() // No session Id - assertThat(sut.getFromIntent(createIntent("elementx://open"))).isNull() + assertThat(sut.getFromIntent(createIntent("healthchat://open"))).isNull() assertThrowsInDebug { // Invalid sessionId - sut.getFromIntent(createIntent("elementx://open/alice:server.org")) + sut.getFromIntent(createIntent("healthchat://open/alice:server.org")) } assertThrowsInDebug { // Empty sessionId - sut.getFromIntent(createIntent("elementx://open//")) + sut.getFromIntent(createIntent("healthchat://open//")) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverter.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverter.kt index efb106acd3..f1cf90b8ea 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverter.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverter.kt @@ -22,25 +22,29 @@ import io.element.android.libraries.matrix.api.permalink.MatrixToConverter @ContributesBinding(AppScope::class) class DefaultMatrixToConverter : MatrixToConverter { /** - * Try to convert a URL from an element web instance or from a client permalink to a matrix.to url. + * Try to convert a URL from a web client instance or from a client permalink to a matrix.to url. * To be successfully converted, URL path should contain one of the [SUPPORTED_PATHS]. * Examples: * - https://riot.im/develop/#/room/#element-android:matrix.org -> https://matrix.to/#/#element-android:matrix.org - * - https://app.element.io/#/room/#element-android:matrix.org -> https://matrix.to/#/#element-android:matrix.org + * - https://app.healthchat.ch/#/room/#room:healthchat.ch -> https://matrix.to/#/#room:healthchat.ch * - https://www.example.org/#/room/#element-android:matrix.org -> https://matrix.to/#/#element-android:matrix.org - * Also convert links coming from the matrix.to website: - * - element://room/#element-android:matrix.org -> https://matrix.to/#/#element-android:matrix.org - * - element://user/@alice:matrix.org -> https://matrix.to/#/@alice:matrix.org + * Also convert links coming from the HealthChat matrix.to website, which uses the matrix.to URL + * format on its own host and hands out a custom scheme to Android: + * - https://to.healthchat.ch/#/#room:healthchat.ch -> https://matrix.to/#/#room:healthchat.ch + * - healthchat://room/#room:healthchat.ch -> https://matrix.to/#/#room:healthchat.ch + * - healthchat://user/@alice:healthchat.ch -> https://matrix.to/#/@alice:healthchat.ch */ override fun convert(uri: Uri): Uri? { - val uriString = uri.toString() - // Handle links coming from the matrix.to website. - .replacePrefix(MATRIX_TO_CUSTOM_SCHEME_BASE_URL, "https://app.element.io/#/") val baseUrl = MatrixConfiguration.MATRIX_TO_PERMALINK_BASE_URL + val uriString = uri.toString() + // Handle the custom scheme handed out by the HealthChat matrix.to website. + .replacePrefix(MATRIX_TO_CUSTOM_SCHEME_BASE_URL, MatrixConfiguration.HEALTHCHAT_WEB_BASE_URL) + // Our own matrix.to deployment already uses the matrix.to URL format. + .replacePrefix(MatrixConfiguration.HEALTHCHAT_TO_PERMALINK_BASE_URL, baseUrl) return when { // URL is already a matrix.to - uriString.startsWith(baseUrl) -> uri + uriString.startsWith(baseUrl) -> uriString.toUri() // Web or client url SUPPORTED_PATHS.any { it in uriString } -> { val path = SUPPORTED_PATHS.first { it in uriString } @@ -52,7 +56,7 @@ class DefaultMatrixToConverter : MatrixToConverter { } companion object { - private const val MATRIX_TO_CUSTOM_SCHEME_BASE_URL = "element://" + private const val MATRIX_TO_CUSTOM_SCHEME_BASE_URL = "healthchat://" private val SUPPORTED_PATHS = listOf( "/#/room/", "/#/user/", diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverterTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverterTest.kt index 97b51c0026..88c0d179f1 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverterTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverterTest.kt @@ -44,15 +44,46 @@ class DefaultMatrixToConverterTest : RobolectricTest() { assertThat(DefaultMatrixToConverter().convert(url)).isNull() } + @Test + fun `converting the root url of the HealthChat matrix-to website returns null`() { + val url = Uri.parse("https://to.healthchat.ch/") + assertThat(DefaultMatrixToConverter().convert(url)).isNull() + } + + @Test + fun `converting a url from the HealthChat matrix-to website returns a matrix-to url for room case`() { + val url = Uri.parse("https://to.healthchat.ch/#/#room:healthchat.ch") + assertThat(DefaultMatrixToConverter().convert(url)).isEqualTo(Uri.parse("https://matrix.to/#/#room:healthchat.ch")) + } + + @Test + fun `converting a url from the HealthChat matrix-to website returns a matrix-to url for user case`() { + val url = Uri.parse("https://to.healthchat.ch/#/@alice:healthchat.ch") + assertThat(DefaultMatrixToConverter().convert(url)).isEqualTo(Uri.parse("https://matrix.to/#/@alice:healthchat.ch")) + } + + @Test + fun `converting a url from the HealthChat web client returns a matrix-to url`() { + val url = Uri.parse("https://app.healthchat.ch/#/room/%23room%3Ahealthchat.ch") + assertThat(DefaultMatrixToConverter().convert(url)).isEqualTo(Uri.parse("https://matrix.to/#/%23room%3Ahealthchat.ch")) + } + @Test fun `converting url coming from the matrix-to website returns a matrix-to url for room case`() { - val url = Uri.parse("element://room/#element-android:matrix.org") + val url = Uri.parse("healthchat://room/#element-android:matrix.org") assertThat(DefaultMatrixToConverter().convert(url)).isEqualTo(Uri.parse("https://matrix.to/#/#element-android:matrix.org")) } @Test fun `converting url coming from the matrix-to website returns a matrix-to url for user case`() { - val url = Uri.parse("element://user/@alice:matrix.org") + val url = Uri.parse("healthchat://user/@alice:matrix.org") assertThat(DefaultMatrixToConverter().convert(url)).isEqualTo(Uri.parse("https://matrix.to/#/@alice:matrix.org")) } + + @Test + fun `converting an event url coming from the matrix-to website keeps the event id and the via params`() { + val url = Uri.parse("healthchat://room/%23room%3Ahealthchat.ch/%24eventId?via=healthchat.ch") + assertThat(DefaultMatrixToConverter().convert(url)) + .isEqualTo(Uri.parse("https://matrix.to/#/%23room%3Ahealthchat.ch/%24eventId?via=healthchat.ch")) + } } diff --git a/tools/adb/deeplink.sh b/tools/adb/deeplink.sh index d9ee729972..9edc37b515 100755 --- a/tools/adb/deeplink.sh +++ b/tools/adb/deeplink.sh @@ -7,13 +7,13 @@ # Please see LICENSE files in the repository root for full details. # Format is: -# elementx://open/{sessionId} to open a session -# elementx://open/{sessionId}/{roomId} to open a room -# elementx://open/{sessionId}/{roomId}/{eventId} to open a thread +# healthchat://open/{sessionId} to open a session +# healthchat://open/{sessionId}/{roomId} to open a room +# healthchat://open/{sessionId}/{roomId}/{eventId} to open a thread # Open a session -# adb shell am start -a android.intent.action.VIEW -d elementx://open/@benoit10518:matrix.org +# adb shell am start -a android.intent.action.VIEW -d healthchat://open/@benoit10518:matrix.org # Open a room -adb shell am start -a android.intent.action.VIEW -d elementx://open/@benoit10518:matrix.org/!dehdDVSkabQLZFYrgo:matrix.org +adb shell am start -a android.intent.action.VIEW -d healthchat://open/@benoit10518:matrix.org/!dehdDVSkabQLZFYrgo:matrix.org # Open a thread -# adb shell am start -a android.intent.action.VIEW -d elementx://open/@benoit10518:matrix.org/!dehdDVSkabQLZFYrgo:matrix.org/\\\$threadId +# adb shell am start -a android.intent.action.VIEW -d healthchat://open/@benoit10518:matrix.org/!dehdDVSkabQLZFYrgo:matrix.org/\\\$threadId diff --git a/tools/adb/deeplink_element.sh b/tools/adb/deeplink_customscheme.sh similarity index 82% rename from tools/adb/deeplink_element.sh rename to tools/adb/deeplink_customscheme.sh index 7bc48a5fe8..a462bbd853 100755 --- a/tools/adb/deeplink_element.sh +++ b/tools/adb/deeplink_customscheme.sh @@ -6,4 +6,4 @@ # Please see LICENSE files in the repository root for full details. adb shell am start -a android.intent.action.VIEW \ - -d "element://room/%23element-android%3Amatrix.org" + -d "healthchat://room/%23healthchat%3Ahealthchat.ch" diff --git a/tools/adb/deeplink_external.sh b/tools/adb/deeplink_external.sh index 3c3f299c4b..5fa638fd2c 100755 --- a/tools/adb/deeplink_external.sh +++ b/tools/adb/deeplink_external.sh @@ -7,4 +7,4 @@ # Please see LICENSE files in the repository root for full details. adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE \ - -d "https://app.element.io/#/room/!cuqHozLHNBgupgLMKN:matrix.org/%24LZDOueY3R8OD2ZYf8FLKtu95aF7imLBC3F5TIUj-4cc" + -d "https://app.healthchat.ch/#/room/!cuqHozLHNBgupgLMKN:healthchat.ch/%24LZDOueY3R8OD2ZYf8FLKtu95aF7imLBC3F5TIUj-4cc" diff --git a/tools/adb/deeplink_matrixto.sh b/tools/adb/deeplink_matrixto.sh index 5f125f9db7..b883a0541f 100755 --- a/tools/adb/deeplink_matrixto.sh +++ b/tools/adb/deeplink_matrixto.sh @@ -7,4 +7,4 @@ # Please see LICENSE files in the repository root for full details. adb shell am start -a android.intent.action.VIEW \ - -d "https://matrix.to/#/#matrix:matrix.org" + -d "https://to.healthchat.ch/#/#healthchat:healthchat.ch" diff --git a/tools/adb/deeplink_mobile.sh b/tools/adb/deeplink_mobile.sh deleted file mode 100755 index 43c4690f48..0000000000 --- a/tools/adb/deeplink_mobile.sh +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/bash - -# Copyright (c) 2025 Element Creations Ltd. -# Copyright 2025 New Vector Ltd. -# -# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. -# Please see LICENSE files in the repository root for full details. - -# Format is: -# https://mobile.element.io/element/?account_provider=example.org&login_hint=mxid:@alice:example.org - -adb shell am start -a android.intent.action.VIEW \ - -d "https://mobile.element.io/element/?account_provider=element.io\\&login_hint=mxid:@alice:element.io"