From bcd6534ef8995bc4a7e06a67e43199c7c5c6be62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=97=D0=B0=D1=86=D0=B5=D0=BF=D0=B8=D0=BD?= Date: Tue, 2 Apr 2019 15:10:38 +0300 Subject: [PATCH] [android] Made purchase controller and validator savable to survive the screen rotation during validation process --- .../maps/PurchaseOperationObservable.java | 65 ++++++++++++++++++- .../purchase/AbstractPurchaseController.java | 13 ++++ .../purchase/BookmarkPaymentFragment.java | 3 + .../purchase/DefaultPurchaseValidator.java | 25 ++++++- .../FailedBookmarkPurchaseController.java | 13 ++++ .../maps/purchase/PurchaseController.java | 5 +- .../maps/purchase/PurchaseValidator.java | 5 +- 7 files changed, 124 insertions(+), 5 deletions(-) diff --git a/android/src/com/mapswithme/maps/PurchaseOperationObservable.java b/android/src/com/mapswithme/maps/PurchaseOperationObservable.java index 332c2beea5..f98548d64d 100644 --- a/android/src/com/mapswithme/maps/PurchaseOperationObservable.java +++ b/android/src/com/mapswithme/maps/PurchaseOperationObservable.java @@ -24,6 +24,8 @@ public class PurchaseOperationObservable implements Framework.PurchaseValidation private final Map mValidationObservers = new HashMap<>(); @NonNull private final List mTransactionObservers = new ArrayList<>(); + @NonNull + private final Map mValidationPendingResults = new HashMap<>(); @SuppressWarnings("NullableProblems") @NonNull private Logger mLogger; @@ -56,10 +58,15 @@ public class PurchaseOperationObservable implements Framework.PurchaseValidation String purchaseData = new String(tokenBytes); String orderId = PurchaseUtils.parseOrderId(purchaseData); CoreValidationObserver observer = mValidationObservers.get(orderId); + ValidationStatus status = ValidationStatus.values()[code]; if (observer == null) + { + PendingResult result = new PendingResult(status, serverId, vendorId, purchaseData); + mValidationPendingResults.put(orderId, result); return; + } - observer.onValidatePurchase(ValidationStatus.values()[code], serverId, vendorId, purchaseData); + observer.onValidatePurchase(status, serverId, vendorId, purchaseData); } @Override @@ -70,10 +77,19 @@ public class PurchaseOperationObservable implements Framework.PurchaseValidation observer.onStartTransaction(success, serverId, vendorId); } - public void addValidationObserver(@NonNull String orderId, @NonNull CoreValidationObserver observer) + public void addValidationObserver(@NonNull String orderId, + @NonNull CoreValidationObserver observer) { mLogger.d(TAG, "Add validation observer '" + observer + "' for '" + orderId + "'"); mValidationObservers.put(orderId, observer); + PendingResult result = mValidationPendingResults.remove(orderId); + if (result != null) + { + mLogger.d(TAG, "Post pending validation result to '" + observer + "' for '" + + orderId + "'"); + observer.onValidatePurchase(result.getStatus(), result.getServerId(), result.getVendorId(), + result.getPurchaseData()); + } } public void removeValidationObserver(@NonNull String orderId) @@ -93,4 +109,49 @@ public class PurchaseOperationObservable implements Framework.PurchaseValidation mLogger.d(TAG, "Remove transaction observer '" + observer + "'"); mTransactionObservers.remove(observer); } + + private static class PendingResult + { + @NonNull + private final ValidationStatus mStatus; + @NonNull + private final String mServerId; + @NonNull + private final String mVendorId; + @NonNull + private final String mPurchaseData; + + private PendingResult(@NonNull ValidationStatus status, @NonNull String serverId, + @NonNull String vendorId, @NonNull String purchaseData) + { + mStatus = status; + mServerId = serverId; + mVendorId = vendorId; + mPurchaseData = purchaseData; + } + + @NonNull + ValidationStatus getStatus() + { + return mStatus; + } + + @NonNull + String getServerId() + { + return mServerId; + } + + @NonNull + String getVendorId() + { + return mVendorId; + } + + @NonNull + String getPurchaseData() + { + return mPurchaseData; + } + } } diff --git a/android/src/com/mapswithme/maps/purchase/AbstractPurchaseController.java b/android/src/com/mapswithme/maps/purchase/AbstractPurchaseController.java index ef7b2d0dbd..81a0c263cb 100644 --- a/android/src/com/mapswithme/maps/purchase/AbstractPurchaseController.java +++ b/android/src/com/mapswithme/maps/purchase/AbstractPurchaseController.java @@ -1,6 +1,7 @@ package com.mapswithme.maps.purchase; import android.app.Activity; +import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -128,6 +129,18 @@ abstract class AbstractPurchaseController, { private static final Logger LOGGER = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.BILLING); private static final String TAG = DefaultPurchaseValidator.class.getSimpleName(); + private static final String EXTRA_VALIDATED_ORDER_ID = "extra_validated_order_id"; @Nullable private ValidationCallback mCallback; @NonNull private final PurchaseOperationObservable mOperationObservable; + @Nullable + private String mValidatedOrderId; DefaultPurchaseValidator(@NonNull PurchaseOperationObservable validationObservable) { @@ -28,7 +33,8 @@ class DefaultPurchaseValidator implements PurchaseValidator, public void validate(@Nullable String serverId, @NonNull String vendor, @NonNull String purchaseData) { - String orderId = PurchaseUtils.parseOrderId(purchaseData); + final String orderId = PurchaseUtils.parseOrderId(purchaseData); + mValidatedOrderId = orderId; mOperationObservable.addValidationObserver(orderId, this); String encodedPurchaseData = Base64.encodeToString(purchaseData.getBytes(), Base64.DEFAULT); Framework.nativeValidatePurchase(serverId == null ? "" : serverId, vendor, encodedPurchaseData); @@ -38,12 +44,28 @@ class DefaultPurchaseValidator implements PurchaseValidator, public void addCallback(@NonNull ValidationCallback callback) { mCallback = callback; + if (!TextUtils.isEmpty(mValidatedOrderId)) + mOperationObservable.addValidationObserver(mValidatedOrderId, this); } @Override public void removeCallback() { mCallback = null; + if (!TextUtils.isEmpty(mValidatedOrderId)) + mOperationObservable.removeValidationObserver(mValidatedOrderId); + } + + @Override + public void onSave(@NonNull Bundle outState) + { + outState.putString(EXTRA_VALIDATED_ORDER_ID, mValidatedOrderId); + } + + @Override + public void onRestore(@NonNull Bundle inState) + { + mValidatedOrderId = inState.getString(EXTRA_VALIDATED_ORDER_ID); } @Override @@ -53,6 +75,7 @@ class DefaultPurchaseValidator implements PurchaseValidator, LOGGER.i(TAG, "Validation code: " + status); String orderId = PurchaseUtils.parseOrderId(purchaseData); mOperationObservable.removeValidationObserver(orderId); + mValidatedOrderId = null; if (mCallback != null) mCallback.onValidate(purchaseData, status); } diff --git a/android/src/com/mapswithme/maps/purchase/FailedBookmarkPurchaseController.java b/android/src/com/mapswithme/maps/purchase/FailedBookmarkPurchaseController.java index cf7132c105..ad60a927b1 100644 --- a/android/src/com/mapswithme/maps/purchase/FailedBookmarkPurchaseController.java +++ b/android/src/com/mapswithme/maps/purchase/FailedBookmarkPurchaseController.java @@ -1,6 +1,7 @@ package com.mapswithme.maps.purchase; import android.app.Activity; +import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -87,6 +88,18 @@ public class FailedBookmarkPurchaseController implements PurchaseController +public interface PurchaseController extends Savable { /** * Initializes the controller. diff --git a/android/src/com/mapswithme/maps/purchase/PurchaseValidator.java b/android/src/com/mapswithme/maps/purchase/PurchaseValidator.java index 3191b44ac7..26a25498a7 100644 --- a/android/src/com/mapswithme/maps/purchase/PurchaseValidator.java +++ b/android/src/com/mapswithme/maps/purchase/PurchaseValidator.java @@ -1,8 +1,11 @@ package com.mapswithme.maps.purchase; +import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import com.mapswithme.maps.base.Savable; + /** * Represents a purchase validator. The main of purpose is to validate existing purchase and inform * the client code through typed callback {@link T}.

@@ -10,7 +13,7 @@ import android.support.annotation.Nullable; * one-to-one. If you need to validate different purchases you have to create different * implementations of this interface. */ -interface PurchaseValidator +interface PurchaseValidator extends Savable { /** * Validates the purchase with specified purchase data.