diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt index 81806eaa58..2314c3db1c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt @@ -1438,6 +1438,7 @@ object BackupRepository { fun enablePaidBackupTier() { Log.i(TAG, "Setting backup tier to PAID", true) + resetInitializedStateAndAuthCredentials() SignalStore.backup.backupTier = MessageBackupTier.PAID SignalStore.backup.lastCheckInMillis = System.currentTimeMillis() SignalStore.backup.lastCheckInSnoozeMillis = 0 diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupStateObserver.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupStateObserver.kt index b827e5b6ff..bcd3818b05 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupStateObserver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupStateObserver.kt @@ -63,9 +63,9 @@ class BackupStateObserver( private val backupTierChangedNotifier = MutableSharedFlow() /** - * Called when the value returned by [SignalStore.backup.backupTier] changes. + * Called when the backup state likely changed. */ - fun notifyBackupTierChanged(scope: CoroutineScope = staticScope) { + fun notifyBackupStateChanged(scope: CoroutineScope = staticScope) { Log.d(TAG, "Notifier got a change") scope.launch { backupTierChangedNotifier.emit(Unit) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupsSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupsSettingsViewModel.kt index a2ecf5159d..86b4363fc3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupsSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupsSettingsViewModel.kt @@ -59,6 +59,6 @@ class BackupsSettingsViewModel : ViewModel() { StorageSyncHelper.scheduleSyncForDataChange() } - BackupStateObserver.notifyBackupTierChanged(scope = viewModelScope) + BackupStateObserver.notifyBackupStateChanged(scope = viewModelScope) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupSubscriptionCheckJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupSubscriptionCheckJob.kt index 29c5dcbecf..fc49b9c1a3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupSubscriptionCheckJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupSubscriptionCheckJob.kt @@ -14,6 +14,7 @@ import org.signal.donations.InAppPaymentType import org.thoughtcrime.securesms.backup.DeletionState import org.thoughtcrime.securesms.backup.v2.BackupRepository import org.thoughtcrime.securesms.backup.v2.MessageBackupTier +import org.thoughtcrime.securesms.components.settings.app.backups.BackupStateObserver import org.thoughtcrime.securesms.components.settings.app.subscription.DonationSerializationHelper.toFiatValue import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository import org.thoughtcrime.securesms.components.settings.app.subscription.RecurringInAppPaymentRepository @@ -225,6 +226,7 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C if (backupExpiration != null) { Log.i(TAG, "Marking subscription failed or canceled.") SignalStore.backup.setDownloadNotifierToTriggerAtHalfwayPoint(backupExpiration) + BackupStateObserver.notifyBackupStateChanged() } else { Log.w(TAG, "Failed to mark, no entitlement was found on WhoAmIResponse") } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt index 374be8dde7..b62a5d6a28 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt @@ -106,7 +106,7 @@ class InAppPaymentRecurringContextJob private constructor( warning("A permanent failure occurred.") val inAppPayment = SignalDatabase.inAppPayments.getById(inAppPaymentId) - val isRedeemed = inAppPayment?.state == InAppPaymentTable.State.END && inAppPayment.data.redemption?.stage != InAppPaymentData.RedemptionState.Stage.REDEEMED + val isRedeemed = inAppPayment?.state == InAppPaymentTable.State.END && inAppPayment.data.redemption?.stage == InAppPaymentData.RedemptionState.Stage.REDEEMED if (isRedeemed) { info("Already redeemed. Exiting quietly.") return @@ -116,11 +116,11 @@ class InAppPaymentRecurringContextJob private constructor( inAppPayment.copy( notified = false, state = InAppPaymentTable.State.END, - data = inAppPayment.data.copy( + data = inAppPayment.data.newBuilder().error( error = InAppPaymentData.Error( type = InAppPaymentData.Error.Type.REDEMPTION ) - ) + ).build() ) ) } @@ -544,7 +544,9 @@ class InAppPaymentRecurringContextJob private constructor( 409 -> { warning("Already redeemed this token during new subscription. Failing.", applicationError) - if (inAppPayment.type == InAppPaymentType.RECURRING_BACKUP) { + // During keep-alive processing, we don't alert the user about redemption failures. + if (inAppPayment.type == InAppPaymentType.RECURRING_BACKUP && inAppPayment.data.redemption?.keepAlive != true) { + info("Displaying redemption failure for non-keep-alive processing.") SignalStore.backup.hasBackupAlreadyRedeemedError = true } @@ -633,12 +635,14 @@ class InAppPaymentRecurringContextJob private constructor( SignalDatabase.inAppPayments.update( inAppPayment = inAppPayment.copy( state = InAppPaymentTable.State.END, - data = inAppPayment.data.copy( - error = InAppPaymentData.Error( - type = InAppPaymentData.Error.Type.REDEMPTION, - data_ = "409" + data = inAppPayment.data.newBuilder() + .error( + InAppPaymentData.Error( + type = InAppPaymentData.Error.Type.REDEMPTION, + data_ = "409" + ) ) - ) + .build() ) ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRedemptionJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRedemptionJob.kt index 90b41031f8..d42777e815 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRedemptionJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRedemptionJob.kt @@ -130,11 +130,11 @@ class InAppPaymentRedemptionJob private constructor( inAppPayment.copy( notified = false, state = InAppPaymentTable.State.END, - data = inAppPayment.data.copy( - error = InAppPaymentData.Error( + data = inAppPayment.data.newBuilder().error( + InAppPaymentData.Error( type = InAppPaymentData.Error.Type.REDEMPTION ) - ) + ).build() ) ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt index ab0c52bb0a..987ad00b80 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt @@ -262,7 +262,7 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) { putLong(KEY_BACKUP_TIER, serializedValue) } - BackupStateObserver.notifyBackupTierChanged() + BackupStateObserver.notifyBackupStateChanged() } /** An internal setting that can override the backup tier for a user. */ diff --git a/app/src/test/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJobTest.kt b/app/src/test/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJobTest.kt index 4faafc19e9..d998e54509 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJobTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJobTest.kt @@ -452,6 +452,7 @@ class InAppPaymentRecurringContextJobTest { mockkObject(BackupRepository) every { BackupRepository.getBackupTier() } returns NetworkResult.Success(MessageBackupTier.PAID) + every { BackupRepository.resetInitializedStateAndAuthCredentials() } returns Unit val iap = insertInAppPayment( type = InAppPaymentType.RECURRING_BACKUP