diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bfd69aea3d..74ebfa89d4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -33,6 +33,7 @@ plugins { id("com.google.firebase.appdistribution") version "4.0.0" id("org.jetbrains.kotlinx.knit") version "0.4.0" id("kotlin-parcelize") + // TODO Move the plugin to the firebase module? id("com.google.gms.google-services") } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt index f548771717..a798f95bae 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt @@ -46,9 +46,9 @@ class LoggedInPresenter @Inject constructor( override fun present(): LoggedInState { LaunchedEffect(Unit) { // Ensure pusher is registered - // TODO Register with Firebase for now - val pushProvider = pushService.getAvailablePushProviders().firstOrNull() ?: return@LaunchedEffect - val distributor = pushProvider.getDistributorNames().firstOrNull() ?: return@LaunchedEffect + // TODO Manually select push provider for now + val pushProvider = pushService.getAvailablePushProviders().find { it.name == "UnifiedPush" } ?: return@LaunchedEffect + val distributor = pushProvider.getDistributors().first() pushService.registerWith(matrixClient, pushProvider, distributor) } diff --git a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt index 595f4850b2..71d303150b 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt @@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.permissions.api.PermissionsPresenter import io.element.android.libraries.permissions.noop.NoopPermissionsPresenter import io.element.android.libraries.push.api.PushService +import io.element.android.libraries.push.providers.api.Distributor import io.element.android.libraries.push.providers.api.PushProvider import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest @@ -60,7 +61,7 @@ class LoggedInPresenterTest { return emptyList() } - override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributorName: String) { + override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor) { } override suspend fun testPush() { diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/PushersService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/PushersService.kt index ef2291f8ce..71a642965f 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/PushersService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/pusher/PushersService.kt @@ -18,4 +18,5 @@ package io.element.android.libraries.matrix.api.pusher interface PushersService { suspend fun setHttpPusher(setHttpPusherData: SetHttpPusherData): Result + suspend fun unsetHttpPusher(): Result } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/pushers/RustPushersService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/pushers/RustPushersService.kt index 4eaafef12d..60ca4df311 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/pushers/RustPushersService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/pushers/RustPushersService.kt @@ -53,4 +53,9 @@ class RustPushersService( } } } + + override suspend fun unsetHttpPusher(): Result { + // TODO Missing client API. We need to set the pusher with Kind == null, but we do not have access to this field from the SDK. + return Result.success(Unit) + } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/pushers/FakePushersService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/pushers/FakePushersService.kt index 77087d132f..6ff7e4a20b 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/pushers/FakePushersService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/pushers/FakePushersService.kt @@ -21,4 +21,5 @@ import io.element.android.libraries.matrix.api.pusher.SetHttpPusherData class FakePushersService : PushersService { override suspend fun setHttpPusher(setHttpPusherData: SetHttpPusherData) = Result.success(Unit) + override suspend fun unsetHttpPusher(): Result = Result.success(Unit) } diff --git a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt index 7eeca6e0a3..83504e7a8a 100644 --- a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt +++ b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt @@ -17,6 +17,7 @@ package io.element.android.libraries.push.api import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.push.providers.api.Distributor import io.element.android.libraries.push.providers.api.PushProvider interface PushService { @@ -30,7 +31,7 @@ interface PushService { * * The method has effect only if the [PushProvider] is different than the current one. */ - suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributorName: String) + suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor) // TODO Move away suspend fun testPush() diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt index 1d9397d9a9..d1e266357b 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt @@ -20,14 +20,19 @@ import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.AppScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.push.api.PushService +import io.element.android.libraries.push.impl.clientsecret.PushClientSecret import io.element.android.libraries.push.impl.notifications.NotificationDrawerManager +import io.element.android.libraries.push.providers.api.Distributor import io.element.android.libraries.push.providers.api.PushProvider +import io.element.android.libraries.pushstore.api.UserPushStoreFactory import javax.inject.Inject @ContributesBinding(AppScope::class) class DefaultPushService @Inject constructor( private val notificationDrawerManager: NotificationDrawerManager, private val pushersManager: PushersManager, + private val pushClientSecret: PushClientSecret, + private val userPushStoreFactory: UserPushStoreFactory, private val pushProviders: Set<@JvmSuppressWildcards PushProvider>, ) : PushService { override fun notificationStyleChanged() { @@ -38,10 +43,22 @@ class DefaultPushService @Inject constructor( return pushProviders.sortedBy { it.index } } - override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributorName: String) { - // TODO Get current push provider, compare with provided one, then unregister and register if different, and store change + /** + * Get current push provider, compare with provided one, then unregister and register if different, and store change + */ + override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor) { + val userPushStore = userPushStoreFactory.create(matrixClient.sessionId.value) + val currentPushProviderName = userPushStore.getPushProviderName() + if (currentPushProviderName != pushProvider.name) { + // Unregister previous one if any + pushProviders.find { it.name == currentPushProviderName }?.unregister(matrixClient) + } - pushProvider.registerWith(matrixClient, distributorName) + val clientSecret = pushClientSecret.getSecretForUser(matrixClient.sessionId) + pushProvider.registerWith(matrixClient, distributor, clientSecret) + + // Store new value + userPushStore.setPushProviderName(pushProvider.name) } override suspend fun testPush() { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt index 532a904c82..eb3157adff 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt @@ -148,9 +148,8 @@ class PushersManager @Inject constructor( // currentSession.pushersService().removeEmailPusher(email) } - suspend fun unregisterPusher(pushKey: String) { - // val currentSession = activeSessionHolder.getSafeActiveSession() ?: return - // currentSession.pushersService().removeHttpPusher(pushKey, PushConfig.pusher_app_id) + override suspend fun unregisterPusher(matrixClient: MatrixClient, pushKey: String, gateway: String) { + matrixClient.pushersService().unsetHttpPusher() } companion object { diff --git a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/Distributor.kt b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/Distributor.kt new file mode 100644 index 0000000000..3d4d0add28 --- /dev/null +++ b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/Distributor.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.push.providers.api + +data class Distributor( + val value: String, + val name: String, +) diff --git a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/PushProvider.kt b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/PushProvider.kt index 854ae43522..92246851ec 100644 --- a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/PushProvider.kt +++ b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/PushProvider.kt @@ -26,8 +26,23 @@ interface PushProvider { * Allow to sort provider, from lower index to higher index */ val index: Int - fun getDistributorNames(): List - suspend fun registerWith(matrixClient: MatrixClient, distributorName: String) + + /** + * User friendly name. + */ + val name: String + + fun getDistributors(): List + + /** + * Register the pusher to the homeserver + */ + suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor, clientSecret: String) + + /** + * Unregister the pusher + */ + suspend fun unregister(matrixClient: MatrixClient) /** * Attempt to troubleshoot the push provider diff --git a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/PusherSubscriber.kt b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/PusherSubscriber.kt index 805244e0ed..0bf0f949f3 100644 --- a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/PusherSubscriber.kt +++ b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/push/providers/api/PusherSubscriber.kt @@ -20,4 +20,5 @@ import io.element.android.libraries.matrix.api.MatrixClient interface PusherSubscriber { suspend fun registerPusher(matrixClient: MatrixClient, pushKey: String, gateway: String) + suspend fun unregisterPusher(matrixClient: MatrixClient, pushKey: String, gateway: String) } diff --git a/libraries/pushproviders/firebase/build.gradle.kts b/libraries/pushproviders/firebase/build.gradle.kts index 65360d5465..eabc70305b 100644 --- a/libraries/pushproviders/firebase/build.gradle.kts +++ b/libraries/pushproviders/firebase/build.gradle.kts @@ -40,7 +40,7 @@ dependencies { implementation(projects.libraries.pushproviders.api) implementation(platform(libs.google.firebase.bom)) - implementation("com.google.firebase:firebase-messaging-ktx") + api("com.google.firebase:firebase-messaging-ktx") testImplementation(libs.test.junit) testImplementation(libs.test.truth) diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebaseConfig.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebaseConfig.kt index 27463825d6..bf35a1b18a 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebaseConfig.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebaseConfig.kt @@ -23,5 +23,6 @@ object FirebaseConfig { */ const val pusher_http_url: String = "https://matrix.org/_matrix/push/v1/notify" - const val internalName = "NOTIFICATION_METHOD_FIREBASE" + const val index = 0 + const val name = "Firebase" } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebaseNewTokenHandler.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebaseNewTokenHandler.kt index 01b93f3d95..2c987c75e1 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebaseNewTokenHandler.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebaseNewTokenHandler.kt @@ -43,7 +43,7 @@ class FirebaseNewTokenHandler @Inject constructor( // Register the pusher for all the sessions sessionStore.getAllSessions().toUserList().forEach { userId -> val userDataStore = userPushStoreFactory.create(userId) - if (userDataStore.getNotificationMethod() == FirebaseConfig.internalName) { + if (userDataStore.getPushProviderName() == FirebaseConfig.name) { matrixAuthenticationService.restoreSession(SessionId(userId)).getOrNull()?.use { client -> pusherSubscriber.registerPusher(client, firebaseToken, FirebaseConfig.pusher_http_url) } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebasePushProvider.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebasePushProvider.kt index 86042ae4e3..f30e031bab 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebasePushProvider.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/push/providers/firebase/FirebasePushProvider.kt @@ -18,6 +18,7 @@ package io.element.android.libraries.push.providers.firebase import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.push.providers.api.Distributor import io.element.android.libraries.push.providers.api.PushProvider import io.element.android.libraries.push.providers.api.PusherSubscriber import timber.log.Timber @@ -30,20 +31,27 @@ class FirebasePushProvider @Inject constructor( private val firebaseTroubleshooter: FirebaseTroubleshooter, private val pusherSubscriber: PusherSubscriber, ) : PushProvider { - override val index = 0 + override val index = FirebaseConfig.index + override val name = FirebaseConfig.name - override fun getDistributorNames(): List { - // Must return an non-empty list for now - return listOf("unused") + override fun getDistributors(): List { + return listOf(Distributor("Firebase", "Firebase")) } - override suspend fun registerWith(matrixClient: MatrixClient, distributorName: String) { + override suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor, clientSecret: String) { val pushKey = firebaseStore.getFcmToken() ?: return Unit.also { Timber.tag(loggerTag.value).w("Unable to register pusher, Firebase token is not known.") } pusherSubscriber.registerPusher(matrixClient, pushKey, FirebaseConfig.pusher_http_url) } + override suspend fun unregister(matrixClient: MatrixClient) { + val pushKey = firebaseStore.getFcmToken() ?: return Unit.also { + Timber.tag(loggerTag.value).w("Unable to unregister pusher, Firebase token is not known.") + } + pusherSubscriber.unregisterPusher(matrixClient, pushKey, FirebaseConfig.pusher_http_url) + } + override suspend fun troubleshoot(): Result { return firebaseTroubleshooter.troubleshoot() } diff --git a/libraries/pushproviders/unifiedpush/build.gradle.kts b/libraries/pushproviders/unifiedpush/build.gradle.kts index 6817d0aad6..7dcd773c25 100644 --- a/libraries/pushproviders/unifiedpush/build.gradle.kts +++ b/libraries/pushproviders/unifiedpush/build.gradle.kts @@ -30,14 +30,21 @@ anvil { dependencies { implementation(libs.dagger) + implementation(projects.libraries.androidutils) implementation(projects.libraries.core) implementation(projects.libraries.matrix.api) + implementation(projects.libraries.pushstore.api) implementation(projects.libraries.pushproviders.api) implementation(projects.libraries.architecture) implementation(projects.libraries.core) implementation(projects.services.toolbox.api) + implementation(projects.libraries.network) + implementation(platform(libs.network.okhttp.bom)) + implementation("com.squareup.okhttp3:okhttp") + implementation(libs.network.retrofit) + implementation(libs.serialization.json) // UnifiedPush library diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/PushDataUnifiedPush.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/PushDataUnifiedPush.kt index 6d5ecb1db3..618a3c989f 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/PushDataUnifiedPush.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/PushDataUnifiedPush.kt @@ -55,13 +55,13 @@ data class PushDataUnifiedPushCounts( @SerialName("unread") val unread: Int? = null ) -fun PushDataUnifiedPush.toPushData(): PushData? { +fun PushDataUnifiedPush.toPushData(clientSecret: String): PushData? { val safeEventId = notification?.eventId?.asEventId() ?: return null val safeRoomId = notification.roomId?.asRoomId() ?: return null return PushData( eventId = safeEventId, roomId = safeRoomId, unread = notification.counts?.unread, - clientSecret = null // TODO EAx check how client secret will be sent through UnifiedPush + clientSecret = clientSecret ) } diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/RegisterUnifiedPushUseCase.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/RegisterUnifiedPushUseCase.kt index a80d9ba865..813f8e97ca 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/RegisterUnifiedPushUseCase.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/RegisterUnifiedPushUseCase.kt @@ -18,45 +18,56 @@ package io.element.android.libraries.push.providers.unifiedpush import android.content.Context import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.push.providers.api.Distributor +import io.element.android.libraries.push.providers.api.PusherSubscriber import org.unifiedpush.android.connector.UnifiedPush import javax.inject.Inject class RegisterUnifiedPushUseCase @Inject constructor( @ApplicationContext private val context: Context, + private val pusherSubscriber: PusherSubscriber, + private val unifiedPushStore: UnifiedPushStore, ) { sealed interface RegisterUnifiedPushResult { object Success : RegisterUnifiedPushResult object NeedToAskUserForDistributor : RegisterUnifiedPushResult + object Error : RegisterUnifiedPushResult } - fun execute(distributor: String = ""): RegisterUnifiedPushResult { - if (distributor.isNotEmpty()) { - saveAndRegisterApp(distributor) + suspend fun execute(matrixClient: MatrixClient, distributor: Distributor, clientSecret: String): RegisterUnifiedPushResult { + val distributorValue = distributor.value + if (distributorValue.isNotEmpty()) { + saveAndRegisterApp(distributorValue, clientSecret) + val endpoint = unifiedPushStore.getEndpoint() ?: return RegisterUnifiedPushResult.Error + val gateway = unifiedPushStore.getPushGateway() ?: return RegisterUnifiedPushResult.Error + pusherSubscriber.registerPusher(matrixClient, endpoint, gateway) return RegisterUnifiedPushResult.Success } + // TODO Below should never happen? if (UnifiedPush.getDistributor(context).isNotEmpty()) { - registerApp() + registerApp(clientSecret) return RegisterUnifiedPushResult.Success } val distributors = UnifiedPush.getDistributors(context) return if (distributors.size == 1) { - saveAndRegisterApp(distributors.first()) + saveAndRegisterApp(distributors.first(), clientSecret) RegisterUnifiedPushResult.Success } else { RegisterUnifiedPushResult.NeedToAskUserForDistributor } } - private fun saveAndRegisterApp(distributor: String) { + private fun saveAndRegisterApp(distributor: String, clientSecret: String) { UnifiedPush.saveDistributor(context, distributor) - registerApp() + registerApp(clientSecret) } - private fun registerApp() { - UnifiedPush.registerApp(context) + private fun registerApp(clientSecret: String) { + UnifiedPush.registerApp(context = context, instance = clientSecret) } } diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushConfig.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushConfig.kt index 73c31f430c..21b4ca9a76 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushConfig.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushConfig.kt @@ -23,5 +23,6 @@ object UnifiedPushConfig { */ const val default_push_gateway_http_url: String = "https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify" - const val internalName = "NOTIFICATION_METHOD_UNIFIEDPUSH" + const val index = 1 + const val name = "UnifiedPush" } diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushHelper.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushHelper.kt index dce17015b7..6c17c16c67 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushHelper.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushHelper.kt @@ -17,11 +17,13 @@ package io.element.android.libraries.push.providers.unifiedpush import android.content.Context +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.network.RetrofitFactory +import io.element.android.libraries.push.providers.unifiedpush.network.UnifiedPushApi import io.element.android.services.toolbox.api.strings.StringProvider -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.unifiedpush.android.connector.UnifiedPush +import kotlinx.coroutines.withContext import timber.log.Timber import java.net.URL import javax.inject.Inject @@ -30,132 +32,34 @@ class UnifiedPushHelper @Inject constructor( @ApplicationContext private val context: Context, private val unifiedPushStore: UnifiedPushStore, private val stringProvider: StringProvider, + private val retrofitFactory: RetrofitFactory, + private val coroutineDispatchers: CoroutineDispatchers, ) { - - /* TODO EAx - @MainThread - fun showSelectDistributorDialog( - context: Context, - onDistributorSelected: (String) -> Unit, - ) { - val internalDistributorName = stringProvider.getString( - if (fcmHelper.isFirebaseAvailable()) { - R.string.push_distributor_firebase_android - } else { - R.string.push_distributor_background_sync_android - } - ) - - val distributors = UnifiedPush.getDistributors(context) - val distributorsName = distributors.map { - if (it == context.packageName) { - internalDistributorName - } else { - context.getApplicationLabel(it) - } - } - - MaterialAlertDialogBuilder(context) - .setTitle(stringProvider.getString(R.string.push_choose_distributor_dialog_title_android)) - .setItems(distributorsName.toTypedArray()) { _, which -> - val distributor = distributors[which] - onDistributorSelected(distributor) - } - .setOnCancelListener { - // we do not want to change the distributor on behalf of the user - if (UnifiedPush.getDistributor(context).isEmpty()) { - // By default, use internal solution (fcm/background sync) - onDistributorSelected(context.packageName) - } - } - .setCancelable(true) - .show() - } - - */ - - @Serializable - internal data class DiscoveryResponse( - @SerialName("unifiedpush") val unifiedpush: DiscoveryUnifiedPush = DiscoveryUnifiedPush() - ) - - @Serializable - internal data class DiscoveryUnifiedPush( - @SerialName("gateway") val gateway: String = "" - ) - - suspend fun storeCustomOrDefaultGateway( - endpoint: String, - onDoneRunnable: Runnable? = null - ) { - // if we use the embedded distributor, - // register app_id type upfcm on sygnal - // the pushkey if FCM key - /* - if (UnifiedPush.getDistributor(context) == context.packageName) { - unifiedPushStore.storePushGateway(PushConfig.pusher_http_url) - onDoneRunnable?.run() - return - } - - */ - /* TODO EAx UnifiedPush - // else, unifiedpush, and pushkey is an endpoint - val gateway = PushConfig.default_push_gateway_http_url + suspend fun storeCustomOrDefaultGateway(endpoint: String) { + val gateway = UnifiedPushConfig.default_push_gateway_http_url val parsed = URL(endpoint) val custom = "${parsed.protocol}://${parsed.host}/_matrix/push/v1/notify" Timber.i("Testing $custom") try { - val response = matrix.rawService().getUrl(custom, CacheStrategy.NoCache) - tryOrNull { Json.decodeFromString(response) } - ?.let { discoveryResponse -> - if (discoveryResponse.unifiedpush.gateway == "matrix") { - Timber.d("Using custom gateway") - unifiedPushStore.storePushGateway(custom) - onDoneRunnable?.run() - return + withContext(coroutineDispatchers.io) { + val api = retrofitFactory.create("${parsed.protocol}://${parsed.host}") + .create(UnifiedPushApi::class.java) + tryOrNull { api.discover() } + ?.let { discoveryResponse -> + if (discoveryResponse.unifiedpush.gateway == "matrix") { + Timber.d("Using custom gateway") + unifiedPushStore.storePushGateway(custom) + } } - } + } + return } catch (e: Throwable) { Timber.d(e, "Cannot try custom gateway") } unifiedPushStore.storePushGateway(gateway) - onDoneRunnable?.run() - - */ } - fun getExternalDistributors(): List { - return UnifiedPush.getDistributors(context) - .filterNot { it == context.packageName } - } - - fun getCurrentDistributorName(): String { - TODO() - /* - return when { - isEmbeddedDistributor() -> stringProvider.getString(R.string.push_distributor_firebase_android) - isBackgroundSync() -> stringProvider.getString(R.string.push_distributor_background_sync_android) - else -> context.getApplicationLabel(UnifiedPush.getDistributor(context)) - } - - */ - } - - fun isEmbeddedDistributor(): Boolean { - TODO() - //return isInternalDistributor() && fcmHelper.isFirebaseAvailable() - } - - fun isBackgroundSync(): Boolean { - TODO() - //return isInternalDistributor() && !fcmHelper.isFirebaseAvailable() - } - - private fun isInternalDistributor(): Boolean { - return UnifiedPush.getDistributor(context).isEmpty() || - UnifiedPush.getDistributor(context) == context.packageName - } + private fun isEmbeddedDistributor() = false fun getPrivacyFriendlyUpEndpoint(): String? { val endpoint = getEndpointOrToken() diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushNewGatewayHandler.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushNewGatewayHandler.kt new file mode 100644 index 0000000000..b02fab04ea --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushNewGatewayHandler.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.push.providers.unifiedpush + +import io.element.android.libraries.core.log.logger.LoggerTag +import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.push.providers.api.PusherSubscriber +import io.element.android.libraries.pushstore.api.UserPushStoreFactory +import io.element.android.libraries.sessionstorage.api.SessionStore +import io.element.android.libraries.sessionstorage.api.toUserList +import timber.log.Timber +import javax.inject.Inject + +private val loggerTag = LoggerTag("UnifiedPushNewGatewayHandler") + +/** + * Handle new endpoint received from UnifiedPush. Will update all the sessions which are using UnifiedPush as a push provider. + */ +class UnifiedPushNewGatewayHandler @Inject constructor( + private val pusherSubscriber: PusherSubscriber, + private val sessionStore: SessionStore, + private val userPushStoreFactory: UserPushStoreFactory, + private val matrixAuthenticationService: MatrixAuthenticationService, +) { + suspend fun handle(endpoint: String, pushGateway: String) { + // Register the pusher for all the sessions which are using UnifiedPush. + sessionStore.getAllSessions().toUserList().forEach { userId -> + val userDataStore = userPushStoreFactory.create(userId) + if (userDataStore.getPushProviderName() == UnifiedPushConfig.name) { + matrixAuthenticationService.restoreSession(SessionId(userId)).getOrNull()?.use { client -> + pusherSubscriber.registerPusher(client, endpoint, pushGateway) + } + } else { + Timber.tag(loggerTag.value).d("This session is not using UnifiedPush pusher") + } + } + } +} diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushParser.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushParser.kt index 881862d473..6169e1f8eb 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushParser.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushParser.kt @@ -25,7 +25,7 @@ import javax.inject.Inject class UnifiedPushParser @Inject constructor() { private val json by lazy { Json { ignoreUnknownKeys = true } } - fun parse(message: ByteArray): PushData? { - return tryOrNull { json.decodeFromString(String(message)) }?.toPushData() + fun parse(message: ByteArray, clientSecret: String): PushData? { + return tryOrNull { json.decodeFromString(String(message)) }?.toPushData(clientSecret) } } diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushProvider.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushProvider.kt index e6d402b8d2..c12c54c0a3 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushProvider.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushProvider.kt @@ -16,19 +16,41 @@ package io.element.android.libraries.push.providers.unifiedpush +import android.content.Context +import io.element.android.libraries.androidutils.system.getApplicationLabel +import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.push.providers.api.Distributor import io.element.android.libraries.push.providers.api.PushProvider +import org.unifiedpush.android.connector.UnifiedPush import javax.inject.Inject -class UnifiedPushProvider @Inject constructor() : PushProvider { - override val index = 1 +class UnifiedPushProvider @Inject constructor( + @ApplicationContext private val context: Context, + private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase, + private val unRegisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase, +) : PushProvider { + override val index = UnifiedPushConfig.index + override val name = UnifiedPushConfig.name - override fun getDistributorNames(): List { - TODO("Not yet implemented") + override fun getDistributors(): List { + val distributors = UnifiedPush.getDistributors(context) + return distributors.mapNotNull { + if (it == context.packageName) { + // Exclude self + null + } else { + Distributor(it, context.getApplicationLabel(it)) + } + } } - override suspend fun registerWith(matrixClient: MatrixClient, distributorName: String) { - TODO("Not yet implemented") + override suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor, clientSecret: String) { + registerUnifiedPushUseCase.execute(matrixClient, distributor, clientSecret) + } + + override suspend fun unregister(matrixClient: MatrixClient) { + unRegisterUnifiedPushUseCase.execute() } override suspend fun troubleshoot(): Result { diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnregisterUnifiedPushUseCase.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnregisterUnifiedPushUseCase.kt index b7cd592951..750eb95f83 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnregisterUnifiedPushUseCase.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnregisterUnifiedPushUseCase.kt @@ -16,21 +16,26 @@ package io.element.android.libraries.push.providers.unifiedpush -/* +import android.content.Context +import io.element.android.libraries.di.ApplicationContext +import org.unifiedpush.android.connector.UnifiedPush +import timber.log.Timber +import javax.inject.Inject + class UnregisterUnifiedPushUseCase @Inject constructor( @ApplicationContext private val context: Context, - private val pushDataStore: PushDataStore, + //private val pushDataStore: PushDataStore, private val unifiedPushStore: UnifiedPushStore, private val unifiedPushHelper: UnifiedPushHelper, ) { - suspend fun execute(pushersManager: PushersManager?) { - val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME - pushDataStore.setFdroidSyncBackgroundMode(mode) + suspend fun execute(/*pushersManager: PushersManager?*/) { + //val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME + //pushDataStore.setFdroidSyncBackgroundMode(mode) try { unifiedPushHelper.getEndpointOrToken()?.let { Timber.d("Removing $it") - pushersManager?.unregisterPusher(it) + // TODO pushersManager?.unregisterPusher(it) } } catch (e: Exception) { Timber.d(e, "Probably unregistering a non existing pusher") @@ -40,4 +45,3 @@ class UnregisterUnifiedPushUseCase @Inject constructor( UnifiedPush.unregisterApp(context) } } - */ diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/VectorUnifiedPushMessagingReceiver.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/VectorUnifiedPushMessagingReceiver.kt index d745df6e87..0736badbc2 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/VectorUnifiedPushMessagingReceiver.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/VectorUnifiedPushMessagingReceiver.kt @@ -21,6 +21,7 @@ import android.content.Intent import io.element.android.libraries.architecture.bindings import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.push.providers.api.PushHandler +import io.element.android.libraries.push.providers.api.PusherSubscriber import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch @@ -32,22 +33,24 @@ private val loggerTag = LoggerTag("VectorUnifiedPushMessagingReceiver") class VectorUnifiedPushMessagingReceiver : MessagingReceiver() { @Inject lateinit var pushParser: UnifiedPushParser - // @Inject lateinit var pushDataStore: PushDataStore + + // @Inject lateinit var pushDataStore: PushDataStore @Inject lateinit var pushHandler: PushHandler @Inject lateinit var guardServiceStarter: GuardServiceStarter -// @Inject lateinit var unifiedPushStore: UnifiedPushStore -// @Inject lateinit var unifiedPushHelper: UnifiedPushHelper + @Inject lateinit var unifiedPushStore: UnifiedPushStore + @Inject lateinit var unifiedPushHelper: UnifiedPushHelper + @Inject lateinit var pusherSubscriber: PusherSubscriber + @Inject lateinit var newGatewayHandler: UnifiedPushNewGatewayHandler private val coroutineScope = CoroutineScope(SupervisorJob()) override fun onReceive(context: Context, intent: Intent) { - super.onReceive(context, intent) - // Inject context.applicationContext.bindings().inject(this) + super.onReceive(context, intent) } /** - * Called when message is received. + * Called when message is received. The message contains the full POST body of the push message. * * @param context the Android context * @param message the message @@ -56,7 +59,7 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() { override fun onMessage(context: Context, message: ByteArray, instance: String) { Timber.tag(loggerTag.value).d("New message") coroutineScope.launch { - val pushData = pushParser.parse(message) + val pushData = pushParser.parse(message, instance) if (pushData == null) { Timber.tag(loggerTag.value).w("Invalid data received from UnifiedPush") } else { @@ -65,36 +68,36 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() { } } + /** + * Called when a new endpoint is to be used for sending push messages. + * You should send the endpoint to your application server and sync for missing notifications. + * TODO use [instance] for multi-account + */ override fun onNewEndpoint(context: Context, endpoint: String, instance: String) { - TODO() - /* Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint") - if (pushDataStore.areNotificationEnabledForDevice() /* TODO EAx && activeSessionHolder.hasActiveSession() */) { - // If the endpoint has changed - // or the gateway has changed - if (unifiedPushHelper.getEndpointOrToken() != endpoint) { - unifiedPushStore.storeUpEndpoint(endpoint) - coroutineScope.launch { - unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) { - unifiedPushHelper.getPushGateway()?.let { - coroutineScope.launch { - pushersManager.onNewUnifiedPushEndpoint(endpoint, it) - } - } - } + // If the endpoint has changed + // or the gateway has changed + if (unifiedPushHelper.getEndpointOrToken() != endpoint) { + unifiedPushStore.storeUpEndpoint(endpoint) + coroutineScope.launch { + unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) + unifiedPushHelper.getPushGateway()?.let { pushGateway -> + newGatewayHandler.handle(endpoint, pushGateway) } - } else { - Timber.tag(loggerTag.value).i("onNewEndpoint: skipped") } + } else { + Timber.tag(loggerTag.value).i("onNewEndpoint: skipped") } - val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED - pushDataStore.setFdroidSyncBackgroundMode(mode) + //val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED + //pushDataStore.setFdroidSyncBackgroundMode(mode) guardServiceStarter.stop() - */ } + /** + * Called when the registration is not possible, eg. no network. + */ override fun onRegistrationFailed(context: Context, instance: String) { - TODO() + Timber.tag(loggerTag.value).e("onRegistrationFailed for $instance") /* Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show() val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME @@ -103,10 +106,13 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() { */ } + /** + * Called when this application is unregistered from receiving push messages. + */ override fun onUnregistered(context: Context, instance: String) { + Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered") TODO() /* - Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered") val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME pushDataStore.setFdroidSyncBackgroundMode(mode) guardServiceStarter.start() diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/network/DiscoveryResponse.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/network/DiscoveryResponse.kt new file mode 100644 index 0000000000..b961da1285 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/network/DiscoveryResponse.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.push.providers.unifiedpush.network + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class DiscoveryResponse( + @SerialName("unifiedpush") val unifiedpush: DiscoveryUnifiedPush = DiscoveryUnifiedPush() +) diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/network/DiscoveryUnifiedPush.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/network/DiscoveryUnifiedPush.kt new file mode 100644 index 0000000000..b4c7345fd7 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/network/DiscoveryUnifiedPush.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.push.providers.unifiedpush.network + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class DiscoveryUnifiedPush( + @SerialName("gateway") val gateway: String = "" +) diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/network/UnifiedPushApi.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/network/UnifiedPushApi.kt new file mode 100644 index 0000000000..e384b8353b --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/push/providers/unifiedpush/network/UnifiedPushApi.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.push.providers.unifiedpush.network + +import retrofit2.http.GET + +interface UnifiedPushApi { + @GET("_matrix/push/v1/notify") + suspend fun discover(): DiscoveryResponse +} diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushParserTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushParserTest.kt index 6b5c0db62f..b18be39e07 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushParserTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/push/providers/unifiedpush/UnifiedPushParserTest.kt @@ -20,56 +20,65 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.push.providers.api.PushData +import org.junit.Assert.assertThrows import org.junit.Test class UnifiedPushParserTest { + private val aClientSecret = "a-client-secret" private val validData = PushData( eventId = AN_EVENT_ID, roomId = A_ROOM_ID, unread = 1, - // TODO handle client secret here. - clientSecret = null + clientSecret = aClientSecret ) @Test fun `test edge cases UnifiedPush`() { val pushParser = UnifiedPushParser() // Empty string - assertThat(pushParser.parse("".toByteArray())).isNull() + assertThat(pushParser.parse("".toByteArray(), aClientSecret)).isNull() // Empty Json - assertThat(pushParser.parse("{}".toByteArray())).isNull() + assertThat(pushParser.parse("{}".toByteArray(), aClientSecret)).isNull() // Bad Json - assertThat(pushParser.parse("ABC".toByteArray())).isNull() + assertThat(pushParser.parse("ABC".toByteArray(), aClientSecret)).isNull() } @Test fun `test UnifiedPush format`() { val pushParser = UnifiedPushParser() - assertThat(pushParser.parse(UNIFIED_PUSH_DATA.toByteArray())).isEqualTo(validData) + assertThat(pushParser.parse(UNIFIED_PUSH_DATA.toByteArray(), aClientSecret)).isEqualTo(validData) } @Test fun `test empty roomId`() { val pushParser = UnifiedPushParser() - assertThat(pushParser.parse(UNIFIED_PUSH_DATA.replace(A_ROOM_ID.value, "").toByteArray())).isNull() + assertThrows(IllegalStateException::class.java) { + pushParser.parse(UNIFIED_PUSH_DATA.replace(A_ROOM_ID.value, "").toByteArray(), aClientSecret) + } } @Test fun `test invalid roomId`() { val pushParser = UnifiedPushParser() - assertThat(pushParser.parse(UNIFIED_PUSH_DATA.mutate(A_ROOM_ID.value, "aRoomId:domain"))).isNull() + assertThrows(IllegalStateException::class.java) { + pushParser.parse(UNIFIED_PUSH_DATA.mutate(A_ROOM_ID.value, "aRoomId:domain"), aClientSecret) + } } @Test fun `test empty eventId`() { val pushParser = UnifiedPushParser() - assertThat(pushParser.parse(UNIFIED_PUSH_DATA.mutate(AN_EVENT_ID.value, ""))).isNull() + assertThrows(IllegalStateException::class.java) { + pushParser.parse(UNIFIED_PUSH_DATA.mutate(AN_EVENT_ID.value, ""), aClientSecret) + } } @Test fun `test invalid eventId`() { val pushParser = UnifiedPushParser() - assertThat(pushParser.parse(UNIFIED_PUSH_DATA.mutate(AN_EVENT_ID.value, "anEventId"))).isNull() + assertThrows(IllegalStateException::class.java) { + pushParser.parse(UNIFIED_PUSH_DATA.mutate(AN_EVENT_ID.value, "anEventId"), aClientSecret) + } } companion object { diff --git a/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt b/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt index 35ec23f80d..6817199e13 100644 --- a/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt +++ b/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt @@ -20,12 +20,9 @@ package io.element.android.libraries.pushstore.api * Store data related to push about a user. */ interface UserPushStore { - /** - * [NOTIFICATION_METHOD_FIREBASE] or [NOTIFICATION_METHOD_UNIFIEDPUSH]. - */ - suspend fun getNotificationMethod(): String? + suspend fun getPushProviderName(): String? - suspend fun setNotificationMethod(value: String) + suspend fun setPushProviderName(value: String) suspend fun getCurrentRegisteredPushKey(): String? diff --git a/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt b/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt index 8b37056768..0e4e668eda 100644 --- a/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt +++ b/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt @@ -33,16 +33,16 @@ class UserPushStoreDataStore( userId: String, ) : UserPushStore { private val Context.dataStore: DataStore by preferencesDataStore(name = "push_store_$userId") - private val notificationMethod = stringPreferencesKey("notificationMethod") + private val pushProviderName = stringPreferencesKey("pushProviderName") private val currentPushKey = stringPreferencesKey("currentPushKey") - override suspend fun getNotificationMethod(): String? { - return context.dataStore.data.first()[notificationMethod] + override suspend fun getPushProviderName(): String? { + return context.dataStore.data.first()[pushProviderName] } - override suspend fun setNotificationMethod(value: String) { + override suspend fun setPushProviderName(value: String) { context.dataStore.edit { - it[notificationMethod] = value + it[pushProviderName] = value } } diff --git a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt index 368747961d..1427269755 100644 --- a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt +++ b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt @@ -79,7 +79,7 @@ fun DependencyHandlerScope.allLibrariesImpl() { // Comment to not include firebase in the project implementation(project(":libraries:pushproviders:firebase")) // Comment to not include unified push in the project - // implementation(project(":libraries:pushproviders:unifiedpush")) + implementation(project(":libraries:pushproviders:unifiedpush")) implementation(project(":libraries:pushstore:impl")) implementation(project(":libraries:architecture")) implementation(project(":libraries:dateformatter:impl"))