Skip to content

Commit ba626fc

Browse files
authored
Use embedded version of Element Call (#4470)
* Use embedded version of Element Call: for in-app room calls, the app will use an embedded version of Element Call shipped with the app instead of using an external service. * Remove `ElementCallBaseUrlProvider` so we don't use the Element well known file to get the base URL anymore * Remove `ElementCallConfig.DEFAULT_BASE_URL` since it's not used anymore * Restore the usage of the custom EC base URL in developer settings as the actual base URL, it present * Add a way to customise the embedded EC analytic credentials * Update CI to use the EC analytic credentials as secrets * Improve the custom URL placeholder to include the `/room` suffix
1 parent 03f4122 commit ba626fc

File tree

32 files changed

+177
-288
lines changed

32 files changed

+177
-288
lines changed

.github/workflows/build.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ jobs:
4646
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
4747
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
4848
ELEMENT_ANDROID_SENTRY_DSN: ${{ secrets.ELEMENT_ANDROID_SENTRY_DSN }}
49+
ELEMENT_CALL_SENTRY_DSN: ${{ secrets.ELEMENT_CALL_SENTRY_DSN }}
50+
ELEMENT_CALL_POSTHOG_API_HOST: ${{ secrets.ELEMENT_CALL_POSTHOG_API_HOST }}
51+
ELEMENT_CALL_POSTHOG_API_KEY: ${{ secrets.ELEMENT_CALL_POSTHOG_API_KEY }}
52+
ELEMENT_CALL_RAGESHAKE_URL: ${{ secrets.ELEMENT_CALL_RAGESHAKE_URL }}
4953
run: ./gradlew :app:assembleGplayDebug app:assembleFDroidDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
5054
- name: Upload debug APKs
5155
if: ${{ matrix.variant == 'debug' }}

.github/workflows/build_enterprise.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ jobs:
5454
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
5555
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
5656
ELEMENT_ANDROID_SENTRY_DSN: ${{ secrets.ELEMENT_ANDROID_SENTRY_DSN }}
57+
ELEMENT_CALL_SENTRY_DSN: ${{ secrets.ELEMENT_CALL_SENTRY_DSN }}
58+
ELEMENT_CALL_POSTHOG_API_HOST: ${{ secrets.ELEMENT_CALL_POSTHOG_API_HOST }}
59+
ELEMENT_CALL_POSTHOG_API_KEY: ${{ secrets.ELEMENT_CALL_POSTHOG_API_KEY }}
60+
ELEMENT_CALL_RAGESHAKE_URL: ${{ secrets.ELEMENT_CALL_RAGESHAKE_URL }}
5761
run: ./gradlew :app:assembleGplayDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
5862
- name: Upload debug Enterprise APKs
5963
if: ${{ matrix.variant == 'debug' }}

.github/workflows/nightly.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ jobs:
3030
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
3131
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
3232
ELEMENT_ANDROID_SENTRY_DSN: ${{ secrets.ELEMENT_ANDROID_SENTRY_DSN }}
33+
ELEMENT_CALL_SENTRY_DSN: ${{ secrets.ELEMENT_CALL_SENTRY_DSN }}
34+
ELEMENT_CALL_POSTHOG_API_HOST: ${{ secrets.ELEMENT_CALL_POSTHOG_API_HOST }}
35+
ELEMENT_CALL_POSTHOG_API_KEY: ${{ secrets.ELEMENT_CALL_POSTHOG_API_KEY }}
36+
ELEMENT_CALL_RAGESHAKE_URL: ${{ secrets.ELEMENT_CALL_RAGESHAKE_URL }}
3337
ELEMENT_ANDROID_NIGHTLY_KEYID: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYID }}
3438
ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD }}
3539
ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD }}

.github/workflows/nightly_enterprise.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ jobs:
3636
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
3737
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
3838
ELEMENT_ANDROID_SENTRY_DSN: ${{ secrets.ELEMENT_ANDROID_SENTRY_DSN }}
39+
ELEMENT_CALL_SENTRY_DSN: ${{ secrets.ELEMENT_CALL_SENTRY_DSN }}
40+
ELEMENT_CALL_POSTHOG_API_HOST: ${{ secrets.ELEMENT_CALL_POSTHOG_API_HOST }}
41+
ELEMENT_CALL_POSTHOG_API_KEY: ${{ secrets.ELEMENT_CALL_POSTHOG_API_KEY }}
42+
ELEMENT_CALL_RAGESHAKE_URL: ${{ secrets.ELEMENT_CALL_RAGESHAKE_URL }}
3943
ELEMENT_ANDROID_NIGHTLY_KEYID: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYID }}
4044
ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD }}
4145
ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD }}

