kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add better application error handling for badges and token redemption.
rodzic
2b6190bf34
commit
b8dc541fc5
|
@ -36,6 +36,10 @@ data class Badge(
|
|||
val visible: Boolean,
|
||||
) : Parcelable, Key {
|
||||
|
||||
fun setVisible(): Badge {
|
||||
return copy(visible = true)
|
||||
}
|
||||
|
||||
fun isExpired(): Boolean = expirationTimestamp < System.currentTimeMillis() && expirationTimestamp > 0
|
||||
fun isBoost(): Boolean = id == BOOST_BADGE_ID
|
||||
|
||||
|
|
|
@ -2,4 +2,5 @@ package org.thoughtcrime.securesms.components.settings.app.subscription
|
|||
|
||||
class DonationExceptions {
|
||||
object TimedOutWaitingForTokenRedemption : Exception()
|
||||
object RedemptionFailed : Exception()
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.signal.donations.GooglePayApi
|
|||
import org.signal.donations.GooglePayPaymentSource
|
||||
import org.signal.donations.StripeApi
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobmanager.JobTracker
|
||||
import org.thoughtcrime.securesms.jobs.BoostReceiptRequestResponseJob
|
||||
import org.thoughtcrime.securesms.jobs.SubscriptionReceiptRequestResponseJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
|
@ -114,15 +115,30 @@ class DonationPaymentRepository(activity: Activity) : StripeApi.PaymentIntentFet
|
|||
val jobId = BoostReceiptRequestResponseJob.enqueueChain(paymentIntent)
|
||||
val countDownLatch = CountDownLatch(1)
|
||||
|
||||
var finalJobState: JobTracker.JobState? = null
|
||||
ApplicationDependencies.getJobManager().addListener(jobId) { _, jobState ->
|
||||
if (jobState.isComplete) {
|
||||
finalJobState = jobState
|
||||
countDownLatch.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (countDownLatch.await(10, TimeUnit.SECONDS)) {
|
||||
it.onComplete()
|
||||
when (finalJobState) {
|
||||
JobTracker.JobState.SUCCESS -> {
|
||||
Log.d(TAG, "Request response job chain succeeded.", true)
|
||||
it.onComplete()
|
||||
}
|
||||
JobTracker.JobState.FAILURE -> {
|
||||
Log.d(TAG, "Request response job chain failed permanently.", true)
|
||||
it.onError(DonationExceptions.RedemptionFailed)
|
||||
}
|
||||
else -> {
|
||||
Log.d(TAG, "Request response job chain ignored due to in-progress jobs.", true)
|
||||
it.onError(DonationExceptions.TimedOutWaitingForTokenRedemption)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
it.onError(DonationExceptions.TimedOutWaitingForTokenRedemption)
|
||||
}
|
||||
|
@ -137,7 +153,7 @@ class DonationPaymentRepository(activity: Activity) : StripeApi.PaymentIntentFet
|
|||
.flatMapCompletable { levelUpdateOperation ->
|
||||
val subscriber = SignalStore.donationsValues().requireSubscriber()
|
||||
|
||||
Log.d(TAG, "Attempting to set user subscription level to $subscriptionLevel")
|
||||
Log.d(TAG, "Attempting to set user subscription level to $subscriptionLevel", true)
|
||||
|
||||
ApplicationDependencies.getDonationsService().updateSubscriptionLevel(
|
||||
subscriber.subscriberId,
|
||||
|
@ -145,27 +161,46 @@ class DonationPaymentRepository(activity: Activity) : StripeApi.PaymentIntentFet
|
|||
subscriber.currencyCode,
|
||||
levelUpdateOperation.idempotencyKey.serialize()
|
||||
).flatMap(ServiceResponse<EmptyResponse>::flattenResult).ignoreElement().andThen {
|
||||
Log.d(TAG, "Successfully set user subscription to level $subscriptionLevel", true)
|
||||
SignalStore.donationsValues().clearUserManuallyCancelled()
|
||||
SignalStore.donationsValues().clearLevelOperation()
|
||||
LevelUpdate.updateProcessingState(false)
|
||||
it.onComplete()
|
||||
}.andThen {
|
||||
Log.d(TAG, "Enqueuing request response job chain.", true)
|
||||
val jobId = SubscriptionReceiptRequestResponseJob.enqueueSubscriptionContinuation()
|
||||
val countDownLatch = CountDownLatch(1)
|
||||
|
||||
var finalJobState: JobTracker.JobState? = null
|
||||
ApplicationDependencies.getJobManager().addListener(jobId) { _, jobState ->
|
||||
if (jobState.isComplete) {
|
||||
finalJobState = jobState
|
||||
countDownLatch.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (countDownLatch.await(10, TimeUnit.SECONDS)) {
|
||||
it.onComplete()
|
||||
when (finalJobState) {
|
||||
JobTracker.JobState.SUCCESS -> {
|
||||
Log.d(TAG, "Request response job chain succeeded.", true)
|
||||
it.onComplete()
|
||||
}
|
||||
JobTracker.JobState.FAILURE -> {
|
||||
Log.d(TAG, "Request response job chain failed permanently.", true)
|
||||
it.onError(DonationExceptions.RedemptionFailed)
|
||||
}
|
||||
else -> {
|
||||
Log.d(TAG, "Request response job chain ignored due to in-progress jobs.", true)
|
||||
it.onError(DonationExceptions.TimedOutWaitingForTokenRedemption)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Request response job timed out.", true)
|
||||
it.onError(DonationExceptions.TimedOutWaitingForTokenRedemption)
|
||||
}
|
||||
} catch (e: InterruptedException) {
|
||||
Log.w(TAG, "Request response interrupted.", e, true)
|
||||
it.onError(DonationExceptions.TimedOutWaitingForTokenRedemption)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,11 +21,13 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
|||
import org.thoughtcrime.securesms.components.settings.DSLSettingsBottomSheetFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.DonationEvent
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.DonationExceptions
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.models.CurrencySelection
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.models.GooglePayButton
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.help.HelpFragment
|
||||
import org.thoughtcrime.securesms.util.BottomSheetUtil.requireCoordinatorLayout
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
||||
|
@ -201,7 +203,7 @@ class BoostFragment : DSLSettingsBottomSheetFragment(
|
|||
|
||||
private fun onPaymentError(throwable: Throwable?) {
|
||||
if (throwable is DonationExceptions.TimedOutWaitingForTokenRedemption) {
|
||||
Log.w(TAG, "Error occurred while redeeming token", throwable)
|
||||
Log.w(TAG, "Timed out while redeeming token", throwable, true)
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.DonationsErrors__redemption_still_pending)
|
||||
.setMessage(R.string.DonationsErrors__you_might_not_see_your_badge_right_away)
|
||||
|
@ -210,8 +212,19 @@ class BoostFragment : DSLSettingsBottomSheetFragment(
|
|||
findNavController().popBackStack()
|
||||
}
|
||||
.show()
|
||||
} else if (throwable is DonationExceptions.RedemptionFailed) {
|
||||
Log.w(TAG, "Error occurred while trying to redeem token", throwable, true)
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.DonationsErrors__redemption_failed)
|
||||
.setMessage(R.string.DonationsErrors__please_contact_support)
|
||||
.setPositiveButton(R.string.Subscription__contact_support) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
requireActivity().finish()
|
||||
requireActivity().startActivity(AppSettingsActivity.help(requireContext(), HelpFragment.DONATION_INDEX))
|
||||
}
|
||||
.show()
|
||||
} else {
|
||||
Log.w(TAG, "Error occurred while processing payment", throwable)
|
||||
Log.w(TAG, "Error occurred while processing payment", throwable, true)
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.DonationsErrors__payment_failed)
|
||||
.setMessage(R.string.DonationsErrors__your_payment)
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.components.settings.app.subscription.DonationE
|
|||
import org.thoughtcrime.securesms.components.settings.app.subscription.models.CurrencySelection
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.models.GooglePayButton
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.help.HelpFragment
|
||||
import org.thoughtcrime.securesms.payments.FiatMoneyUtil
|
||||
import org.thoughtcrime.securesms.subscription.Subscription
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
|
@ -235,7 +236,7 @@ class SubscribeFragment : DSLSettingsFragment(
|
|||
|
||||
private fun onPaymentError(throwable: Throwable?) {
|
||||
if (throwable is DonationExceptions.TimedOutWaitingForTokenRedemption) {
|
||||
Log.w(TAG, "Error occurred while redeeming token", throwable)
|
||||
Log.w(TAG, "Timeout occurred while redeeming token", throwable, true)
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.DonationsErrors__redemption_still_pending)
|
||||
.setMessage(R.string.DonationsErrors__you_might_not_see_your_badge_right_away)
|
||||
|
@ -245,8 +246,19 @@ class SubscribeFragment : DSLSettingsFragment(
|
|||
requireActivity().startActivity(AppSettingsActivity.subscriptions(requireContext()))
|
||||
}
|
||||
.show()
|
||||
} else if (throwable is DonationExceptions.RedemptionFailed) {
|
||||
Log.w(TAG, "Error occurred while trying to redeem token", throwable, true)
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.DonationsErrors__redemption_failed)
|
||||
.setMessage(R.string.DonationsErrors__please_contact_support)
|
||||
.setPositiveButton(R.string.Subscription__contact_support) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
requireActivity().finish()
|
||||
requireActivity().startActivity(AppSettingsActivity.help(requireContext(), HelpFragment.DONATION_INDEX))
|
||||
}
|
||||
.show()
|
||||
} else {
|
||||
Log.w(TAG, "Error occurred while processing payment", throwable)
|
||||
Log.w(TAG, "Error occurred while processing payment", throwable, true)
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.DonationsErrors__payment_failed)
|
||||
.setMessage(R.string.DonationsErrors__your_payment)
|
||||
|
@ -267,7 +279,7 @@ class SubscribeFragment : DSLSettingsFragment(
|
|||
}
|
||||
|
||||
private fun onSubscriptionFailedToCancel(throwable: Throwable) {
|
||||
Log.w(TAG, "Failed to cancel subscription", throwable)
|
||||
Log.w(TAG, "Failed to cancel subscription", throwable, true)
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.DonationsErrors__failed_to_cancel_subscription)
|
||||
.setMessage(R.string.DonationsErrors__subscription_cancellation_requires_an_internet_connection)
|
||||
|
|
|
@ -19,9 +19,6 @@ import org.thoughtcrime.securesms.jobmanager.Data;
|
|||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.subscription.SubscriptionNotification;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
import org.whispersystems.signalservice.api.subscriptions.ActiveSubscription;
|
||||
import org.whispersystems.signalservice.api.subscriptions.SubscriberId;
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -122,12 +119,7 @@ public class BoostReceiptRequestResponseJob extends BaseJob {
|
|||
.blockingGet();
|
||||
|
||||
if (response.getApplicationError().isPresent()) {
|
||||
if (response.getStatus() == 204) {
|
||||
Log.w(TAG, "User does not have receipts available to exchange. Exiting.", response.getApplicationError().get());
|
||||
} else {
|
||||
Log.w(TAG, "Encountered a server failure: " + response.getStatus(), response.getApplicationError().get());
|
||||
throw new RetryableException();
|
||||
}
|
||||
handleApplicationError(response);
|
||||
} else if (response.getResult().isPresent()) {
|
||||
ReceiptCredential receiptCredential = getReceiptCredential(response.getResult().get());
|
||||
|
||||
|
@ -140,18 +132,36 @@ public class BoostReceiptRequestResponseJob extends BaseJob {
|
|||
receiptCredentialPresentation.serialize())
|
||||
.build());
|
||||
} else {
|
||||
Log.w(TAG, "Encountered a retryable exception: " + response.getStatus(), response.getExecutionError().orNull());
|
||||
Log.w(TAG, "Encountered a retryable exception: " + response.getStatus(), response.getExecutionError().orNull(), true);
|
||||
throw new RetryableException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleApplicationError(ServiceResponse<ReceiptCredentialResponse> response) throws Exception {
|
||||
Throwable applicationException = response.getApplicationError().get();
|
||||
switch (response.getStatus()) {
|
||||
case 204:
|
||||
Log.w(TAG, "User does not have receipts available to exchange. Exiting.", applicationException, true);
|
||||
break;
|
||||
case 400:
|
||||
Log.w(TAG, "Receipt credential request failed to validate.", applicationException, true);
|
||||
throw new Exception(applicationException);
|
||||
case 409:
|
||||
Log.w(TAG, "Receipt already redeemed with a different request credential.", response.getApplicationError().get(), true);
|
||||
throw new Exception(applicationException);
|
||||
default:
|
||||
Log.w(TAG, "Encountered a server failure: " + response.getStatus(), applicationException, true);
|
||||
throw new RetryableException();
|
||||
}
|
||||
}
|
||||
|
||||
private ReceiptCredentialPresentation getReceiptCredentialPresentation(@NonNull ReceiptCredential receiptCredential) throws RetryableException {
|
||||
ClientZkReceiptOperations operations = ApplicationDependencies.getClientZkReceiptOperations();
|
||||
|
||||
try {
|
||||
return operations.createReceiptCredentialPresentation(receiptCredential);
|
||||
} catch (VerificationFailedException e) {
|
||||
Log.w(TAG, "getReceiptCredentialPresentation: encountered a verification failure in zk", e);
|
||||
Log.w(TAG, "getReceiptCredentialPresentation: encountered a verification failure in zk", e, true);
|
||||
requestContext = null;
|
||||
throw new RetryableException();
|
||||
}
|
||||
|
@ -163,7 +173,7 @@ public class BoostReceiptRequestResponseJob extends BaseJob {
|
|||
try {
|
||||
return operations.receiveReceiptCredential(requestContext, response);
|
||||
} catch (VerificationFailedException e) {
|
||||
Log.w(TAG, "getReceiptCredential: encountered a verification failure in zk", e);
|
||||
Log.w(TAG, "getReceiptCredential: encountered a verification failure in zk", e, true);
|
||||
requestContext = null;
|
||||
throw new RetryableException();
|
||||
}
|
||||
|
|
|
@ -4,19 +4,14 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.zkgroup.receipts.ReceiptCredentialPresentation;
|
||||
import org.thoughtcrime.securesms.badges.models.Badge;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
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.whispersystems.signalservice.api.subscriptions.IdempotencyKey;
|
||||
import org.whispersystems.signalservice.internal.EmptyResponse;
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
|
@ -75,13 +70,13 @@ public class DonationReceiptRedemptionJob extends BaseJob {
|
|||
Data inputData = getInputData();
|
||||
|
||||
if (inputData == null) {
|
||||
Log.w(TAG, "No input data. Failing.");
|
||||
Log.w(TAG, "No input data. Failing.", null, true);
|
||||
throw new IllegalStateException("Expected a presentation object in input data.");
|
||||
}
|
||||
|
||||
byte[] presentationBytes = inputData.getStringAsBlob(INPUT_RECEIPT_CREDENTIAL_PRESENTATION);
|
||||
if (presentationBytes == null) {
|
||||
Log.d(TAG, "No response data. Exiting.");
|
||||
Log.d(TAG, "No response data. Exiting.", null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -92,10 +87,15 @@ public class DonationReceiptRedemptionJob extends BaseJob {
|
|||
.blockingGet();
|
||||
|
||||
if (response.getApplicationError().isPresent()) {
|
||||
Log.w(TAG, "Encountered a non-recoverable exception", response.getApplicationError().get());
|
||||
throw new IOException(response.getApplicationError().get());
|
||||
if (response.getStatus() >= 500) {
|
||||
Log.w(TAG, "Encountered a server exception " + response.getStatus(), response.getApplicationError().get(), true);
|
||||
throw new RetryableException();
|
||||
} else {
|
||||
Log.w(TAG, "Encountered a non-recoverable exception " + response.getStatus(), response.getApplicationError().get(), true);
|
||||
throw new IOException(response.getApplicationError().get());
|
||||
}
|
||||
} else if (response.getExecutionError().isPresent()) {
|
||||
Log.w(TAG, "Encountered a retryable exception", response.getExecutionError().get());
|
||||
Log.w(TAG, "Encountered a retryable exception", response.getExecutionError().get(), true);
|
||||
throw new RetryableException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.annotation.Nullable;
|
|||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.zkgroup.profiles.ProfileKey;
|
||||
import org.signal.zkgroup.profiles.ProfileKeyCredential;
|
||||
import org.thoughtcrime.securesms.badges.BadgeRepository;
|
||||
import org.thoughtcrime.securesms.badges.Badges;
|
||||
import org.thoughtcrime.securesms.badges.models.Badge;
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
|
@ -30,6 +31,7 @@ import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
|||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Ref;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
@ -213,9 +215,27 @@ public class RefreshOwnProfileJob extends BaseJob {
|
|||
SignalStore.donationsValues().setExpiredBadge(mostRecentExpiration);
|
||||
}
|
||||
|
||||
DatabaseFactory.getRecipientDatabase(context)
|
||||
.setBadges(Recipient.self().getId(),
|
||||
badges.stream().map(Badges::fromServiceBadge).collect(Collectors.toList()));
|
||||
boolean userHasVisibleBadges = badges.stream().anyMatch(SignalServiceProfile.Badge::isVisible);
|
||||
boolean userHasInvisibleBadges = badges.stream().anyMatch(b -> !b.isVisible());
|
||||
|
||||
List<Badge> appBadges = badges.stream().map(Badges::fromServiceBadge).collect(Collectors.toList());
|
||||
|
||||
if (userHasVisibleBadges && userHasInvisibleBadges) {
|
||||
Log.d(TAG, "Detected mixed visibility of badges. Telling the server to mark them all visible.", true);
|
||||
|
||||
BadgeRepository badgeRepository = new BadgeRepository(context);
|
||||
badgeRepository.setVisibilityForAllBadges(true);
|
||||
|
||||
DatabaseFactory.getRecipientDatabase(context)
|
||||
.setBadges(Recipient.self().getId(),
|
||||
appBadges.stream()
|
||||
.map(Badge::setVisible)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
} else {
|
||||
DatabaseFactory.getRecipientDatabase(context)
|
||||
.setBadges(Recipient.self().getId(), appBadges);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isSubscription(String badgeId) {
|
||||
|
|
|
@ -109,10 +109,10 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
|||
protected void onRun() throws Exception {
|
||||
ActiveSubscription.Subscription subscription = getLatestSubscriptionInformation();
|
||||
if (subscription == null || !subscription.isActive()) {
|
||||
Log.d(TAG, "User does not have an active subscription. Exiting.");
|
||||
Log.d(TAG, "User does not have an active subscription. Exiting.", true);
|
||||
return;
|
||||
} else {
|
||||
Log.i(TAG, "Recording end of period from active subscription.");
|
||||
Log.i(TAG, "Recording end of period from active subscription.", true);
|
||||
SignalStore.donationsValues().setLastEndOfPeriod(subscription.getEndOfCurrentPeriod());
|
||||
}
|
||||
|
||||
|
@ -133,12 +133,7 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
|||
.blockingGet();
|
||||
|
||||
if (response.getApplicationError().isPresent()) {
|
||||
if (response.getStatus() == 204) {
|
||||
Log.w(TAG, "User does not have receipts available to exchange. Exiting.", response.getApplicationError().get());
|
||||
} else {
|
||||
Log.w(TAG, "Encountered a server failure response: " + response.getStatus(), response.getApplicationError().get());
|
||||
throw new RetryableException();
|
||||
}
|
||||
handleApplicationError(response);
|
||||
} else if (response.getResult().isPresent()) {
|
||||
ReceiptCredential receiptCredential = getReceiptCredential(response.getResult().get());
|
||||
|
||||
|
@ -151,7 +146,7 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
|||
receiptCredentialPresentation.serialize())
|
||||
.build());
|
||||
} else {
|
||||
Log.w(TAG, "Encountered a retryable exception: " + response.getStatus(), response.getExecutionError().orNull());
|
||||
Log.w(TAG, "Encountered a retryable exception: " + response.getStatus(), response.getExecutionError().orNull(), true);
|
||||
throw new RetryableException();
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +159,7 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
|||
if (activeSubscription.getResult().isPresent()) {
|
||||
return activeSubscription.getResult().get().getActiveSubscription();
|
||||
} else if (activeSubscription.getApplicationError().isPresent()) {
|
||||
Log.w(TAG, "Unrecoverable error getting the user's current subscription. Failing.");
|
||||
Log.w(TAG, "Unrecoverable error getting the user's current subscription. Failing.", activeSubscription.getApplicationError().get(), true);
|
||||
throw new IOException(activeSubscription.getApplicationError().get());
|
||||
} else {
|
||||
throw new RetryableException();
|
||||
|
@ -177,7 +172,7 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
|||
try {
|
||||
return operations.createReceiptCredentialPresentation(receiptCredential);
|
||||
} catch (VerificationFailedException e) {
|
||||
Log.w(TAG, "getReceiptCredentialPresentation: encountered a verification failure in zk", e);
|
||||
Log.w(TAG, "getReceiptCredentialPresentation: encountered a verification failure in zk", e, true);
|
||||
requestContext = null;
|
||||
throw new RetryableException();
|
||||
}
|
||||
|
@ -189,12 +184,35 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
|||
try {
|
||||
return operations.receiveReceiptCredential(requestContext, response);
|
||||
} catch (VerificationFailedException e) {
|
||||
Log.w(TAG, "getReceiptCredential: encountered a verification failure in zk", e);
|
||||
Log.w(TAG, "getReceiptCredential: encountered a verification failure in zk", e, true);
|
||||
requestContext = null;
|
||||
throw new RetryableException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleApplicationError(ServiceResponse<ReceiptCredentialResponse> response) throws Exception {
|
||||
switch (response.getStatus()) {
|
||||
case 204:
|
||||
Log.w(TAG, "User does not have receipts available to exchange. Exiting.", response.getApplicationError().get(), true);
|
||||
break;
|
||||
case 400:
|
||||
Log.w(TAG, "Receipt credential request failed to validate.", response.getApplicationError().get(), true);
|
||||
throw new Exception(response.getApplicationError().get());
|
||||
case 403:
|
||||
Log.w(TAG, "SubscriberId password mismatch or account auth was present.", response.getApplicationError().get(), true);
|
||||
throw new Exception(response.getApplicationError().get());
|
||||
case 404:
|
||||
Log.w(TAG, "SubscriberId not found or misformed.", response.getApplicationError().get(), true);
|
||||
throw new Exception(response.getApplicationError().get());
|
||||
case 409:
|
||||
Log.w(TAG, "Latest paid receipt on subscription already redeemed with a different request credential.", response.getApplicationError().get(), true);
|
||||
throw new Exception(response.getApplicationError().get());
|
||||
default:
|
||||
Log.w(TAG, "Encountered a server failure response: " + response.getStatus(), response.getApplicationError().get(), true);
|
||||
throw new RetryableException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the generated Receipt Credential has the following characteristics
|
||||
* - level should match the current subscription level and be the same level you signed up for at the time the subscription was last updated
|
||||
|
|
|
@ -4007,6 +4007,8 @@
|
|||
<string name="DonationsErrors__payment_failed">Payment failed</string>
|
||||
<string name="DonationsErrors__your_payment">Your payment couldn\'t be processed and you have not been charged. Please try again.</string>
|
||||
<string name="DonationsErrors__redemption_still_pending">Redemption still pending</string>
|
||||
<string name="DonationsErrors__redemption_failed">Redemption failed</string>
|
||||
<string name="DonationsErrors__please_contact_support">Please contact support</string>
|
||||
<string name="DonationsErrors__you_might_not_see_your_badge_right_away">You may not see your badge right away, but we\'re working on it!</string>
|
||||
<string name="DonationsErrors__google_pay_unavailable">Google Pay Unavailable</string>
|
||||
<string name="DonationsErrors__you_have_to_set_up_google_pay_to_donate_in_app">You have to set up Google Pay to donate in-app.</string>
|
||||
|
|
Ładowanie…
Reference in New Issue