Skip to content

Commit

Permalink
Create ActivityPaymentSessionListener
Browse files Browse the repository at this point in the history
**Summary**
`ActivityPaymentSessionListener` is an abstract
implementation of `PaymentSessionListener` that
handles holding a `WeakReference` to an `Activity`
context to avoid memory leaks in the listener's
callback methods.

**Motivation**
ANDROID-348

**Testing**
Manually tested in sample apps
  • Loading branch information
mshafrir-stripe committed Apr 11, 2019
1 parent 437f55b commit 7ca4cde
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 125 deletions.
Expand Up @@ -76,18 +76,27 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
setupCustomerSession(); // CustomerSession only needs to be initialized once per app.
mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ShippingInformation shippingInformation = intent.getParcelableExtra(EXTRA_SHIPPING_INFO_DATA);
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
ShippingInformation shippingInformation = intent
.getParcelableExtra(EXTRA_SHIPPING_INFO_DATA);
Intent shippingInfoProcessedIntent = new Intent(EVENT_SHIPPING_INFO_PROCESSED);
if (shippingInformation.getAddress() == null || !shippingInformation.getAddress().getCountry().equals(Locale.US.getCountry())) {
if (!isValidShippingInfo(shippingInformation)) {
shippingInfoProcessedIntent.putExtra(EXTRA_IS_SHIPPING_INFO_VALID, false);
} else {
ArrayList<ShippingMethod> shippingMethods = createSampleShippingMethods();
shippingInfoProcessedIntent.putExtra(EXTRA_IS_SHIPPING_INFO_VALID, true);
shippingInfoProcessedIntent.putParcelableArrayListExtra(EXTRA_VALID_SHIPPING_METHODS, shippingMethods);
shippingInfoProcessedIntent.putExtra(EXTRA_DEFAULT_SHIPPING_METHOD, shippingMethods.get(1));
shippingInfoProcessedIntent.putParcelableArrayListExtra(
EXTRA_VALID_SHIPPING_METHODS, shippingMethods);
shippingInfoProcessedIntent.putExtra(EXTRA_DEFAULT_SHIPPING_METHOD,
shippingMethods.get(1));
}
LocalBroadcastManager.getInstance(PaymentSessionActivity.this).sendBroadcast(shippingInfoProcessedIntent);
LocalBroadcastManager.getInstance(PaymentSessionActivity.this)
.sendBroadcast(shippingInfoProcessedIntent);
}