.github/workflows/release.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ jobs:
3232
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
3333
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
3434
ELEMENT_ANDROID_SENTRY_DSN: ${{ secrets.ELEMENT_ANDROID_SENTRY_DSN }}
35+
ELEMENT_CALL_SENTRY_DSN: ${{ secrets.ELEMENT_CALL_SENTRY_DSN }}
36+
ELEMENT_CALL_POSTHOG_API_HOST: ${{ secrets.ELEMENT_CALL_POSTHOG_API_HOST }}
37+
ELEMENT_CALL_POSTHOG_API_KEY: ${{ secrets.ELEMENT_CALL_POSTHOG_API_KEY }}
38+
ELEMENT_CALL_RAGESHAKE_URL: ${{ secrets.ELEMENT_CALL_RAGESHAKE_URL }}
3539
run: ./gradlew bundleGplayRelease $CI_GRADLE_ARG_PROPERTIES
3640
- name: Upload bundle as artifact
3741
uses: actions/upload-artifact@v4

anvilcodegen/src/main/kotlin/io/element/android/anvilcodegen/ContributesNodeProcessorProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import com.google.devtools.ksp.processing.SymbolProcessorProvider
1313

1414
class ContributesNodeProcessorProvider : SymbolProcessorProvider {
1515
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
16-
val enableLogging = environment.options["enableLogging"]?.toBoolean() ?: false
16+
val enableLogging = environment.options["enableLogging"]?.toBoolean() == true
1717
return ContributesNodeProcessor(
1818
logger = environment.logger,
1919
codeGenerator = environment.codeGenerator,

appconfig/src/main/kotlin/io/element/android/appconfig/ElementCallConfig.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@
88
package io.element.android.appconfig
99

1010
object ElementCallConfig {
11-
/**
12-
* The default base URL for the Element Call service.
13-
*/
14-
const val DEFAULT_BASE_URL = "https://call.element.io"
15-
1611
/**
1712
* The default duration of a ringing call in seconds before it's automatically dismissed.
1813
*/

features/call/impl/build.gradle.kts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import extension.readLocalProperty
12
import extension.setupAnvil
23

34
/*
@@ -23,6 +24,49 @@ android {
2324
testOptions {
2425
unitTests.isIncludeAndroidResources = true
2526
}
27+
28+
defaultConfig {
29+
buildConfigField(
30+
type = "String",
31+
name = "SENTRY_DSN",
32+
value = (System.getenv("ELEMENT_CALL_SENTRY_DSN")
33+
?: readLocalProperty("features.call.sentry.dsn")
34+
?: ""
35+
).let { "\"$it\"" }
36+
)
37+
buildConfigField(
38+
type = "String",
39+
name = "POSTHOG_USER_ID",
40+
value = (System.getenv("ELEMENT_CALL_POSTHOG_USER_ID")
41+
?: readLocalProperty("features.call.posthog.userid")
42+
?: ""
43+
).let { "\"$it\"" }
44+
)
45+
buildConfigField(
46+
type = "String",
47+
name = "POSTHOG_API_HOST",
48+
value = (System.getenv("ELEMENT_CALL_POSTHOG_API_HOST")
49+
?: readLocalProperty("features.call.posthog.api.host")
50+
?: ""
51+
).let { "\"$it\"" }
52+
)
53+
buildConfigField(
54+
type = "String",
55+
name = "POSTHOG_API_KEY",
56+
value = (System.getenv("ELEMENT_CALL_POSTHOG_API_KEY")
57+
?: readLocalProperty("features.call.posthog.api.key")
58+
?: ""
59+
).let { "\"$it\"" }
60+
)
61+
buildConfigField(
62+
type = "String",
63+
name = "RAGESHAKE_URL",
64+
value = (System.getenv("ELEMENT_CALL_RAGESHAKE_URL")
65+
?: readLocalProperty("features.call.regeshake.url")
66+
?: ""
67+
).let { "\"$it\"" }
68+
)
69+
}
2670
}
2771

2872
setupAnvil()
@@ -47,6 +91,7 @@ dependencies {
4791
implementation(libs.coil.compose)
4892
implementation(libs.network.retrofit)
4993
implementation(libs.serialization.json)
94+
implementation(libs.element.call.embedded)
5095
api(projects.features.call.api)
5196

5297
testImplementation(libs.coroutines.test)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2025 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
5+
* Please see LICENSE files in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.call.impl.utils
9+
10+
import com.squareup.anvil.annotations.ContributesBinding
11+
import io.element.android.features.call.impl.BuildConfig
12+
import io.element.android.libraries.di.AppScope
13+
import io.element.android.libraries.matrix.api.widget.CallAnalyticCredentialsProvider
14+
import javax.inject.Inject
15+
16+
@ContributesBinding(AppScope::class)
17+
class DefaultCallAnalyticCredentialsProvider @Inject constructor() : CallAnalyticCredentialsProvider {
18+
override val posthogUserId: String? = BuildConfig.POSTHOG_USER_ID.takeIf { it.isNotBlank() }
19+
override val posthogApiHost: String? = BuildConfig.POSTHOG_API_HOST.takeIf { it.isNotBlank() }
20+
override val posthogApiKey: String? = BuildConfig.POSTHOG_API_KEY.takeIf { it.isNotBlank() }
21+
override val rageshakeSubmitUrl: String? = BuildConfig.RAGESHAKE_URL.takeIf { it.isNotBlank() }
22+
override val sentryDsn: String? = BuildConfig.SENTRY_DSN.takeIf { it.isNotBlank() }
23+
}

features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,22 @@
88
package io.element.android.features.call.impl.utils
99

1010
import com.squareup.anvil.annotations.ContributesBinding
11-
import io.element.android.appconfig.ElementCallConfig
1211
import io.element.android.libraries.di.AppScope
1312
import io.element.android.libraries.matrix.api.MatrixClientProvider
14-
import io.element.android.libraries.matrix.api.call.ElementCallBaseUrlProvider
1513
import io.element.android.libraries.matrix.api.core.RoomId
1614
import io.element.android.libraries.matrix.api.core.SessionId
1715
import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider
1816
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
1917
import kotlinx.coroutines.flow.firstOrNull
2018
import javax.inject.Inject
2119

20+
private const val EMBEDDED_CALL_WIDGET_BASE_URL = "https://appassets.androidplatform.net/element-call/index.html"
21+
2222
@ContributesBinding(AppScope::class)
2323
class DefaultCallWidgetProvider @Inject constructor(
2424
private val matrixClientsProvider: MatrixClientProvider,
2525
private val appPreferencesStore: AppPreferencesStore,
2626
private val callWidgetSettingsProvider: CallWidgetSettingsProvider,
27-
private val elementCallBaseUrlProvider: ElementCallBaseUrlProvider,
2827
) : CallWidgetProvider {
2928
override suspend fun getWidget(
3029
sessionId: SessionId,
@@ -35,9 +34,10 @@ class DefaultCallWidgetProvider @Inject constructor(
3534
): Result<CallWidgetProvider.GetWidgetResult> = runCatching {
3635
val matrixClient = matrixClientsProvider.getOrRestore(sessionId).getOrThrow()
3736
val room = matrixClient.getRoom(roomId) ?: error("Room not found")
38-
val baseUrl = appPreferencesStore.getCustomElementCallBaseUrlFlow().firstOrNull()
39-
?: elementCallBaseUrlProvider.provides(matrixClient)
40-
?: ElementCallConfig.DEFAULT_BASE_URL
37+
38+
val customBaseUrl = appPreferencesStore.getCustomElementCallBaseUrlFlow().firstOrNull()
39+
val baseUrl = customBaseUrl ?: EMBEDDED_CALL_WIDGET_BASE_URL
40+
4141
val isEncrypted = room.info().isEncrypted ?: room.getUpdatedIsEncrypted().getOrThrow()
4242
val widgetSettings = callWidgetSettingsProvider.provide(baseUrl, encrypted = isEncrypted)
4343
val callUrl = room.generateWidgetWebViewUrl(
@@ -46,9 +46,10 @@ class DefaultCallWidgetProvider @Inject constructor(
4646
languageTag = languageTag,
4747
theme = theme,
4848
).getOrThrow()
49+
4950
CallWidgetProvider.GetWidgetResult(
5051
driver = room.getWidgetDriver(widgetSettings).getOrThrow(),
51-
url = callUrl
52+
url = callUrl,
5253
)
5354
}
5455
}

0 commit comments

Comments
 (0)