diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt index f4a90f23a4..be018bc302 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt @@ -430,6 +430,16 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter findNavController().safeNavigate(InternalSettingsFragmentDirections.actionInternalSettingsFragmentToDonorErrorConfigurationFragment()) } ) + + clickPref( + title = DSLSettingsText.from("Clear keep-alive timestamps"), + onClick = { + SignalStore.donationsValues().subscriptionEndOfPeriodRedemptionStarted = 0L + SignalStore.donationsValues().subscriptionEndOfPeriodConversionStarted = 0L + SignalStore.donationsValues().setLastEndOfPeriod(0L) + Toast.makeText(context, "Cleared", Toast.LENGTH_SHORT) + } + ) } dividerPref() diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalActivity.kt index a225e00bea..ce6cafbd91 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalActivity.kt @@ -20,7 +20,7 @@ class DonateToSignalActivity : FragmentWrapperActivity(), DonationPaymentCompone override val googlePayResultPublisher: Subject = PublishSubject.create() override fun getFragment(): Fragment { - return NavHostFragment.create(R.navigation.donate_to_signal, DonateToSignalFragmentArgs.Builder(DonateToSignalType.ONE_TIME).build().toBundle()) + return NavHostFragment.create(R.navigation.donate_to_signal, DonateToSignalFragmentArgs.Builder(DonateToSignalType.ONE_TIME).build().toBundle()) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java index ad8719dc4e..bc01a7769e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java @@ -39,6 +39,7 @@ public class DonationReceiptRedemptionJob extends BaseJob { public static final String SUBSCRIPTION_QUEUE = "ReceiptRedemption"; public static final String KEY = "DonationReceiptRedemptionJob"; public static final String INPUT_RECEIPT_CREDENTIAL_PRESENTATION = "data.receipt.credential.presentation"; + public static final String INPUT_KEEP_ALIVE_409 = "data.keep.alive.409"; public static final String DATA_ERROR_SOURCE = "data.error.source"; public static final String DATA_GIFT_MESSAGE_ID = "data.gift.message.id"; public static final String DATA_PRIMARY = "data.primary"; @@ -160,6 +161,12 @@ public class DonationReceiptRedemptionJob extends BaseJob { } private void doRun() throws Exception { + boolean isKeepAlive409 = getInputData() != null && getInputData().getBooleanOrDefault(INPUT_KEEP_ALIVE_409, false); + if (isKeepAlive409) { + Log.d(TAG, "Keep-Alive redemption job hit a 409. Exiting.", true); + return; + } + ReceiptCredentialPresentation presentation = getPresentation(); if (presentation == null) { Log.d(TAG, "No presentation available. Exiting.", true); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/SubscriptionReceiptRequestResponseJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/SubscriptionReceiptRequestResponseJob.java index 36153ae2e0..dfa9bee3fc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/SubscriptionReceiptRequestResponseJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/SubscriptionReceiptRequestResponseJob.java @@ -166,6 +166,7 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob { Log.i(TAG, "Subscription is valid, proceeding with request for ReceiptCredentialResponse", true); long storedEndOfPeriod = SignalStore.donationsValues().getLastEndOfPeriod(); if (storedEndOfPeriod < subscription.getEndOfCurrentPeriod()) { + Log.i(TAG, "Storing lastEndOfPeriod and syncing with linked devices", true); SignalStore.donationsValues().setLastEndOfPeriod(subscription.getEndOfCurrentPeriod()); MultiDeviceSubscriptionSyncRequestJob.enqueue(); } @@ -264,7 +265,7 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob { throw new Exception(response.getApplicationError().get()); case 409: onAlreadyRedeemed(response); - throw new Exception(response.getApplicationError().get()); + break; default: Log.w(TAG, "Encountered a server failure response: " + response.getStatus(), response.getApplicationError().get(), true); throw new RetryableException(); @@ -320,12 +321,17 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob { } } - private void onAlreadyRedeemed(ServiceResponse response) { + /** + * Handle 409 error code. This is a permanent failure for new subscriptions but an ignorable error for keep-alive messages. + */ + private void onAlreadyRedeemed(ServiceResponse response) throws Exception { if (isForKeepAlive) { Log.i(TAG, "KeepAlive: Latest paid receipt on subscription already redeemed with a different request credential, ignoring.", response.getApplicationError().get(), true); + setOutputData(new Data.Builder().putBoolean(DonationReceiptRedemptionJob.INPUT_KEEP_ALIVE_409, true).build()); } else { Log.w(TAG, "Latest paid receipt on subscription already redeemed with a different request credential.", response.getApplicationError().get(), true); DonationError.routeDonationError(context, DonationError.genericBadgeRedemptionFailure(getErrorSource())); + throw new Exception(response.getApplicationError().get()); } }