Ensure that disabling (resp. enabling) notification unregisters (resp. registers) the pusher

This commit is contained in:
Benoit Marty 2025-11-13 17:46:49 +01:00
parent c7d4689473
commit d3339872ff
11 changed files with 441 additions and 355 deletions

View file

@ -36,7 +36,7 @@ import io.element.android.libraries.matrix.api.sync.SyncService
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.push.api.PushService
import io.element.android.libraries.pushproviders.api.RegistrationFailure
import io.element.android.libraries.push.api.PusherRegistrationFailure
import io.element.android.services.analytics.api.AnalyticsService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
@ -71,7 +71,17 @@ class LoggedInPresenter(
when (sessionVerifiedStatus) {
SessionVerifiedStatus.Unknown -> Unit
SessionVerifiedStatus.Verified -> {
ensurePusherIsRegistered(pusherRegistrationState)
Timber.tag(pusherTag.value).d("Ensure pusher is registered")
pushService.ensurePusherIsRegistered(matrixClient).fold(
onSuccess = {
Timber.tag(pusherTag.value).d("Pusher registered")
pusherRegistrationState.value = AsyncData.Success(Unit)
},
onFailure = {
Timber.tag(pusherTag.value).e(it, "Failed to register pusher")
pusherRegistrationState.value = AsyncData.Failure(it)
},
)
}
SessionVerifiedStatus.NotVerified -> {
pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.AccountNotVerified())
@ -133,59 +143,6 @@ class LoggedInPresenter(
currentSlidingSyncVersion == SlidingSyncVersion.Proxy
}
private suspend fun ensurePusherIsRegistered(pusherRegistrationState: MutableState<AsyncData<Unit>>) {
Timber.tag(pusherTag.value).d("Ensure pusher is registered")
val currentPushProvider = pushService.getCurrentPushProvider(matrixClient.sessionId)
val result = if (currentPushProvider == null) {
Timber.tag(pusherTag.value).d("Register with the first available push provider with at least one distributor")
val pushProvider = pushService.getAvailablePushProviders()
.firstOrNull { it.getDistributors().isNotEmpty() }
// Else fallback to the first available push provider (the list should never be empty)
?: pushService.getAvailablePushProviders().firstOrNull()
?: return Unit
.also { Timber.tag(pusherTag.value).w("No push providers available") }
.also { pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.NoProvidersAvailable()) }
val distributor = pushProvider.getDistributors().firstOrNull()
?: return Unit
.also { Timber.tag(pusherTag.value).w("No distributors available") }
.also {
// In this case, consider the push provider is chosen.
pushService.selectPushProvider(matrixClient.sessionId, pushProvider)
}
.also { pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.NoDistributorsAvailable()) }
pushService.registerWith(matrixClient, pushProvider, distributor)
} else {
val currentPushDistributor = currentPushProvider.getCurrentDistributor(matrixClient.sessionId)
if (currentPushDistributor == null) {
Timber.tag(pusherTag.value).d("Register with the first available distributor")
val distributor = currentPushProvider.getDistributors().firstOrNull()
?: return Unit
.also { Timber.tag(pusherTag.value).w("No distributors available") }
.also { pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.NoDistributorsAvailable()) }
pushService.registerWith(matrixClient, currentPushProvider, distributor)
} else {
Timber.tag(pusherTag.value).d("Re-register with the current distributor")
pushService.registerWith(matrixClient, currentPushProvider, currentPushDistributor)
}
}
result.fold(
onSuccess = {
Timber.tag(pusherTag.value).d("Pusher registered")
pusherRegistrationState.value = AsyncData.Success(Unit)
},
onFailure = {
Timber.tag(pusherTag.value).e(it, "Failed to register pusher")
if (it is RegistrationFailure) {
pusherRegistrationState.value = AsyncData.Failure(
PusherRegistrationFailure.RegistrationFailure(it.clientException, it.isRegisteringAgain)
)
} else {
pusherRegistrationState.value = AsyncData.Failure(it)
}
}
)
}
private fun reportCryptoStatusToAnalytics(verificationState: SessionVerifiedStatus, recoveryState: RecoveryState) {
// Update first the user property, to store the current status for that posthog user
val userVerificationState = verificationState.toAnalyticsUserPropertyValue()

View file

@ -10,6 +10,7 @@ package io.element.android.appnav.loggedin
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.push.api.PusherRegistrationFailure
open class LoggedInStateProvider : PreviewParameterProvider<LoggedInState> {
override val values: Sequence<LoggedInState>

View file

@ -25,6 +25,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
import io.element.android.libraries.matrix.api.exception.isNetworkError
import io.element.android.libraries.push.api.PusherRegistrationFailure
import io.element.android.libraries.ui.strings.CommonStrings
@Composable

View file

@ -1,26 +0,0 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector 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.appnav.loggedin
import io.element.android.libraries.matrix.api.exception.ClientException
sealed class PusherRegistrationFailure : Exception() {
class AccountNotVerified : PusherRegistrationFailure()
class NoProvidersAvailable : PusherRegistrationFailure()
class NoDistributorsAvailable : PusherRegistrationFailure()
/**
* @param clientException the failure that occurred.
* @param isRegisteringAgain true if the server should already have a the same pusher registered.
*/
class RegistrationFailure(
val clientException: ClientException,
val isRegisteringAgain: Boolean,
) : PusherRegistrationFailure()
}