mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 12:38:33 +00:00
Prevent "Free" tier from being upgraded in the background.
This commit is contained in:
@@ -169,7 +169,7 @@ private fun BackupsSettingsContent(
|
|||||||
OtherWaysToBackUpHeading()
|
OtherWaysToBackUpHeading()
|
||||||
}
|
}
|
||||||
|
|
||||||
is BackupState.ActiveFree, is BackupState.ActivePaid -> {
|
is BackupState.ActiveFree, is BackupState.ActivePaid, is BackupState.Canceled -> {
|
||||||
ActiveBackupsRow(
|
ActiveBackupsRow(
|
||||||
backupState = backupsSettingsState.backupState,
|
backupState = backupsSettingsState.backupState,
|
||||||
onBackupsRowClick = onBackupsRowClick,
|
onBackupsRowClick = onBackupsRowClick,
|
||||||
@@ -210,15 +210,6 @@ private fun BackupsSettingsContent(
|
|||||||
OtherWaysToBackUpHeading()
|
OtherWaysToBackUpHeading()
|
||||||
}
|
}
|
||||||
|
|
||||||
is BackupState.Canceled -> {
|
|
||||||
ActiveBackupsRow(
|
|
||||||
backupState = backupsSettingsState.backupState,
|
|
||||||
lastBackupAt = backupsSettingsState.lastBackupAt
|
|
||||||
)
|
|
||||||
|
|
||||||
OtherWaysToBackUpHeading()
|
|
||||||
}
|
|
||||||
|
|
||||||
is BackupState.SubscriptionMismatchMissingGooglePlay -> {
|
is BackupState.SubscriptionMismatchMissingGooglePlay -> {
|
||||||
ActiveBackupsRow(
|
ActiveBackupsRow(
|
||||||
backupState = backupsSettingsState.backupState,
|
backupState = backupsSettingsState.backupState,
|
||||||
@@ -421,13 +412,25 @@ private fun ActiveBackupsRow(
|
|||||||
|
|
||||||
when (val type = backupState.messageBackupsType) {
|
when (val type = backupState.messageBackupsType) {
|
||||||
is MessageBackupsType.Paid -> {
|
is MessageBackupsType.Paid -> {
|
||||||
Text(
|
val body = if (backupState is BackupState.Canceled) {
|
||||||
text = stringResource(
|
stringResource(R.string.BackupsSettingsFragment__subscription_canceled)
|
||||||
|
} else {
|
||||||
|
stringResource(
|
||||||
R.string.BackupsSettingsFragment_s_month_renews_s,
|
R.string.BackupsSettingsFragment_s_month_renews_s,
|
||||||
FiatMoneyUtil.format(LocalContext.current.resources, type.pricePerMonth),
|
FiatMoneyUtil.format(LocalContext.current.resources, type.pricePerMonth),
|
||||||
DateUtils.formatDateWithYear(Locale.getDefault(), backupState.renewalTime.inWholeMilliseconds)
|
DateUtils.formatDateWithYear(Locale.getDefault(), backupState.renewalTime.inWholeMilliseconds)
|
||||||
),
|
)
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
}
|
||||||
|
|
||||||
|
val color = if (backupState is BackupState.Canceled) {
|
||||||
|
MaterialTheme.colorScheme.error
|
||||||
|
} else {
|
||||||
|
MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = body,
|
||||||
|
color = color,
|
||||||
style = MaterialTheme.typography.bodyMedium
|
style = MaterialTheme.typography.bodyMedium
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,43 +71,43 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C
|
|||||||
|
|
||||||
override suspend fun doRun(): Result {
|
override suspend fun doRun(): Result {
|
||||||
if (!SignalStore.account.isRegistered) {
|
if (!SignalStore.account.isRegistered) {
|
||||||
Log.i(TAG, "User is not registered. Clearing mismatch value and exiting.")
|
Log.i(TAG, "User is not registered. Clearing mismatch value and exiting.", true)
|
||||||
SignalStore.backup.subscriptionStateMismatchDetected = false
|
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!RemoteConfig.messageBackups) {
|
if (!RemoteConfig.messageBackups) {
|
||||||
Log.i(TAG, "Message backups feature is not available. Clearing mismatch value and exiting.")
|
Log.i(TAG, "Message backups feature is not available. Clearing mismatch value and exiting.", true)
|
||||||
SignalStore.backup.subscriptionStateMismatchDetected = false
|
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AppDependencies.billingApi.isApiAvailable()) {
|
if (!AppDependencies.billingApi.isApiAvailable()) {
|
||||||
Log.i(TAG, "Google Play Billing API is not available on this device. Clearing mismatch value and exiting.")
|
Log.i(TAG, "Google Play Billing API is not available on this device. Clearing mismatch value and exiting.", true)
|
||||||
SignalStore.backup.subscriptionStateMismatchDetected = false
|
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SignalStore.backup.deletionState != DeletionState.NONE) {
|
if (SignalStore.backup.deletionState != DeletionState.NONE) {
|
||||||
Log.i(TAG, "User is in the process of or has delete their backup. Clearing mismatch value and exiting.")
|
Log.i(TAG, "User is in the process of or has delete their backup. Clearing mismatch value and exiting.", true)
|
||||||
SignalStore.backup.subscriptionStateMismatchDetected = false
|
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SignalStore.backup.areBackupsEnabled) {
|
if (!SignalStore.backup.areBackupsEnabled) {
|
||||||
Log.i(TAG, "Backups are not enabled on this device. Clearing mismatch value and exiting.")
|
Log.i(TAG, "Backups are not enabled on this device. Clearing mismatch value and exiting.", true)
|
||||||
SignalStore.backup.subscriptionStateMismatchDetected = false
|
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
val purchase: BillingPurchaseResult = AppDependencies.billingApi.queryPurchases()
|
val purchase: BillingPurchaseResult = AppDependencies.billingApi.queryPurchases()
|
||||||
Log.i(TAG, "Retrieved purchase result from Billing api: $purchase")
|
Log.i(TAG, "Retrieved purchase result from Billing api: $purchase", true)
|
||||||
|
|
||||||
val hasActivePurchase = purchase is BillingPurchaseResult.Success && purchase.isAcknowledged
|
val hasActivePurchase = purchase is BillingPurchaseResult.Success && purchase.isAcknowledged
|
||||||
val product: BillingProduct? = AppDependencies.billingApi.queryProduct()
|
val product: BillingProduct? = AppDependencies.billingApi.queryProduct()
|
||||||
|
|
||||||
if (product == null) {
|
if (product == null) {
|
||||||
Log.w(TAG, "Google Play Billing product not available. Exiting.")
|
Log.w(TAG, "Google Play Billing product not available. Exiting.", true)
|
||||||
return Result.failure()
|
return Result.failure()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C
|
|||||||
val inAppPayment = SignalDatabase.inAppPayments.getLatestInAppPaymentByType(InAppPaymentType.RECURRING_BACKUP)
|
val inAppPayment = SignalDatabase.inAppPayments.getLatestInAppPaymentByType(InAppPaymentType.RECURRING_BACKUP)
|
||||||
|
|
||||||
if (inAppPayment?.state == InAppPaymentTable.State.PENDING) {
|
if (inAppPayment?.state == InAppPaymentTable.State.PENDING) {
|
||||||
Log.i(TAG, "User has a pending in-app payment. Clearing mismatch value and re-checking later.")
|
Log.i(TAG, "User has a pending in-app payment. Clearing mismatch value and re-checking later.", true)
|
||||||
SignalStore.backup.subscriptionStateMismatchDetected = false
|
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
@@ -125,24 +125,27 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C
|
|||||||
|
|
||||||
checkForFailedOrCanceledSubscriptionState(activeSubscription)
|
checkForFailedOrCanceledSubscriptionState(activeSubscription)
|
||||||
|
|
||||||
Log.i(TAG, "Synchronizing backup tier with value from server.")
|
val isSignalSubscriptionFailedOrCanceled = activeSubscription?.isFailedPayment == true || activeSubscription?.isCanceled == true
|
||||||
|
if (hasActiveSignalSubscription && !isSignalSubscriptionFailedOrCanceled) {
|
||||||
|
Log.i(TAG, "Detected an active, non-failed, non-canceled signal subscription. Synchronizing backup tier with value from server.", true)
|
||||||
BackupRepository.getBackupTier().runIfSuccessful {
|
BackupRepository.getBackupTier().runIfSuccessful {
|
||||||
SignalStore.backup.backupTier = it
|
SignalStore.backup.backupTier = it
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val hasActivePaidBackupTier = SignalStore.backup.backupTier == MessageBackupTier.PAID
|
val hasActivePaidBackupTier = SignalStore.backup.backupTier == MessageBackupTier.PAID
|
||||||
val hasValidActiveState = hasActivePaidBackupTier && hasActiveSignalSubscription && hasActivePurchase
|
val hasValidActiveState = hasActivePaidBackupTier && hasActiveSignalSubscription && hasActivePurchase
|
||||||
val hasValidInactiveState = !hasActivePaidBackupTier && !hasActiveSignalSubscription && !hasActivePurchase
|
val hasValidInactiveState = !hasActivePaidBackupTier && !hasActiveSignalSubscription && !hasActivePurchase
|
||||||
|
|
||||||
val purchaseToken = if (hasActivePurchase) {
|
val purchaseToken = if (hasActivePurchase) {
|
||||||
(purchase as BillingPurchaseResult.Success).purchaseToken
|
purchase.purchaseToken
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasTokenMismatch = purchaseToken?.let { hasLocalDevicePurchaseTokenMismatch(purchaseToken) } == true
|
val hasTokenMismatch = purchaseToken?.let { hasLocalDevicePurchaseTokenMismatch(purchaseToken) } == true
|
||||||
if (hasActiveSignalSubscription && hasTokenMismatch) {
|
if (hasActiveSignalSubscription && hasTokenMismatch) {
|
||||||
Log.i(TAG, "Encountered token mismatch with an active Signal subscription. Attempting to redeem against latest token.")
|
Log.i(TAG, "Encountered token mismatch with an active Signal subscription. Attempting to redeem against latest token.", true)
|
||||||
enqueueRedemptionForNewToken(purchaseToken, product.price)
|
enqueueRedemptionForNewToken(purchaseToken, product.price)
|
||||||
SignalStore.backup.subscriptionStateMismatchDetected = false
|
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||||
return Result.success()
|
return Result.success()
|
||||||
@@ -151,6 +154,13 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C
|
|||||||
Log.i(TAG, "Valid state: (hasValidActiveState: $hasValidActiveState, hasValidInactiveState: $hasValidInactiveState). Clearing mismatch value and exiting.", true)
|
Log.i(TAG, "Valid state: (hasValidActiveState: $hasValidActiveState, hasValidInactiveState: $hasValidInactiveState). Clearing mismatch value and exiting.", true)
|
||||||
SignalStore.backup.subscriptionStateMismatchDetected = false
|
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||||
return Result.success()
|
return Result.success()
|
||||||
|
} else {
|
||||||
|
val isGooglePlayBillingCanceled = purchase is BillingPurchaseResult.Success && !purchase.isAutoRenewing
|
||||||
|
|
||||||
|
if (isGooglePlayBillingCanceled && (!hasActiveSignalSubscription || isSignalSubscriptionFailedOrCanceled)) {
|
||||||
|
Log.i(TAG, "Valid cancel state. Clearing mismatch. (isGooglePlayBillingCanceled: true, hasActiveSignalSubscription: $hasActiveSignalSubscription, isSignalSubscriptionFailedOrCanceled: $isSignalSubscriptionFailedOrCanceled", true)
|
||||||
|
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||||
|
return Result.success()
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "State mismatch: (hasActivePaidBackupTier: $hasActivePaidBackupTier, hasActiveSignalSubscription: $hasActiveSignalSubscription, hasActivePurchase: $hasActivePurchase). Setting mismatch value and exiting.", true)
|
Log.w(TAG, "State mismatch: (hasActivePaidBackupTier: $hasActivePaidBackupTier, hasActiveSignalSubscription: $hasActiveSignalSubscription, hasActivePurchase: $hasActivePurchase). Setting mismatch value and exiting.", true)
|
||||||
SignalStore.backup.subscriptionStateMismatchDetected = true
|
SignalStore.backup.subscriptionStateMismatchDetected = true
|
||||||
@@ -159,6 +169,7 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for a payment failure / subscription cancellation. If either of these things occur, we will mark when to display
|
* Checks for a payment failure / subscription cancellation. If either of these things occur, we will mark when to display
|
||||||
|
|||||||
@@ -8072,6 +8072,8 @@
|
|||||||
<string name="BackupsSettingsFragment_s_month_renews_s">%1$s/month, renews %2$s</string>
|
<string name="BackupsSettingsFragment_s_month_renews_s">%1$s/month, renews %2$s</string>
|
||||||
<!-- Subtitle for row for active backup, placeholder is last date of backup -->
|
<!-- Subtitle for row for active backup, placeholder is last date of backup -->
|
||||||
<string name="BackupsSettingsFragment_last_backup_s">Last backup %1$s</string>
|
<string name="BackupsSettingsFragment_last_backup_s">Last backup %1$s</string>
|
||||||
|
<!-- Subtitle for row for canceled backup -->
|
||||||
|
<string name="BackupsSettingsFragment__subscription_canceled">Subscription canceled</string>
|
||||||
<!-- Subtitle for row for no backup ever created -->
|
<!-- Subtitle for row for no backup ever created -->
|
||||||
<string name="BackupsSettingsFragment_automatic_backups_with_signals">Automatic backups with Signal\'s secure end-to-end encrypted storage service.</string>
|
<string name="BackupsSettingsFragment_automatic_backups_with_signals">Automatic backups with Signal\'s secure end-to-end encrypted storage service.</string>
|
||||||
<!-- Subtitle for row for backups that are active but subscription not found -->
|
<!-- Subtitle for row for backups that are active but subscription not found -->
|
||||||
|
|||||||
Reference in New Issue
Block a user