[android] Made purchase controller and validator savable to survive the screen rotation during validation process

This commit is contained in:
Александр Зацепин 2019-04-02 15:10:38 +03:00 committed by yoksnod
parent 7ab237c8e7
commit bcd6534ef8
7 changed files with 124 additions and 5 deletions

View file

@ -24,6 +24,8 @@ public class PurchaseOperationObservable implements Framework.PurchaseValidation
private final Map<String, CoreValidationObserver> mValidationObservers = new HashMap<>();
@NonNull
private final List<CoreStartTransactionObserver> mTransactionObservers = new ArrayList<>();
@NonNull
private final Map<String, PendingResult> 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;
}
}
}

View file

@ -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<V, B, UiCallback extends PurchaseCallb
abstract void onDestroy();
@Override
public void onSave(@NonNull Bundle outState)
{
mValidator.onSave(outState);
}
@Override
public void onRestore(@NonNull Bundle inState)
{
mValidator.onRestore(inState);
}
abstract class AbstractPlayStoreBillingCallback implements PlayStoreBillingCallback
{
@Override

View file

@ -83,6 +83,8 @@ public class BookmarkPaymentFragment extends BaseMwmFragment
mPurchaseController = PurchaseFactory.createBookmarkPurchaseController(requireContext(),
mPaymentData.getProductId(),
mPaymentData.getServerId());
if (savedInstanceState != null)
mPurchaseController.onRestore(savedInstanceState);
mPurchaseController.initialize(requireActivity());
View root = inflater.inflate(R.layout.fragment_bookmark_payment, container, false);
TextView buyButton = root.findViewById(R.id.buy_btn);
@ -196,6 +198,7 @@ public class BookmarkPaymentFragment extends BaseMwmFragment
LOGGER.d(TAG, "onSaveInstanceState");
outState.putInt(EXTRA_CURRENT_STATE, mState.ordinal());
outState.putParcelable(EXTRA_PRODUCT_DETAILS, mProductDetails);
mPurchaseController.onSave(outState);
}
@Override

View file

@ -1,7 +1,9 @@
package com.mapswithme.maps.purchase;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Base64;
import com.mapswithme.maps.Framework;
@ -14,10 +16,13 @@ class DefaultPurchaseValidator implements PurchaseValidator<ValidationCallback>,
{
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<ValidationCallback>,
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<ValidationCallback>,
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<ValidationCallback>,
LOGGER.i(TAG, "Validation code: " + status);
String orderId = PurchaseUtils.parseOrderId(purchaseData);
mOperationObservable.removeValidationObserver(orderId);
mValidatedOrderId = null;
if (mCallback != null)
mCallback.onValidate(purchaseData, status);
}

View file

@ -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<Fail
mCallback = null;
}
@Override
public void onSave(@NonNull Bundle outState)
{
mValidator.onSave(outState);
}
@Override
public void onRestore(@NonNull Bundle inState)
{
mValidator.onRestore(inState);
}
private class ValidationCallbackImpl implements ValidationCallback
{

View file

@ -1,14 +1,17 @@
package com.mapswithme.maps.purchase;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.NonNull;
import com.mapswithme.maps.base.Savable;
/**
* Provides necessary purchase functionality to the UI. Controls whole platform-specific billing
* process. This controller has to be used only within {@link #initialize(Activity)} and {@link #destroy()}
* interval.
*/
public interface PurchaseController<T>
public interface PurchaseController<T> extends Savable<Bundle>
{
/**
* Initializes the controller.

View file

@ -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}.<br><br>
@ -10,7 +13,7 @@ import android.support.annotation.Nullable;
* <b>one-to-one</b>. If you need to validate different purchases you have to create different
* implementations of this interface.
*/
interface PurchaseValidator<T>
interface PurchaseValidator<T> extends Savable<Bundle>
{
/**
* Validates the purchase with specified purchase data.