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 553bee1e17..2096a04656 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 @@ -10,6 +10,7 @@ package io.element.android.libraries.push.api import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.push.api.history.PushHistoryItem import io.element.android.libraries.pushproviders.api.Distributor import io.element.android.libraries.pushproviders.api.PushProvider @@ -73,4 +74,9 @@ interface PushService { * Reset the battery optimization state. */ suspend fun resetBatteryOptimizationState() + + /** + * Notify the user that the service is un-registered. + */ + suspend fun onServiceUnregistered(userId: UserId) } 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 1ea30a7766..5c77438293 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 @@ -14,12 +14,14 @@ import dev.zacsweers.metro.SingleIn import dev.zacsweers.metro.binding import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.push.api.GetCurrentPushProvider import io.element.android.libraries.push.api.PushService import io.element.android.libraries.push.api.history.PushHistoryItem import io.element.android.libraries.push.impl.push.MutableBatteryOptimizationStore import io.element.android.libraries.push.impl.store.PushDataStore import io.element.android.libraries.push.impl.test.TestPush +import io.element.android.libraries.push.impl.unregistration.ServiceUnregisteredHandler import io.element.android.libraries.pushproviders.api.Distributor import io.element.android.libraries.pushproviders.api.PushProvider import io.element.android.libraries.pushstore.api.UserPushStoreFactory @@ -40,6 +42,7 @@ class DefaultPushService( private val pushClientSecretStore: PushClientSecretStore, private val pushDataStore: PushDataStore, private val mutableBatteryOptimizationStore: MutableBatteryOptimizationStore, + private val serviceUnregisteredHandler: ServiceUnregisteredHandler, ) : PushService, SessionListener { init { observeSessions() @@ -141,4 +144,8 @@ class DefaultPushService( override suspend fun resetBatteryOptimizationState() { mutableBatteryOptimizationStore.reset() } + + override suspend fun onServiceUnregistered(userId: UserId) { + serviceUnregisteredHandler.handle(userId) + } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDisplayer.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDisplayer.kt index 3e9c917cfd..d46bffce73 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDisplayer.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDisplayer.kt @@ -24,6 +24,7 @@ interface NotificationDisplayer { fun cancelNotification(tag: String?, id: Int) fun displayDiagnosticNotification(notification: Notification): Boolean fun dismissDiagnosticNotification() + fun displayUnregistrationNotification(notification: Notification): Boolean } @ContributesBinding(AppScope::class) @@ -60,6 +61,14 @@ class DefaultNotificationDisplayer( ) } + override fun displayUnregistrationNotification(notification: Notification): Boolean { + return showNotification( + tag = TAG_DIAGNOSTIC, + id = NOTIFICATION_ID_UNREGISTRATION, + notification = notification, + ) + } + companion object { private const val TAG_DIAGNOSTIC = "DIAGNOSTIC" @@ -67,5 +76,6 @@ class DefaultNotificationDisplayer( * IDs for notifications * ========================================================================================== */ private const val NOTIFICATION_ID_DIAGNOSTIC = 888 + private const val NOTIFICATION_ID_UNREGISTRATION = 889 } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt index 70d01cbf24..98a1228297 100755 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt @@ -91,6 +91,10 @@ interface NotificationCreator { @ColorInt color: Int, ): Notification + fun createUnregistrationNotification( + notificationAccountParams: NotificationAccountParams, + ): Notification + companion object { /** * Creates a tag for a message notification given its [roomId] and optional [threadId]. @@ -352,6 +356,28 @@ class DefaultNotificationCreator( .build() } + override fun createUnregistrationNotification( + notificationAccountParams: NotificationAccountParams, + ): Notification { + val userId = notificationAccountParams.user.userId + val text = if (notificationAccountParams.showSessionId) { + // TODO i18n + "$userId will not receive notifications anymore." + } else { + // TODO i18n + "You will not receive notifications anymore." + } + return NotificationCompat.Builder(context, notificationChannels.getChannelIdForTest()) + .setContentTitle(stringProvider.getString(CommonStrings.dialog_title_warning)) + .setContentText(text) + .configureWith(notificationAccountParams) + .setPriority(NotificationCompat.PRIORITY_MAX) + .setCategory(NotificationCompat.CATEGORY_ERROR) + .setAutoCancel(true) + .setContentIntent(pendingIntentFactory.createOpenSessionPendingIntent(userId)) + .build() + } + private suspend fun MessagingStyle.addMessagesFromEvents( events: List, imageLoader: ImageLoader, diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/unregistration/ServiceUnregisteredHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/unregistration/ServiceUnregisteredHandler.kt new file mode 100644 index 0000000000..cb42ceaf5d --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/unregistration/ServiceUnregisteredHandler.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.unregistration + +import androidx.compose.ui.graphics.toArgb +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.appconfig.NotificationConfig +import io.element.android.features.enterprise.api.EnterpriseService +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.push.impl.notifications.NotificationDisplayer +import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams +import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator +import io.element.android.libraries.sessionstorage.api.SessionStore +import kotlinx.coroutines.flow.first + +interface ServiceUnregisteredHandler { + suspend fun handle(userId: UserId) +} + +@ContributesBinding(AppScope::class) +class DefaultServiceUnregisteredHandler( + private val enterpriseService: EnterpriseService, + private val notificationCreator: NotificationCreator, + private val notificationDisplayer: NotificationDisplayer, + private val sessionStore: SessionStore, +) : ServiceUnregisteredHandler { + override suspend fun handle(userId: UserId) { + val color = enterpriseService.brandColorsFlow(userId).first()?.toArgb() + ?: NotificationConfig.NOTIFICATION_ACCENT_COLOR + val hasMultipleAccounts = sessionStore.numberOfSessions() > 1 + val notification = notificationCreator.createUnregistrationNotification( + NotificationAccountParams( + user = MatrixUser(userId), + color = color, + showSessionId = hasMultipleAccounts, + ) + ) + notificationDisplayer.displayDiagnosticNotification(notification) + } +} diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/DefaultPushServiceTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/DefaultPushServiceTest.kt index d862e1cf39..7ddbc93fb1 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/DefaultPushServiceTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/DefaultPushServiceTest.kt @@ -25,6 +25,8 @@ import io.element.android.libraries.push.impl.store.InMemoryPushDataStore import io.element.android.libraries.push.impl.store.PushDataStore import io.element.android.libraries.push.impl.test.FakeTestPush import io.element.android.libraries.push.impl.test.TestPush +import io.element.android.libraries.push.impl.unregistration.FakeServiceUnregisteredHandler +import io.element.android.libraries.push.impl.unregistration.ServiceUnregisteredHandler import io.element.android.libraries.push.test.FakeGetCurrentPushProvider import io.element.android.libraries.pushproviders.api.Config import io.element.android.libraries.pushproviders.api.Distributor @@ -346,6 +348,7 @@ class DefaultPushServiceTest { pushClientSecretStore: PushClientSecretStore = InMemoryPushClientSecretStore(), pushDataStore: PushDataStore = InMemoryPushDataStore(), mutableBatteryOptimizationStore: MutableBatteryOptimizationStore = FakeMutableBatteryOptimizationStore(), + serviceUnregisteredHandler: ServiceUnregisteredHandler = FakeServiceUnregisteredHandler(), ): DefaultPushService { return DefaultPushService( testPush = testPush, @@ -356,6 +359,7 @@ class DefaultPushServiceTest { pushClientSecretStore = pushClientSecretStore, pushDataStore = pushDataStore, mutableBatteryOptimizationStore = mutableBatteryOptimizationStore, + serviceUnregisteredHandler = serviceUnregisteredHandler, ) } } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt index 76302d772e..d5e4ad9695 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt @@ -41,6 +41,8 @@ class FakeNotificationCreator( > = lambdaRecorder { _, _, _, _, _ -> A_NOTIFICATION }, var createDiagnosticNotificationResult: LambdaOneParamRecorder = lambdaRecorder { _ -> A_NOTIFICATION }, + val createUnregistrationNotificationResult: LambdaOneParamRecorder = + lambdaRecorder { _ -> A_NOTIFICATION }, ) : NotificationCreator { override suspend fun createMessagesListNotification( notificationAccountParams: NotificationAccountParams, @@ -93,4 +95,8 @@ class FakeNotificationCreator( ): Notification { return createDiagnosticNotificationResult(color) } + + override fun createUnregistrationNotification(notificationAccountParams: NotificationAccountParams): Notification { + return createUnregistrationNotificationResult(notificationAccountParams) + } } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt index 9ab32cc13e..fd4af70a72 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt @@ -24,6 +24,7 @@ class FakeNotificationDisplayer( var cancelNotificationResult: LambdaTwoParamsRecorder = lambdaRecorder { _, _ -> }, var displayDiagnosticNotificationResult: LambdaOneParamRecorder = lambdaRecorder { _ -> true }, var dismissDiagnosticNotificationResult: LambdaNoParamRecorder = lambdaRecorder { -> }, + var displayUnregistrationNotificationResult: LambdaOneParamRecorder = lambdaRecorder { _ -> true }, ) : NotificationDisplayer { override fun showNotification(tag: String?, id: Int, notification: Notification): Boolean { return showNotificationResult(tag, id, notification) @@ -41,6 +42,10 @@ class FakeNotificationDisplayer( return dismissDiagnosticNotificationResult() } + override fun displayUnregistrationNotification(notification: Notification): Boolean { + return displayUnregistrationNotificationResult(notification) + } + fun verifySummaryCancelled(times: Int = 1) { cancelNotificationResult.assertions().isCalledExactly(times).withSequence( listOf(value(null), value(NotificationIdProvider.getSummaryNotificationId(A_SESSION_ID))) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/unregistration/FakeServiceUnregisteredHandler.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/unregistration/FakeServiceUnregisteredHandler.kt new file mode 100644 index 0000000000..0ae4190973 --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/unregistration/FakeServiceUnregisteredHandler.kt @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.unregistration + +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.tests.testutils.lambda.lambdaError + +class FakeServiceUnregisteredHandler( + private val handleResult: (UserId) -> Unit = { lambdaError() }, +) : ServiceUnregisteredHandler { + override suspend fun handle(userId: UserId) { + handleResult(userId) + } +} diff --git a/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt index d0198fba91..ee99ef1a20 100644 --- a/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt +++ b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt @@ -10,6 +10,7 @@ package io.element.android.libraries.push.test import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.push.api.PushService import io.element.android.libraries.push.api.history.PushHistoryItem import io.element.android.libraries.pushproviders.api.Distributor @@ -30,6 +31,7 @@ class FakePushService( private val setIgnoreRegistrationErrorLambda: (SessionId, Boolean) -> Unit = { _, _ -> lambdaError() }, private val resetPushHistoryResult: () -> Unit = { lambdaError() }, private val resetBatteryOptimizationStateResult: () -> Unit = { lambdaError() }, + private val onServiceUnregisteredResult: (UserId) -> Unit = { lambdaError() }, ) : PushService { override suspend fun getCurrentPushProvider(sessionId: SessionId): PushProvider? { return registeredPushProvider ?: currentPushProvider(sessionId) @@ -98,4 +100,8 @@ class FakePushService( override suspend fun resetBatteryOptimizationState() { resetBatteryOptimizationStateResult() } + + override suspend fun onServiceUnregistered(userId: UserId) { + onServiceUnregisteredResult(userId) + } } diff --git a/libraries/pushproviders/unifiedpush/build.gradle.kts b/libraries/pushproviders/unifiedpush/build.gradle.kts index 6369399f28..1b24bc4b1f 100644 --- a/libraries/pushproviders/unifiedpush/build.gradle.kts +++ b/libraries/pushproviders/unifiedpush/build.gradle.kts @@ -24,6 +24,7 @@ dependencies { implementation(projects.libraries.androidutils) implementation(projects.libraries.core) implementation(projects.libraries.matrix.api) + implementation(projects.libraries.push.api) implementation(projects.libraries.uiStrings) api(projects.libraries.troubleshoot.api) diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushRemovedGatewayHandler.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushRemovedGatewayHandler.kt index 7f494c3f52..fa75fd101e 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushRemovedGatewayHandler.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushRemovedGatewayHandler.kt @@ -12,6 +12,7 @@ import dev.zacsweers.metro.ContributesBinding import io.element.android.libraries.core.extensions.flatMap import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.matrix.api.MatrixClientProvider +import io.element.android.libraries.push.api.PushService import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret import timber.log.Timber @@ -20,7 +21,7 @@ private val loggerTag = LoggerTag("UnifiedPushRemovedGatewayHandler", LoggerTag. /** * Handle new endpoint received from UnifiedPush. Will update the session matching the client secret. */ -interface UnifiedPushRemovedGatewayHandler { +fun interface UnifiedPushRemovedGatewayHandler { suspend fun handle(clientSecret: String): Result } @@ -29,9 +30,10 @@ class DefaultUnifiedPushRemovedGatewayHandler( private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase, private val pushClientSecret: PushClientSecret, private val matrixClientProvider: MatrixClientProvider, + private val pushService: PushService, ) : UnifiedPushRemovedGatewayHandler { override suspend fun handle(clientSecret: String): Result { - // Unregister the pusher for the session with this client secret, if is it using UnifiedPush. + // Unregister the pusher for the session with this client secret. val userId = pushClientSecret.getUserIdFromSecret(clientSecret) ?: return Result.failure( IllegalStateException("Unable to retrieve session") ).also { @@ -39,15 +41,42 @@ class DefaultUnifiedPushRemovedGatewayHandler( } return matrixClientProvider .getOrRestore(userId) + .onFailure { + Timber.tag(loggerTag.value).w(it, "Fails to restore client") + } .flatMap { client -> unregisterUnifiedPushUseCase.unregister( matrixClient = client, clientSecret = clientSecret, unregisterUnifiedPush = false, ) + .onFailure { + Timber.tag(loggerTag.value).w(it, "Unable to unregister pusher") + } + .flatMap { + val pushProvider = pushService.getCurrentPushProvider(userId) + val distributor = pushProvider?.getCurrentDistributor(userId) + // Attempt to register again + if (pushProvider != null && distributor != null) { + pushService.registerWith( + client, + pushProvider, + distributor, + ) + .onFailure { + Timber.tag(loggerTag.value).w(it, "Unable to register with current data") + } + } else { + Result.failure(IllegalStateException("Unable to register again")) + } + } + .onFailure { + // Let the user know + pushService.onServiceUnregistered(userId) + } } .onFailure { - Timber.tag(loggerTag.value).w(it, "Unable to unregister pusher") + Timber.tag(loggerTag.value).w(it, "Issue during pusher unregistration / re registration") } } } diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt index a7484585fe..05f6969fc5 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt @@ -106,12 +106,14 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() { */ override fun onRegistrationFailed(context: Context, reason: FailedReason, instance: String) { Timber.tag(loggerTag.value).e("onRegistrationFailed for $instance, reason: $reason") - /* - Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show() - val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME - pushDataStore.setFdroidSyncBackgroundMode(mode) - guardServiceStarter.start() - */ + coroutineScope.launch { + endpointRegistrationHandler.registrationDone( + RegistrationResult( + clientSecret = instance, + result = Result.failure(Exception("Registration failed. Reason: $reason")), + ) + ) + } } /** diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/FakeUnregisterUnifiedPushUseCase.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/FakeUnregisterUnifiedPushUseCase.kt index cda28554db..182bb5f823 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/FakeUnregisterUnifiedPushUseCase.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/FakeUnregisterUnifiedPushUseCase.kt @@ -12,14 +12,21 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.tests.testutils.lambda.lambdaError class FakeUnregisterUnifiedPushUseCase( - private val unregisterLambda: (MatrixClient, String) -> Result = { _, _ -> lambdaError() }, - private val cleanupLambda: (String) -> Unit = { lambdaError() }, + private val unregisterLambda: (MatrixClient, String, Boolean) -> Result = { _, _, _ -> lambdaError() }, + private val cleanupLambda: (String, Boolean) -> Unit = { _, _ -> lambdaError() }, ) : UnregisterUnifiedPushUseCase { - override suspend fun unregister(matrixClient: MatrixClient, clientSecret: String): Result { - return unregisterLambda(matrixClient, clientSecret) + override suspend fun unregister( + matrixClient: MatrixClient, + clientSecret: String, + unregisterUnifiedPush: Boolean, + ): Result { + return unregisterLambda(matrixClient, clientSecret, unregisterUnifiedPush) } - override fun cleanup(clientSecret: String) { - cleanupLambda(clientSecret) + override fun cleanup( + clientSecret: String, + unregisterUnifiedPush: Boolean, + ) { + cleanupLambda(clientSecret, unregisterUnifiedPush) } } diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProviderTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProviderTest.kt index 10ed18118b..e22c1c3bf4 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProviderTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProviderTest.kt @@ -118,7 +118,7 @@ class UnifiedPushProviderTest { fun `unregister ok`() = runTest { val matrixClient = FakeMatrixClient() val getSecretForUserResultLambda = lambdaRecorder { A_SECRET } - val unregisterLambda = lambdaRecorder> { _, _ -> Result.success(Unit) } + val unregisterLambda = lambdaRecorder> { _, _, _ -> Result.success(Unit) } val unifiedPushProvider = createUnifiedPushProvider( pushClientSecret = FakePushClientSecret( getSecretForUserResult = getSecretForUserResultLambda, @@ -134,14 +134,14 @@ class UnifiedPushProviderTest { .with(value(A_SESSION_ID)) unregisterLambda.assertions() .isCalledOnce() - .with(value(matrixClient), value(A_SECRET)) + .with(value(matrixClient), value(A_SECRET), value(true)) } @Test fun `unregister ko`() = runTest { val matrixClient = FakeMatrixClient() val getSecretForUserResultLambda = lambdaRecorder { A_SECRET } - val unregisterLambda = lambdaRecorder> { _, _ -> Result.failure(AN_EXCEPTION) } + val unregisterLambda = lambdaRecorder> { _, _, _ -> Result.failure(AN_EXCEPTION) } val unifiedPushProvider = createUnifiedPushProvider( pushClientSecret = FakePushClientSecret( getSecretForUserResult = getSecretForUserResultLambda, @@ -157,7 +157,7 @@ class UnifiedPushProviderTest { .with(value(A_SESSION_ID)) unregisterLambda.assertions() .isCalledOnce() - .with(value(matrixClient), value(A_SECRET)) + .with(value(matrixClient), value(A_SECRET), value(true)) } @Test @@ -230,7 +230,7 @@ class UnifiedPushProviderTest { @Test fun `onSessionDeleted should do the cleanup`() = runTest { - val cleanupLambda = lambdaRecorder { } + val cleanupLambda = lambdaRecorder { _, _ -> } val unifiedPushProvider = createUnifiedPushProvider( pushClientSecret = FakePushClientSecret( getSecretForUserResult = { A_SECRET } @@ -240,7 +240,7 @@ class UnifiedPushProviderTest { ), ) unifiedPushProvider.onSessionDeleted(A_SESSION_ID) - cleanupLambda.assertions().isCalledOnce().with(value(A_SECRET)) + cleanupLambda.assertions().isCalledOnce().with(value(A_SECRET), value(true)) } private fun createUnifiedPushProvider( diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt index 6cf82c1fc0..f10f6430f0 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.pushproviders.api.PushData import io.element.android.libraries.pushproviders.api.PushHandler import io.element.android.libraries.pushproviders.unifiedpush.registration.EndpointRegistrationHandler import io.element.android.libraries.pushproviders.unifiedpush.registration.RegistrationResult +import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -51,10 +52,17 @@ class VectorUnifiedPushMessagingReceiverTest { } @Test - fun `onUnregistered does nothing`() = runTest { + fun `onUnregistered invokes the removedGatewayHandler`() = runTest { val context = InstrumentationRegistry.getInstrumentation().context - val vectorUnifiedPushMessagingReceiver = createVectorUnifiedPushMessagingReceiver() + val handleResult = lambdaRecorder> { + Result.success(Unit) + } + val vectorUnifiedPushMessagingReceiver = createVectorUnifiedPushMessagingReceiver( + removedGatewayHandler = UnifiedPushRemovedGatewayHandler { handleResult(it) }, + ) vectorUnifiedPushMessagingReceiver.onUnregistered(context, A_SECRET) + advanceUntilIdle() + handleResult.assertions().isCalledOnce().with(value(A_SECRET)) } @Test @@ -199,6 +207,7 @@ class VectorUnifiedPushMessagingReceiverTest { unifiedPushGatewayUrlResolver: UnifiedPushGatewayUrlResolver = FakeUnifiedPushGatewayUrlResolver(), unifiedPushNewGatewayHandler: UnifiedPushNewGatewayHandler = FakeUnifiedPushNewGatewayHandler(), endpointRegistrationHandler: EndpointRegistrationHandler = EndpointRegistrationHandler(), + removedGatewayHandler: UnifiedPushRemovedGatewayHandler = UnifiedPushRemovedGatewayHandler { lambdaError() }, ): VectorUnifiedPushMessagingReceiver { return VectorUnifiedPushMessagingReceiver().apply { this.pushParser = unifiedPushParser @@ -208,6 +217,7 @@ class VectorUnifiedPushMessagingReceiverTest { this.unifiedPushGatewayResolver = unifiedPushGatewayResolver this.unifiedPushGatewayUrlResolver = unifiedPushGatewayUrlResolver this.newGatewayHandler = unifiedPushNewGatewayHandler + this.removedGatewayHandler = removedGatewayHandler this.endpointRegistrationHandler = endpointRegistrationHandler this.coroutineScope = this@createVectorUnifiedPushMessagingReceiver }