[android] Extracted common logic for subscription flow in abstract fragment for futher reuse

This commit is contained in:
Александр Зацепин 2019-11-06 19:53:03 +03:00 committed by yoksnod
parent 41483f244c
commit 0a77b44e08
2 changed files with 344 additions and 315 deletions

View file

@ -1,38 +1,94 @@
package com.mapswithme.maps.purchase;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.android.billingclient.api.SkuDetails;
import com.mapswithme.maps.Framework;
import com.mapswithme.maps.PrivateVariables;
import com.mapswithme.maps.R;
import com.mapswithme.maps.base.BaseAuthFragment;
import com.mapswithme.maps.bookmarks.data.BookmarkManager;
import com.mapswithme.maps.dialog.AlertDialog;
import com.mapswithme.maps.dialog.AlertDialogCallback;
import com.mapswithme.maps.dialog.ResolveFragmentManagerStrategy;
import com.mapswithme.util.ConnectionState;
import com.mapswithme.util.NetworkPolicy;
import com.mapswithme.util.log.Logger;
import com.mapswithme.util.log.LoggerFactory;
import com.mapswithme.util.statistics.Statistics;
import java.util.Collections;
import java.util.List;
abstract class AbstractBookmarkSubscriptionFragment extends BaseAuthFragment
implements PurchaseStateActivator<BookmarkSubscriptionPaymentState>, SubscriptionUiChangeListener
implements PurchaseStateActivator<BookmarkSubscriptionPaymentState>,
SubscriptionUiChangeListener, AlertDialogCallback
{
private static final Logger LOGGER = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.BILLING);
private static final String TAG = AbstractBookmarkSubscriptionFragment.class.getSimpleName();
private final static String EXTRA_CURRENT_STATE = "extra_current_state";
private final static String EXTRA_PRODUCT_DETAILS = "extra_product_details";
private boolean mPingingResult;
private boolean mValidationResult;
@NonNull
private final PingCallback mPingCallback = new PingCallback();
@NonNull
private final BookmarkSubscriptionCallback mPurchaseCallback = new BookmarkSubscriptionCallback();
@NonNull
private BookmarkSubscriptionPaymentState mState = BookmarkSubscriptionPaymentState.NONE;
@Nullable
private ProductDetails[] mProductDetails;
@SuppressWarnings("NullableProblems")
@NonNull
private PurchaseController<PurchaseCallback> mPurchaseController;
@Nullable
@Override
public final View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
@Nullable Bundle savedInstanceState)
{
mPurchaseController =
PurchaseFactory.createBookmarksSubscriptionPurchaseController(requireContext());
if (savedInstanceState != null)
mPurchaseController.onRestore(savedInstanceState);
mPurchaseController.initialize(requireActivity());
mPingCallback.attach(this);
BookmarkManager.INSTANCE.addCatalogPingListener(mPingCallback);
return onSubscriptionCreateView(inflater, container, savedInstanceState);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState != null)
{
BookmarkSubscriptionPaymentState savedState
=
BookmarkSubscriptionPaymentState.values()[savedInstanceState.getInt(EXTRA_CURRENT_STATE)];
ProductDetails[] productDetails
= (ProductDetails[]) savedInstanceState.getParcelableArray(EXTRA_PRODUCT_DETAILS);
if (productDetails != null)
mProductDetails = productDetails;
activateState(savedState);
return;
}
activateState(BookmarkSubscriptionPaymentState.CHECK_NETWORK_CONNECTION);
}
@Override
public final void onDestroyView()
{
@ -42,11 +98,98 @@ abstract class AbstractBookmarkSubscriptionFragment extends BaseAuthFragment
onSubscriptionDestroyView();
}
@Nullable
abstract View onSubscriptionCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState);
@Override
public final void onStart()
{
super.onStart();
mPurchaseController.addCallback(mPurchaseCallback);
mPurchaseCallback.attach(this);
}
abstract void onSubscriptionDestroyView();
@Override
public final void onStop()
{
super.onStop();
mPurchaseController.removeCallback();
mPurchaseCallback.detach();
}
private void queryProductDetails()
{
mPurchaseController.queryProductDetails();
}
void launchPurchaseFlow(@NonNull String productId)
{
mPurchaseController.launchPurchaseFlow(productId);
}
private void handleProductDetails(@NonNull List<SkuDetails> details)
{
mProductDetails = new ProductDetails[PurchaseUtils.Period.values().length];
for (SkuDetails sku : details)
{
PurchaseUtils.Period period = PurchaseUtils.Period.valueOf(sku.getSubscriptionPeriod());
mProductDetails[period.ordinal()] = PurchaseUtils.toProductDetails(sku);
}
}
@NonNull
ProductDetails getProductDetailsForPeriod(@NonNull PurchaseUtils.Period period)
{
if (mProductDetails == null)
throw new AssertionError("Product details must be exist at this moment!");
return mProductDetails[period.ordinal()];
}
@Override
public void onAuthorizationFinish(boolean success)
{
hideProgress();
if (!success)
{
Toast.makeText(requireContext(), R.string.profile_authorization_error, Toast.LENGTH_LONG)
.show();
return;
}
onAuthorizationFinishSuccessfully();
}
@Override
public void onAuthorizationStart()
{
showProgress();
}
@Override
protected int getProgressMessageId()
{
return R.string.please_wait;
}
@Override
public void onSocialAuthenticationCancel(@Framework.AuthTokenType int type)
{
LOGGER.i(TAG, "Social authentication cancelled, auth type = " + type);
}
@Override
public void onSocialAuthenticationError(@Framework.AuthTokenType int type, @Nullable String error)
{
LOGGER.w(TAG, "Social authentication error = " + error + ", auth type = " + type);
}
@Override
public void activateState(@NonNull BookmarkSubscriptionPaymentState state)
{
if (state == mState)
return;
LOGGER.i(TAG, "Activate state: " + state);
mState = state;
mState.activate(this);
}
private void handlePingingResult(boolean result)
{
@ -64,6 +207,48 @@ abstract class AbstractBookmarkSubscriptionFragment extends BaseAuthFragment
authorize();
}
@Override
public void onCheckNetworkConnection()
{
if (ConnectionState.isConnected())
NetworkPolicy.checkNetworkPolicy(requireFragmentManager(),
this::onNetworkPolicyResult, true);
else
PurchaseUtils.showNoConnectionDialog(this);
}
@Override
public void onProductDetailsFailure()
{
PurchaseUtils.showProductDetailsFailureDialog(this, getClass().getSimpleName());
}
@Override
public void onPaymentFailure()
{
PurchaseUtils.showPaymentFailureDialog(this, getClass().getSimpleName());
}
private void onNetworkPolicyResult(@NonNull NetworkPolicy policy)
{
if (policy.canUseNetwork())
onNetworkCheckPassed();
else
requireActivity().finish();
}
private void onNetworkCheckPassed()
{
activateState(BookmarkSubscriptionPaymentState.PRODUCT_DETAILS_LOADING);
}
@Override
@CallSuper
public void onProductDetailsLoading()
{
queryProductDetails();
}
@Override
@CallSuper
public void onPingFinish()
@ -71,6 +256,74 @@ abstract class AbstractBookmarkSubscriptionFragment extends BaseAuthFragment
finishPinging();
}
@Override
@CallSuper
public void onValidationFinish()
{
finishValidation();
}
private void finishValidation()
{
if (mValidationResult)
requireActivity().setResult(Activity.RESULT_OK);
requireActivity().finish();
}
private void handleValidationResult(boolean result)
{
mValidationResult = result;
}
@Override
public void onAlertDialogPositiveClick(int requestCode, int which)
{
if (requestCode == PurchaseUtils.REQ_CODE_NO_NETWORK_CONNECTION_DIALOG)
{
dismissOutdatedNoNetworkDialog();
activateState(BookmarkSubscriptionPaymentState.NONE);
activateState(BookmarkSubscriptionPaymentState.CHECK_NETWORK_CONNECTION);
}
}
private void dismissOutdatedNoNetworkDialog()
{
ResolveFragmentManagerStrategy strategy
= AlertDialog.FragManagerStrategyType.ACTIVITY_FRAGMENT_MANAGER.getValue();
FragmentManager manager = strategy.resolve(this);
Fragment outdatedInstance =
manager.findFragmentByTag(PurchaseUtils.NO_NETWORK_CONNECTION_DIALOG_TAG);
if (outdatedInstance == null)
return;
manager.beginTransaction().remove(outdatedInstance).commitAllowingStateLoss();
manager.executePendingTransactions();
}
@Override
public void onAlertDialogNegativeClick(int requestCode, int which)
{
if (requestCode == PurchaseUtils.REQ_CODE_NO_NETWORK_CONNECTION_DIALOG)
requireActivity().finish();
}
@Override
public void onAlertDialogCancel(int requestCode)
{
if (requestCode == PurchaseUtils.REQ_CODE_NO_NETWORK_CONNECTION_DIALOG)
requireActivity().finish();
}
@Nullable
abstract View onSubscriptionCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState);
abstract void onSubscriptionDestroyView();
abstract void onAuthorizationFinishSuccessfully();
private static class PingCallback
extends StatefulPurchaseCallback<BookmarkSubscriptionPaymentState,
AbstractBookmarkSubscriptionFragment> implements BookmarkManager.BookmarksCatalogPingListener
@ -100,4 +353,85 @@ abstract class AbstractBookmarkSubscriptionFragment extends BaseAuthFragment
}
}
}
private static class BookmarkSubscriptionCallback
extends StatefulPurchaseCallback<BookmarkSubscriptionPaymentState,
AbstractBookmarkSubscriptionFragment>
implements PurchaseCallback
{
@Nullable
private List<SkuDetails> mPendingDetails;
private Boolean mPendingValidationResult;
@Override
public void onProductDetailsLoaded(@NonNull List<SkuDetails> details)
{
if (PurchaseUtils.hasIncorrectSkuDetails(details))
{
activateStateSafely(BookmarkSubscriptionPaymentState.PRODUCT_DETAILS_FAILURE);
return;
}
if (getUiObject() == null)
mPendingDetails = Collections.unmodifiableList(details);
else
getUiObject().handleProductDetails(details);
activateStateSafely(BookmarkSubscriptionPaymentState.PRICE_SELECTION);
}
@Override
public void onPaymentFailure(int error)
{
Statistics.INSTANCE.trackPurchaseStoreError(PrivateVariables.bookmarksSubscriptionServerId(),
error);
activateStateSafely(BookmarkSubscriptionPaymentState.PAYMENT_FAILURE);
}
@Override
public void onProductDetailsFailure()
{
activateStateSafely(BookmarkSubscriptionPaymentState.PRODUCT_DETAILS_FAILURE);
}
@Override
public void onStoreConnectionFailed()
{
activateStateSafely(BookmarkSubscriptionPaymentState.PRODUCT_DETAILS_FAILURE);
}
@Override
public void onValidationStarted()
{
Statistics.INSTANCE.trackPurchaseEvent(Statistics.EventName.INAPP_PURCHASE_STORE_SUCCESS,
PrivateVariables.bookmarksSubscriptionServerId());
activateStateSafely(BookmarkSubscriptionPaymentState.VALIDATION);
}
@Override
public void onValidationFinish(boolean success)
{
if (getUiObject() == null)
mPendingValidationResult = success;
else
getUiObject().handleValidationResult(success);
activateStateSafely(BookmarkSubscriptionPaymentState.VALIDATION_FINISH);
}
@Override
void onAttach(@NonNull AbstractBookmarkSubscriptionFragment fragment)
{
if (mPendingDetails != null)
{
fragment.handleProductDetails(mPendingDetails);
mPendingDetails = null;
}
if (mPendingValidationResult != null)
{
fragment.handleValidationResult(mPendingValidationResult);
mPendingValidationResult = null;
}
}
}
}

