Claim IAP subscription if we detect a payment token mismatch.
This commit is contained in:
parent
fe5de65273
commit
e5e74967dc
2 changed files with 68 additions and 7 deletions
|
@ -215,8 +215,6 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO [backups] - handle other cases.
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -6,22 +6,29 @@
|
|||
package org.thoughtcrime.securesms.jobs
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import org.signal.core.util.billing.BillingProduct
|
||||
import org.signal.core.util.billing.BillingPurchaseResult
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.money.FiatMoney
|
||||
import org.signal.donations.InAppPaymentType
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupRepository
|
||||
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
||||
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
|
||||
import org.thoughtcrime.securesms.database.InAppPaymentTable
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.model.InAppPaymentSubscriberRecord
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.InAppPaymentData
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.jobmanager.CoroutineJob
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.whispersystems.signalservice.api.storage.IAPSubscriptionId
|
||||
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
/**
|
||||
|
@ -85,6 +92,12 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C
|
|||
|
||||
val purchase: BillingPurchaseResult = AppDependencies.billingApi.queryPurchases()
|
||||
val hasActivePurchase = purchase is BillingPurchaseResult.Success && purchase.isAcknowledged && purchase.isWithinTheLastMonth()
|
||||
val product: BillingProduct? = AppDependencies.billingApi.queryProduct()
|
||||
|
||||
if (product == null) {
|
||||
Log.w(TAG, "Google Play Billing product not available. Exiting.")
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
InAppPaymentSubscriberRecord.Type.BACKUP.lock.withLock {
|
||||
val inAppPayment = SignalDatabase.inAppPayments.getLatestInAppPaymentByType(InAppPaymentType.RECURRING_BACKUP)
|
||||
|
@ -107,18 +120,68 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C
|
|||
val hasValidActiveState = hasActivePaidBackupTier && hasActiveSignalSubscription && hasActivePurchase
|
||||
val hasValidInactiveState = !hasActivePaidBackupTier && !hasActiveSignalSubscription && !hasActivePurchase
|
||||
|
||||
if (hasValidActiveState || hasValidInactiveState) {
|
||||
Log.i(TAG, "Valid state: (hasValidActiveState: $hasValidActiveState, hasValidInactiveState: $hasValidInactiveState). Clearing mismatch value and exiting.", true)
|
||||
val purchaseToken = if (hasActivePurchase) {
|
||||
(purchase as BillingPurchaseResult.Success).purchaseToken
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
if (purchaseToken?.let { hasLocalDevicePurchaseTokenMismatch(purchaseToken) } == true) {
|
||||
Log.i(TAG, "Encountered token mismatch. Attempting to redeem.")
|
||||
enqueueRedemptionForNewToken(purchaseToken, product.price)
|
||||
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||
return Result.success()
|
||||
} else {
|
||||
Log.w(TAG, "State mismatch: (hasActivePaidBackupTier: $hasActivePaidBackupTier, hasActiveSignalSubscription: $hasActiveSignalSubscription, hasActivePurchase: $hasActivePurchase). Setting mismatch value and exiting.", true)
|
||||
SignalStore.backup.subscriptionStateMismatchDetected = true
|
||||
return Result.success()
|
||||
if (hasValidActiveState || hasValidInactiveState) {
|
||||
Log.i(TAG, "Valid state: (hasValidActiveState: $hasValidActiveState, hasValidInactiveState: $hasValidInactiveState). Clearing mismatch value and exiting.", true)
|
||||
SignalStore.backup.subscriptionStateMismatchDetected = false
|
||||
return Result.success()
|
||||
} else {
|
||||
Log.w(TAG, "State mismatch: (hasActivePaidBackupTier: $hasActivePaidBackupTier, hasActiveSignalSubscription: $hasActiveSignalSubscription, hasActivePurchase: $hasActivePurchase). Setting mismatch value and exiting.", true)
|
||||
SignalStore.backup.subscriptionStateMismatchDetected = true
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun enqueueRedemptionForNewToken(localDevicePurchaseToken: String, localProductPrice: FiatMoney) {
|
||||
RecurringInAppPaymentRepository.ensureSubscriberId(
|
||||
subscriberType = InAppPaymentSubscriberRecord.Type.BACKUP,
|
||||
isRotation = true,
|
||||
iapSubscriptionId = IAPSubscriptionId.GooglePlayBillingPurchaseToken(localDevicePurchaseToken)
|
||||
).blockingAwait()
|
||||
|
||||
SignalDatabase.inAppPayments.clearCreated()
|
||||
|
||||
val id = SignalDatabase.inAppPayments.insert(
|
||||
type = InAppPaymentType.RECURRING_BACKUP,
|
||||
state = InAppPaymentTable.State.CREATED,
|
||||
subscriberId = null,
|
||||
endOfPeriod = null,
|
||||
inAppPaymentData = InAppPaymentData(
|
||||
badge = null,
|
||||
amount = localProductPrice.toFiatValue(),
|
||||
level = SubscriptionsConfiguration.BACKUPS_LEVEL.toLong(),
|
||||
recipientId = Recipient.self().id.serialize(),
|
||||
paymentMethodType = InAppPaymentData.PaymentMethodType.GOOGLE_PLAY_BILLING,
|
||||
redemption = InAppPaymentData.RedemptionState(
|
||||
stage = InAppPaymentData.RedemptionState.Stage.INIT
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
InAppPaymentRecurringContextJob.createJobChain(
|
||||
inAppPayment = SignalDatabase.inAppPayments.getById(id)!!
|
||||
).enqueue()
|
||||
}
|
||||
|
||||
private fun hasLocalDevicePurchaseTokenMismatch(localDevicePurchaseToken: String): Boolean {
|
||||
val subscriber = InAppPaymentsRepository.getSubscriber(InAppPaymentSubscriberRecord.Type.BACKUP)
|
||||
|
||||
return subscriber?.iapSubscriptionId?.purchaseToken != localDevicePurchaseToken
|
||||
}
|
||||
|
||||
override fun serialize(): ByteArray? = null
|
||||
|
||||
override fun getFactoryKey(): String = KEY
|
||||
|
|
Loading…
Add table
Reference in a new issue