private boolean isValidShippingInfo(@NonNull ShippingInformation shippingInfo) {
return shippingInfo.getAddress() != null &&
Locale.US.getCountry().equals(shippingInfo.getAddress().getCountry());
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver,
Expand Down Expand Up @@ -141,27 +150,7 @@ public void onError(int httpCode, @Nullable String errorMessage,

private void setupPaymentSession() {
mPaymentSession = new PaymentSession(this);
boolean paymentSessionInitialized = mPaymentSession.init(new PaymentSession.PaymentSessionListener() {
@Override
public void onCommunicatingStateChanged(boolean isCommunicating) {
if (isCommunicating) {
mProgressBar.setVisibility(View.VISIBLE);
} else {
mProgressBar.setVisibility(View.INVISIBLE);
}
}

@Override
public void onError(int errorCode, @Nullable String errorMessage) {
mErrorDialogHandler.showError(errorMessage);
}

@Override
public void onPaymentSessionDataChanged(@NonNull PaymentSessionData data) {
mPaymentSessionData = data;
checkForCustomerUpdates();
}
}, new PaymentSessionConfig.Builder()
boolean paymentSessionInitialized = mPaymentSession.init(new PaymentSessionListenerImpl(this), new PaymentSessionConfig.Builder()
.setPrepopulatedShippingInfo(getExampleShippingInfo())
.setHiddenShippingInfoFields(ShippingInfoWidget.PHONE_FIELD, ShippingInfoWidget.CITY_FIELD)
.build());
Expand Down Expand Up @@ -194,7 +183,8 @@ public void onError(int httpCode, @Nullable String errorMessage,
});
}

private String formatStringResults(PaymentSessionData data) {
@NonNull
private String formatStringResults(@NonNull PaymentSessionData data) {
Currency currency = Currency.getInstance("USD");
StringBuilder stringBuilder = new StringBuilder();

Expand Down Expand Up @@ -232,10 +222,13 @@ private String formatStringResults(PaymentSessionData data) {
return stringBuilder.toString();
}

@NonNull
private ArrayList<ShippingMethod> createSampleShippingMethods() {
ArrayList<ShippingMethod> shippingMethods = new ArrayList<>();
shippingMethods.add(new ShippingMethod("UPS Ground", "ups-ground", "Arrives in 3-5 days", 0, "USD"));
shippingMethods.add(new ShippingMethod("FedEx", "fedex", "Arrives tomorrow", 599, "USD"));
final ArrayList<ShippingMethod> shippingMethods = new ArrayList<>();
shippingMethods.add(new ShippingMethod("UPS Ground", "ups-ground",
"Arrives in 3-5 days", 0, "USD"));
shippingMethods.add(new ShippingMethod("FedEx", "fedex",
"Arrives tomorrow", 599, "USD"));
return shippingMethods;
}

Expand All @@ -252,8 +245,9 @@ protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
}

@NonNull
private ShippingInformation getExampleShippingInfo() {
Address address = new Address.Builder()
final Address address = new Address.Builder()
.setCity("San Francisco")
.setCountry("US")
.setLine1("123 Market St")
Expand All @@ -263,4 +257,47 @@ private ShippingInformation getExampleShippingInfo() {
.build();
return new ShippingInformation(address, "Fake Name", "(555) 555-5555");
}

private void onPaymentSessionDataChanged(@NonNull PaymentSessionData data) {
mPaymentSessionData = data;
checkForCustomerUpdates();
}

private static final class PaymentSessionListenerImpl
extends PaymentSession.ActivityPaymentSessionListener<PaymentSessionActivity> {
private PaymentSessionListenerImpl(@NonNull PaymentSessionActivity activity) {
super(activity);
}

@Override
public void onCommunicatingStateChanged(boolean isCommunicating) {
final PaymentSessionActivity activity = getListenerActivity();
if (activity == null) {
return;
}

activity.mProgressBar
.setVisibility(isCommunicating ? View.VISIBLE : View.INVISIBLE);
}

@Override
public void onError(int errorCode, @Nullable String errorMessage) {
final PaymentSessionActivity activity = getListenerActivity();
if (activity == null) {
return;
}

activity.mErrorDialogHandler.showError(errorMessage);
}

@Override
public void onPaymentSessionDataChanged(@NonNull PaymentSessionData data) {
final PaymentSessionActivity activity = getListenerActivity();
if (activity == null) {
return;
}

activity.onPaymentSessionDataChanged(data);
}
}
}
Expand Up @@ -19,9 +19,9 @@
*/
public class AsyncTaskTokenController {

@NonNull private final Context mContext;
@NonNull private final Stripe mStripe;
@NonNull private final ErrorDialogHandler mErrorDialogHandler;
@NonNull private ListViewController mOutputListController;
@NonNull private final ListViewController mOutputListController;
@NonNull private final ProgressDialogController mProgressDialogController;

@Nullable private CardInputWidget mCardInputWidget;
Expand All @@ -34,7 +34,7 @@ public AsyncTaskTokenController(
@NonNull ListViewController outputListController,
@NonNull ProgressDialogController progressDialogController) {
mCardInputWidget = cardInputWidget;
mContext = context;
mStripe = new Stripe(context);
mErrorDialogHandler = errorDialogHandler;
mProgressDialogController = progressDialogController;
mOutputListController = outputListController;
Expand All @@ -52,21 +52,21 @@ public void detach() {
}

private void saveCard() {
Card cardToSave = mCardInputWidget.getCard();
final Card cardToSave = mCardInputWidget.getCard();
if (cardToSave == null) {
mErrorDialogHandler.showError("Invalid Card Data");
return;
}
mProgressDialogController.startProgress();
new Stripe(mContext).createToken(
mStripe.createToken(
cardToSave,
PaymentConfiguration.getInstance().getPublishableKey(),
new TokenCallback() {
public void onSuccess(Token token) {
public void onSuccess(@NonNull Token token) {
mOutputListController.addToList(token);
mProgressDialogController.finishProgress();
}
public void onError(Exception error) {
public void onError(@NonNull Exception error) {
mErrorDialogHandler.showError(error.getLocalizedMessage());
mProgressDialogController.finishProgress();
}
Expand Down
130 changes: 81 additions & 49 deletions samplestore/src/main/java/com/stripe/samplestore/PaymentActivity.java
Expand Up @@ -294,7 +294,9 @@ private void proceedWithPurchaseIf3DSCheckIsNotNecessary(Source source, String c
}
}

private Map<String, Object> createParams(long price, String sourceId, String customerId, ShippingInformation shippingInformation){
@NonNull
private Map<String, Object> createParams(long price, String sourceId, String customerId,
ShippingInformation shippingInformation) {
Map<String, Object> params = new HashMap<>();
params.put("amount", Long.toString(price));
params.put("source", sourceId);
Expand Down Expand Up @@ -372,40 +374,58 @@ private void finishCharge() {

private void setupPaymentSession() {
mPaymentSession = new PaymentSession(this);
mPaymentSession.init(new PaymentSession.PaymentSessionListener() {
@Override
public void onCommunicatingStateChanged(boolean isCommunicating) {
if (isCommunicating) {
mProgressDialogFragment.show(getSupportFragmentManager(), "progress");
} else {
mProgressDialogFragment.dismiss();
}
}
mPaymentSession.init(new PaymentSessionListenerImpl(this),
new PaymentSessionConfig.Builder().build());
}

@Override
public void onError(int errorCode, @Nullable String errorMessage) {
displayError(errorMessage);
}
private String formatSourceDescription(Source source) {
if (Source.CARD.equals(source.getType())) {
final SourceCardData sourceCardData = (SourceCardData) source.getSourceTypeModel();
return sourceCardData.getBrand() + getString(R.string.ending_in) +
sourceCardData.getLast4();
}
return source.getType();
}

@Override
public void onPaymentSessionDataChanged(@NonNull PaymentSessionData data) {
if (data.getShippingMethod() != null) {
mEnterShippingInfo.setText(data.getShippingMethod().getLabel());
mShippingCosts = data.getShippingMethod().getAmount();
addCartItems();
updateConfirmPaymentButton();
}
@NonNull
private ArrayList<ShippingMethod> getValidShippingMethods(@NonNull ShippingInformation shippingInformation) {
ArrayList<ShippingMethod> shippingMethods = new ArrayList<>();
shippingMethods.add(new ShippingMethod("UPS Ground", "ups-ground", "Arrives in 3-5 days", 0, "USD"));
shippingMethods.add(new ShippingMethod("FedEx", "fedex", "Arrives tomorrow", 599, "USD"));
if (shippingInformation.getAddress() != null &&
shippingInformation.getAddress().getPostalCode().equals("94110")) {
shippingMethods.add(new ShippingMethod("1 Hour Courier", "courier", "Arrives in the next hour", 1099, "USD"));
}
return shippingMethods;
}

private void onCommunicatingStateChanged(boolean isCommunicating) {
if (isCommunicating) {
mProgressDialogFragment.show(getSupportFragmentManager(), "progress");
} else {
mProgressDialogFragment.dismiss();
}
}

if (data.getSelectedPaymentMethodId() != null) {
CustomerSession.getInstance().retrieveCurrentCustomer(new CustomerSession.CustomerRetrievalListener() {
private void onPaymentSessionDataChanged(@NonNull PaymentSessionData data) {
if (data.getShippingMethod() != null) {
mEnterShippingInfo.setText(data.getShippingMethod().getLabel());
mShippingCosts = data.getShippingMethod().getAmount();
addCartItems();
updateConfirmPaymentButton();
}

if (data.getSelectedPaymentMethodId() != null) {
CustomerSession.getInstance().retrieveCurrentCustomer(
new CustomerSession.CustomerRetrievalListener() {
@Override
public void onCustomerRetrieved(@NonNull Customer customer) {
String sourceId = customer.getDefaultSource();
final String sourceId = customer.getDefaultSource();
if (sourceId == null) {
displayError("No payment method selected");
return;
}
CustomerSource source = customer.getSourceById(sourceId);
final CustomerSource source = customer.getSourceById(sourceId);
mEnterPaymentInfo.setText(formatSourceDescription(source.asSource()));
}

Expand All @@ -415,35 +435,47 @@ public void onError(int httpCode, @Nullable String errorMessage,
displayError(errorMessage);
}
});
}
}

if (data.isPaymentReadyToCharge()) {
mConfirmPaymentButton.setEnabled(true);
}
if (data.isPaymentReadyToCharge()) {
mConfirmPaymentButton.setEnabled(true);
}
}

private static final class PaymentSessionListenerImpl
extends PaymentSession.ActivityPaymentSessionListener<PaymentActivity> {
private PaymentSessionListenerImpl(@NonNull PaymentActivity activity) {
super(activity);
}

@Override
public void onCommunicatingStateChanged(boolean isCommunicating) {
final PaymentActivity activity = getListenerActivity();
if (activity == null) {
return;
}
}, new PaymentSessionConfig.Builder().build());
}

private String formatSourceDescription(Source source) {
if (Source.CARD.equals(source.getType())) {
final SourceCardData sourceCardData = (SourceCardData) source.getSourceTypeModel();
return sourceCardData.getBrand() + getString(R.string.ending_in) +
sourceCardData.getLast4();
activity.onCommunicatingStateChanged(isCommunicating);
}
return source.getType();
}

@NonNull
private ArrayList<ShippingMethod> getValidShippingMethods(@NonNull ShippingInformation shippingInformation) {
ArrayList<ShippingMethod> shippingMethods = new ArrayList<>();
shippingMethods.add(new ShippingMethod("UPS Ground", "ups-ground", "Arrives in 3-5 days", 0, "USD"));
shippingMethods.add(new ShippingMethod("FedEx", "fedex", "Arrives tomorrow", 599, "USD"));
if (shippingInformation.getAddress() != null &&
shippingInformation.getAddress().getPostalCode().equals("94110")) {
shippingMethods.add(new ShippingMethod("1 Hour Courier", "courier", "Arrives in the next hour", 1099, "USD"));
@Override
public void onError(int errorCode, @Nullable String errorMessage) {
final PaymentActivity activity = getListenerActivity();
if (activity == null) {
return;
}

activity.displayError(errorMessage);
}
return shippingMethods;
}

@Override
public void onPaymentSessionDataChanged(@NonNull PaymentSessionData data) {
final PaymentActivity activity = getListenerActivity();
if (activity == null) {
return;
}

activity.onPaymentSessionDataChanged(data);
}
}
}

0 comments on commit 7ca4cde

Please sign in to comment.