From 503c9e79e0507503eff649fb4aca150c8b412ecb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Oct 2023 13:14:32 +0200 Subject: [PATCH] Move `appPrompt` and `confineToRoom` to the fragment part of the URL --- .../features/call/CallIntentDataParser.kt | 37 +++++++++++++-- .../call/CallIntentDataParserTests.kt | 45 ++++++++++++++++--- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/features/call/src/main/kotlin/io/element/android/features/call/CallIntentDataParser.kt b/features/call/src/main/kotlin/io/element/android/features/call/CallIntentDataParser.kt index b3e2f9227a..b903b437d8 100644 --- a/features/call/src/main/kotlin/io/element/android/features/call/CallIntentDataParser.kt +++ b/features/call/src/main/kotlin/io/element/android/features/call/CallIntentDataParser.kt @@ -54,21 +54,50 @@ class CallIntentDataParser @Inject constructor() { } /** - * Ensure the uri has the following parameters and value: + * Ensure the uri has the following parameters and value in the fragment: * - appPrompt=false * - confineToRoom=true * to ensure that the rendering will bo correct on the embedded Webview. */ private fun Uri.withCustomParameters(): String { val builder = buildUpon() + // Remove the existing query parameters builder.clearQuery() queryParameterNames.forEach { if (it == APP_PROMPT_PARAMETER || it == CONFINE_TO_ROOM_PARAMETER) return@forEach builder.appendQueryParameter(it, getQueryParameter(it)) } - builder.appendQueryParameter(APP_PROMPT_PARAMETER, "false") - builder.appendQueryParameter(CONFINE_TO_ROOM_PARAMETER, "true") - return builder.build().toString() + // Remove the existing fragment parameters, and build the new fragment + val currentFragment = fragment ?: "" + // Reset the current fragment + builder.fragment("") + val queryFragmentPosition = currentFragment.lastIndexOf("?") + val newFragment = if (queryFragmentPosition == -1) { + // No existing query, build it. + "$currentFragment?$APP_PROMPT_PARAMETER=false&$CONFINE_TO_ROOM_PARAMETER=true" + } else { + buildString { + append(currentFragment.substring(0, queryFragmentPosition + 1)) + val queryFragment = currentFragment.substring(queryFragmentPosition + 1) + // Replace the existing parameters + val newQueryFragment = queryFragment + .replace("$APP_PROMPT_PARAMETER=true", "$APP_PROMPT_PARAMETER=false") + .replace("$CONFINE_TO_ROOM_PARAMETER=false", "$CONFINE_TO_ROOM_PARAMETER=true") + append(newQueryFragment) + // Ensure the parameters are there + if (!newQueryFragment.contains("$APP_PROMPT_PARAMETER=false")) { + if (newQueryFragment.isNotEmpty()) { + append("&") + } + append("$APP_PROMPT_PARAMETER=false") + } + if (!newQueryFragment.contains("$CONFINE_TO_ROOM_PARAMETER=true")) { + append("&$CONFINE_TO_ROOM_PARAMETER=true") + } + } + } + // We do not want to encode the Fragment part, so append it manually + return builder.build().toString() + "#" + newFragment } private const val APP_PROMPT_PARAMETER = "appPrompt" diff --git a/features/call/src/test/kotlin/io/element/android/features/call/CallIntentDataParserTests.kt b/features/call/src/test/kotlin/io/element/android/features/call/CallIntentDataParserTests.kt index aee97ed982..148c2fe30d 100644 --- a/features/call/src/test/kotlin/io/element/android/features/call/CallIntentDataParserTests.kt +++ b/features/call/src/test/kotlin/io/element/android/features/call/CallIntentDataParserTests.kt @@ -63,8 +63,8 @@ class CallIntentDataParserTests { fun `Element Call urls will be returned as is`() { val httpsBaseUrl = "https://call.element.io" val httpsCallUrl = VALID_CALL_URL_WITH_PARAM - assertThat(callIntentDataParser.parse(httpsBaseUrl)).isEqualTo("$httpsBaseUrl?$EXTRA_PARAMS") - assertThat(callIntentDataParser.parse(httpsCallUrl)).isEqualTo("$httpsCallUrl&$EXTRA_PARAMS") + assertThat(callIntentDataParser.parse(httpsBaseUrl)).isEqualTo("$httpsBaseUrl#?$EXTRA_PARAMS") + assertThat(callIntentDataParser.parse(httpsCallUrl)).isEqualTo("$httpsCallUrl#?$EXTRA_PARAMS") } @Test @@ -92,7 +92,7 @@ class CallIntentDataParserTests { val embeddedUrl = VALID_CALL_URL_WITH_PARAM val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8") val url = "element://call?url=$encodedUrl" - assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM&$EXTRA_PARAMS") + assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS") } @Test @@ -108,7 +108,7 @@ class CallIntentDataParserTests { val embeddedUrl = VALID_CALL_URL_WITH_PARAM val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8") val url = "io.element.call:/?url=$encodedUrl" - assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM&$EXTRA_PARAMS") + assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS") } @Test @@ -160,7 +160,15 @@ class CallIntentDataParserTests { val embeddedUrl = "${VALID_CALL_URL_WITH_PARAM}&appPrompt=true" val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8") val url = "io.element.call:/?url=$encodedUrl" - assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM&$EXTRA_PARAMS") + assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS") + } + + @Test + fun `element scheme 2 with url extra param in fragment appPrompt gets url extracted`() { + val embeddedUrl = "${VALID_CALL_URL_WITH_PARAM}#?appPrompt=true" + val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8") + val url = "io.element.call:/?url=$encodedUrl" + assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM#?appPrompt=false&confineToRoom=true") } @Test @@ -168,7 +176,15 @@ class CallIntentDataParserTests { val embeddedUrl = "${VALID_CALL_URL_WITH_PARAM}&confineToRoom=false" val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8") val url = "io.element.call:/?url=$encodedUrl" - assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM&$EXTRA_PARAMS") + assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS") + } + + @Test + fun `element scheme 2 with url extra param in fragment confineToRoom gets url extracted`() { + val embeddedUrl = "${VALID_CALL_URL_WITH_PARAM}#?confineToRoom=false" + val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8") + val url = "io.element.call:/?url=$encodedUrl" + assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM#?confineToRoom=true&appPrompt=false") } @Test @@ -176,9 +192,24 @@ class CallIntentDataParserTests { val embeddedUrl = "${VALID_CALL_URL_WITH_PARAM}#fragment" val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8") val url = "io.element.call:/?url=$encodedUrl" - assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM&$EXTRA_PARAMS#fragment") + assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM#fragment?$EXTRA_PARAMS") } + @Test + fun `element scheme 2 with empty fragment`() { + val embeddedUrl = "${VALID_CALL_URL_WITH_PARAM}#" + val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8") + val url = "io.element.call:/?url=$encodedUrl" + assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS") + } + + @Test + fun `element scheme 2 with empty fragment and fragment query`() { + val embeddedUrl = "${VALID_CALL_URL_WITH_PARAM}#?" + val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8") + val url = "io.element.call:/?url=$encodedUrl" + assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS") + } companion object { const val VALID_CALL_URL_WITH_PARAM = "https://call.element.io/some-actual-call?with=parameters"