mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 12:07:28 +00:00
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:
+3
-1
@@ -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"
|
||||
|
||||
+9
-9
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -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//"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-10
@@ -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/",
|
||||
|
||||
+33
-2
@@ -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"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user