Merge pull request #1434 from vector-im/feature/bma/elementCallTweaks
Element call tweaks
This commit is contained in:
1
changelog.d/1434.misc
Normal file
1
changelog.d/1434.misc
Normal file
@@ -0,0 +1 @@
|
||||
Element call: add custom parameters to Element Call urls.
|
||||
@@ -39,7 +39,6 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
|
||||
<data android:host="call.element.io" />
|
||||
|
||||
@@ -21,13 +21,13 @@ import javax.inject.Inject
|
||||
|
||||
class CallIntentDataParser @Inject constructor() {
|
||||
|
||||
private val validHttpSchemes = sequenceOf("http", "https")
|
||||
private val validHttpSchemes = sequenceOf("https")
|
||||
|
||||
fun parse(data: String?): String? {
|
||||
val parsedUrl = data?.let { Uri.parse(data) } ?: return null
|
||||
val scheme = parsedUrl.scheme
|
||||
return when {
|
||||
scheme in validHttpSchemes && parsedUrl.host == "call.element.io" -> data
|
||||
scheme in validHttpSchemes && parsedUrl.host == "call.element.io" -> parsedUrl
|
||||
scheme == "element" && parsedUrl.host == "call" -> {
|
||||
// We use this custom scheme to load arbitrary URLs for other instances of Element Call,
|
||||
// so we can only verify it's an HTTP/HTTPs URL with a non-empty host
|
||||
@@ -40,14 +40,36 @@ class CallIntentDataParser @Inject constructor() {
|
||||
}
|
||||
// This should never be possible, but we still need to take into account the possibility
|
||||
else -> null
|
||||
}
|
||||
}?.withCustomParameters()
|
||||
}
|
||||
|
||||
private fun Uri.getUrlParameter(): String? {
|
||||
private fun Uri.getUrlParameter(): Uri? {
|
||||
return getQueryParameter("url")
|
||||
?.takeIf {
|
||||
val internalUri = Uri.parse(it)
|
||||
internalUri.scheme in validHttpSchemes && !internalUri.host.isNullOrBlank()
|
||||
?.let { urlParameter ->
|
||||
Uri.parse(urlParameter).takeIf { uri ->
|
||||
uri.scheme in validHttpSchemes && !uri.host.isNullOrBlank()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the uri has the following parameters and value:
|
||||
* - appPrompt=false
|
||||
* - confineToRoom=true
|
||||
* to ensure that the rendering will bo correct on the embedded Webview.
|
||||
*/
|
||||
private fun Uri.withCustomParameters(): String {
|
||||
val builder = buildUpon()
|
||||
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()
|
||||
}
|
||||
|
||||
private const val APP_PROMPT_PARAMETER = "appPrompt"
|
||||
private const val CONFINE_TO_ROOM_PARAMETER = "confineToRoom"
|
||||
|
||||
@@ -52,15 +52,19 @@ class CallIntentDataParserTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Element Call urls will be returned as is`() {
|
||||
fun `Element Call http urls returns null`() {
|
||||
val httpBaseUrl = "http://call.element.io"
|
||||
val httpCallUrl = "http://call.element.io/some-actual-call?with=parameters"
|
||||
assertThat(callIntentDataParser.parse(httpBaseUrl)).isNull()
|
||||
assertThat(callIntentDataParser.parse(httpCallUrl)).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Element Call urls will be returned as is`() {
|
||||
val httpsBaseUrl = "https://call.element.io"
|
||||
val httpsCallUrl = "https://call.element.io/some-actual-call?with=parameters"
|
||||
assertThat(callIntentDataParser.parse(httpBaseUrl)).isEqualTo(httpBaseUrl)
|
||||
assertThat(callIntentDataParser.parse(httpCallUrl)).isEqualTo(httpCallUrl)
|
||||
assertThat(callIntentDataParser.parse(httpsBaseUrl)).isEqualTo(httpsBaseUrl)
|
||||
assertThat(callIntentDataParser.parse(httpsCallUrl)).isEqualTo(httpsCallUrl)
|
||||
val httpsCallUrl = VALID_CALL_URL_WITH_PARAM
|
||||
assertThat(callIntentDataParser.parse(httpsBaseUrl)).isEqualTo("$httpsBaseUrl?$EXTRA_PARAMS")
|
||||
assertThat(callIntentDataParser.parse(httpsCallUrl)).isEqualTo("$httpsCallUrl&$EXTRA_PARAMS")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -76,19 +80,35 @@ class CallIntentDataParserTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `element scheme with call host and url param gets url extracted`() {
|
||||
fun `element scheme with call host and url with http will returns null`() {
|
||||
val embeddedUrl = "http://call.element.io/some-actual-call?with=parameters"
|
||||
val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
|
||||
val url = "element://call?url=$encodedUrl"
|
||||
assertThat(callIntentDataParser.parse(url)).isEqualTo(embeddedUrl)
|
||||
assertThat(callIntentDataParser.parse(url)).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `element scheme with call host and url param gets url extracted`() {
|
||||
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")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `element scheme 2 with url param with http returns null`() {
|
||||
val embeddedUrl = "http://call.element.io/some-actual-call?with=parameters"
|
||||
val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
|
||||
val url = "io.element.call:/?url=$encodedUrl"
|
||||
assertThat(callIntentDataParser.parse(url)).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `element scheme 2 with url param gets url extracted`() {
|
||||
val embeddedUrl = "http://call.element.io/some-actual-call?with=parameters"
|
||||
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(embeddedUrl)
|
||||
assertThat(callIntentDataParser.parse(url)).isEqualTo("$VALID_CALL_URL_WITH_PARAM&$EXTRA_PARAMS")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -101,7 +121,7 @@ class CallIntentDataParserTests {
|
||||
|
||||
@Test
|
||||
fun `element scheme 2 with no url returns null`() {
|
||||
val embeddedUrl = "http://call.element.io/some-actual-call?with=parameters"
|
||||
val embeddedUrl = VALID_CALL_URL_WITH_PARAM
|
||||
val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
|
||||
val url = "io.element.call:/?no_url=$encodedUrl"
|
||||
assertThat(callIntentDataParser.parse(url)).isNull()
|
||||
@@ -109,7 +129,7 @@ class CallIntentDataParserTests {
|
||||
|
||||
@Test
|
||||
fun `element scheme with no call host returns null`() {
|
||||
val embeddedUrl = "http://call.element.io/some-actual-call?with=parameters"
|
||||
val embeddedUrl = VALID_CALL_URL_WITH_PARAM
|
||||
val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
|
||||
val url = "element://no-call?url=$encodedUrl"
|
||||
assertThat(callIntentDataParser.parse(url)).isNull()
|
||||
@@ -129,9 +149,39 @@ class CallIntentDataParserTests {
|
||||
|
||||
@Test
|
||||
fun `element invalid scheme returns null`() {
|
||||
val embeddedUrl = "http://call.element.io/some-actual-call?with=parameters"
|
||||
val embeddedUrl = VALID_CALL_URL_WITH_PARAM
|
||||
val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
|
||||
val url = "bad.scheme:/?url=$encodedUrl"
|
||||
assertThat(callIntentDataParser.parse(url)).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `element scheme 2 with url extra param 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&$EXTRA_PARAMS")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `element scheme 2 with url extra param 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&$EXTRA_PARAMS")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `element scheme 2 with url fragment gets url extracted`() {
|
||||
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")
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val VALID_CALL_URL_WITH_PARAM = "https://call.element.io/some-actual-call?with=parameters"
|
||||
const val EXTRA_PARAMS = "appPrompt=false&confineToRoom=true"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user