View file

@ -1,70 +1,33 @@
package com.mapswithme.maps.purchase;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cardview.widget.CardView;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.android.billingclient.api.SkuDetails;
import com.mapswithme.maps.Framework;
import com.mapswithme.maps.PrivateVariables;
import com.mapswithme.maps.R;
import com.mapswithme.maps.bookmarks.data.BookmarkManager;
import com.mapswithme.maps.dialog.AlertDialog;
import com.mapswithme.maps.dialog.AlertDialogCallback;
import com.mapswithme.maps.dialog.ResolveFragmentManagerStrategy;
import com.mapswithme.util.ConnectionState;
import com.mapswithme.util.NetworkPolicy;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
import com.mapswithme.util.log.Logger;
import com.mapswithme.util.log.LoggerFactory;
import com.mapswithme.util.statistics.Statistics;
import java.util.Collections;
import java.util.List;
public class BookmarkSubscriptionFragment extends AbstractBookmarkSubscriptionFragment
implements AlertDialogCallback, PurchaseStateActivator<BookmarkSubscriptionPaymentState>,
SubscriptionUiChangeListener
{
static final String EXTRA_FROM = "extra_from";
private static final Logger LOGGER = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.BILLING);
private static final String TAG = BookmarkSubscriptionFragment.class.getSimpleName();
private final static String EXTRA_CURRENT_STATE = "extra_current_state";
private final static String EXTRA_PRODUCT_DETAILS = "extra_product_details";
private static final int DEF_ELEVATION = 0;
@SuppressWarnings("NullableProblems")
@NonNull
private PurchaseController<PurchaseCallback> mPurchaseController;
@NonNull
private final BookmarkSubscriptionCallback mPurchaseCallback = new BookmarkSubscriptionCallback();
@NonNull
private BookmarkSubscriptionPaymentState mState = BookmarkSubscriptionPaymentState.NONE;
@Nullable
private ProductDetails[] mProductDetails;
private boolean mValidationResult;
@Nullable
@Override
View onSubscriptionCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
mPurchaseController = PurchaseFactory.createBookmarksSubscriptionPurchaseController(requireContext());
if (savedInstanceState != null)
mPurchaseController.onRestore(savedInstanceState);
mPurchaseController.initialize(requireActivity());
View root = inflater.inflate(R.layout.bookmark_subscription_fragment, container, false);
CardView annualPriceCard = root.findViewById(R.id.annual_price_card);
CardView monthlyPriceCard = root.findViewById(R.id.monthly_price_card);
@ -130,68 +93,6 @@ public class BookmarkSubscriptionFragment extends AbstractBookmarkSubscriptionFr
Statistics.STATISTICS_CHANNEL_REALTIME);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState != null)
{
BookmarkSubscriptionPaymentState savedState
= BookmarkSubscriptionPaymentState.values()[savedInstanceState.getInt(EXTRA_CURRENT_STATE)];
ProductDetails[] productDetails
= (ProductDetails[]) savedInstanceState.getParcelableArray(EXTRA_PRODUCT_DETAILS);
if (productDetails != null)
mProductDetails = productDetails;
activateState(savedState);
return;
}
activateState(BookmarkSubscriptionPaymentState.CHECK_NETWORK_CONNECTION);
}
private void queryProductDetails()
{
mPurchaseController.queryProductDetails();
}
@Override
public void onStart()
{
super.onStart();
mPurchaseController.addCallback(mPurchaseCallback);
mPurchaseCallback.attach(this);
}
@Override
public void onStop()
{
super.onStop();
mPurchaseController.removeCallback();
mPurchaseCallback.detach();
}
@Override
public void activateState(@NonNull BookmarkSubscriptionPaymentState state)
{
if (state == mState)
return;
LOGGER.i(TAG, "Activate state: " + state);
mState = state;
mState.activate(this);
}
private void handleProductDetails(@NonNull List<SkuDetails> details)
{
mProductDetails = new ProductDetails[PurchaseUtils.Period.values().length];
for (SkuDetails sku: details)
{
PurchaseUtils.Period period = PurchaseUtils.Period.valueOf(sku.getSubscriptionPeriod());
mProductDetails[period.ordinal()] = PurchaseUtils.toProductDetails(sku);
}
}
private void updatePaymentButtons()
{
updateYearlyButton();
@ -224,52 +125,6 @@ public class BookmarkSubscriptionFragment extends AbstractBookmarkSubscriptionFr
return (int) (100 * (1 - pricePerYear / (pricePerMonth * PurchaseUtils.MONTHS_IN_YEAR)));
}
@NonNull
private ProductDetails getProductDetailsForPeriod(@NonNull PurchaseUtils.Period period)
{
if (mProductDetails == null)
throw new AssertionError("Product details must be exist at this moment!");
return mProductDetails[period.ordinal()];
}
@Override
public void onAlertDialogPositiveClick(int requestCode, int which)
{
if (requestCode == PurchaseUtils.REQ_CODE_NO_NETWORK_CONNECTION_DIALOG)
{
dismissOutdatedNoNetworkDialog();
activateState(BookmarkSubscriptionPaymentState.NONE);
activateState(BookmarkSubscriptionPaymentState.CHECK_NETWORK_CONNECTION);
}
}
@Override
public void onAlertDialogNegativeClick(int requestCode, int which)
{
if (requestCode == PurchaseUtils.REQ_CODE_NO_NETWORK_CONNECTION_DIALOG)
requireActivity().finish();
}
@Override
public void onAlertDialogCancel(int requestCode)
{
if (requestCode == PurchaseUtils.REQ_CODE_NO_NETWORK_CONNECTION_DIALOG)
requireActivity().finish();
}
private void handleActivationResult(boolean result)
{
mValidationResult = result;
}
private void finishValidation()
{
if (mValidationResult)
requireActivity().setResult(Activity.RESULT_OK);
requireActivity().finish();
}
@Override
public boolean onBackPressed()
{
@ -284,65 +139,15 @@ public class BookmarkSubscriptionFragment extends AbstractBookmarkSubscriptionFr
PurchaseUtils.Period period = annualCard.getCardElevation() > 0 ? PurchaseUtils.Period.P1Y
: PurchaseUtils.Period.P1M;
ProductDetails details = getProductDetailsForPeriod(period);
mPurchaseController.launchPurchaseFlow(details.getProductId());
launchPurchaseFlow(details.getProductId());
}
@Override
protected int getProgressMessageId()
void onAuthorizationFinishSuccessfully()
{
return R.string.please_wait;
}
@Override
public void onAuthorizationFinish(boolean success)
{
hideProgress();
if (!success)
{
Toast.makeText(requireContext(), R.string.profile_authorization_error, Toast.LENGTH_LONG)
.show();
return;
}
launchPurchaseFlow();
}
@Override
public void onAuthorizationStart()
{
showProgress();
}
@Override
public void onSocialAuthenticationCancel(@Framework.AuthTokenType int type)
{
LOGGER.i(TAG, "Social authentication cancelled, auth type = " + type);
}
@Override
public void onSocialAuthenticationError(@Framework.AuthTokenType int type, @Nullable String error)
{
LOGGER.w(TAG, "Social authentication error = " + error + ", auth type = " + type);
}
private void onNetworkCheckPassed()
{
activateState(BookmarkSubscriptionPaymentState.PRODUCT_DETAILS_LOADING);
}
private void dismissOutdatedNoNetworkDialog()
{
ResolveFragmentManagerStrategy strategy
= AlertDialog.FragManagerStrategyType.ACTIVITY_FRAGMENT_MANAGER.getValue();
FragmentManager manager = strategy.resolve(this);
Fragment outdatedInstance = manager.findFragmentByTag(PurchaseUtils.NO_NETWORK_CONNECTION_DIALOG_TAG);
if (outdatedInstance == null)
return;
manager.beginTransaction().remove(outdatedInstance).commitAllowingStateLoss();
manager.executePendingTransactions();
}
@Override
public void onReset()
{
@ -352,20 +157,8 @@ public class BookmarkSubscriptionFragment extends AbstractBookmarkSubscriptionFr
@Override
public void onProductDetailsLoading()
{
super.onProductDetailsLoading();
showRootScreenProgress();
queryProductDetails();
}
@Override
public void onProductDetailsFailure()
{
PurchaseUtils.showProductDetailsFailureDialog(this, getClass().getSimpleName());
}
@Override
public void onPaymentFailure()
{
PurchaseUtils.showPaymentFailureDialog(this, getClass().getSimpleName());
}
@Override
@ -384,8 +177,8 @@ public class BookmarkSubscriptionFragment extends AbstractBookmarkSubscriptionFr
@Override
public void onValidationFinish()
{
super.onValidationFinish();
hideButtonProgress();
finishValidation();
}
@Override
@ -401,24 +194,6 @@ public class BookmarkSubscriptionFragment extends AbstractBookmarkSubscriptionFr
hideButtonProgress();
}
@Override
public void onCheckNetworkConnection()
{
if (ConnectionState.isConnected())
NetworkPolicy.checkNetworkPolicy(requireFragmentManager(),
this::onNetworkPolicyResult, true);
else
PurchaseUtils.showNoConnectionDialog(this);
}
private void onNetworkPolicyResult(@NonNull NetworkPolicy policy)
{
if (policy.canUseNetwork())
onNetworkCheckPassed();
else
requireActivity().finish();
}
private void showButtonProgress()
{
UiUtils.hide(getViewOrThrow(), R.id.continue_btn);
@ -507,84 +282,4 @@ public class BookmarkSubscriptionFragment extends AbstractBookmarkSubscriptionFr
mAnnualPriceCard.setSelected(false);
}
}
private static class BookmarkSubscriptionCallback
extends StatefulPurchaseCallback<BookmarkSubscriptionPaymentState, BookmarkSubscriptionFragment>
implements PurchaseCallback
{
@Nullable
private List<SkuDetails> mPendingDetails;
private Boolean mPendingValidationResult;
@Override
public void onProductDetailsLoaded(@NonNull List<SkuDetails> details)
{
if (PurchaseUtils.hasIncorrectSkuDetails(details))
{
activateStateSafely(BookmarkSubscriptionPaymentState.PRODUCT_DETAILS_FAILURE);
return;
}
if (getUiObject() == null)
mPendingDetails = Collections.unmodifiableList(details);
else
getUiObject().handleProductDetails(details);
activateStateSafely(BookmarkSubscriptionPaymentState.PRICE_SELECTION);
}
@Override
public void onPaymentFailure(int error)
{
Statistics.INSTANCE.trackPurchaseStoreError(PrivateVariables.bookmarksSubscriptionServerId(),
error);
activateStateSafely(BookmarkSubscriptionPaymentState.PAYMENT_FAILURE);
}
@Override
public void onProductDetailsFailure()
{
activateStateSafely(BookmarkSubscriptionPaymentState.PRODUCT_DETAILS_FAILURE);
}
@Override
public void onStoreConnectionFailed()
{
activateStateSafely(BookmarkSubscriptionPaymentState.PRODUCT_DETAILS_FAILURE);
}
@Override
public void onValidationStarted()
{
Statistics.INSTANCE.trackPurchaseEvent(Statistics.EventName.INAPP_PURCHASE_STORE_SUCCESS,
PrivateVariables.bookmarksSubscriptionServerId());
activateStateSafely(BookmarkSubscriptionPaymentState.VALIDATION);
}
@Override
public void onValidationFinish(boolean success)
{
if (getUiObject() == null)
mPendingValidationResult = success;
else
getUiObject().handleActivationResult(success);
activateStateSafely(BookmarkSubscriptionPaymentState.VALIDATION_FINISH);
}
@Override
void onAttach(@NonNull BookmarkSubscriptionFragment bookmarkSubscriptionFragment)
{
if (mPendingDetails != null)
{
bookmarkSubscriptionFragment.handleProductDetails(mPendingDetails);
mPendingDetails = null;
}
if (mPendingValidationResult != null)
{
bookmarkSubscriptionFragment.handleActivationResult(mPendingValidationResult);
mPendingValidationResult = null;
}
}
}
}