Permalink
| package com.stripe.android.view; | |
| import android.content.Context; | |
| import android.content.Intent; | |
| import android.os.Bundle; | |
| import android.support.annotation.NonNull; | |
| import android.support.annotation.Nullable; | |
| import android.support.annotation.VisibleForTesting; | |
| import android.widget.FrameLayout; | |
| import com.stripe.android.CustomerSession; | |
| import com.stripe.android.PaymentConfiguration; | |
| import com.stripe.android.R; | |
| import com.stripe.android.SourceCallback; | |
| import com.stripe.android.Stripe; | |
| import com.stripe.android.model.Card; | |
| import com.stripe.android.model.Source; | |
| import com.stripe.android.model.SourceParams; | |
| import com.stripe.android.model.StripePaymentSource; | |
| import static com.stripe.android.PaymentSession.EXTRA_PAYMENT_SESSION_ACTIVE; | |
| import static com.stripe.android.PaymentSession.TOKEN_PAYMENT_SESSION; | |
| /** | |
| * Activity used to display a {@link CardMultilineWidget} and receive the resulting | |
| * {@link Source} in the {@link #onActivityResult(int, int, Intent)} of the launching activity. | |
| */ | |
| public class AddSourceActivity extends StripeActivity { | |
| public static final String EXTRA_NEW_SOURCE = "new_source"; | |
| static final String ADD_SOURCE_ACTIVITY = "AddSourceActivity"; | |
| static final String EXTRA_SHOW_ZIP = "show_zip"; | |
| static final String EXTRA_PROXY_DELAY = "proxy_delay"; | |
| static final String EXTRA_UPDATE_CUSTOMER = "update_customer"; | |
| CardMultilineWidget mCardMultilineWidget; | |
| CustomerSessionProxy mCustomerSessionProxy; | |
| FrameLayout mErrorLayout; | |
| StripeProvider mStripeProvider; | |
| private boolean mStartedFromPaymentSession; | |
| private boolean mUpdatesCustomer; | |
| /** | |
| * Create an {@link Intent} to start a {@link AddSourceActivity}. | |
| * | |
| * @param context the {@link Context} used to launch the activity | |
| * @param requirePostalField {@code true} to require a postal code field | |
| * @param updatesCustomer {@code true} if the activity should update using an | |
| * already-initialized {@link CustomerSession}, or {@code false} if it should just | |
| * return a source. | |
| * @return an {@link Intent} that can be used to start this activity | |
| */ | |
| public static Intent newIntent(@NonNull Context context, | |
| boolean requirePostalField, | |
| boolean updatesCustomer) { | |
| Intent intent = new Intent(context, AddSourceActivity.class); | |
| intent.putExtra(EXTRA_SHOW_ZIP, requirePostalField); | |
| intent.putExtra(EXTRA_UPDATE_CUSTOMER, updatesCustomer); | |
| return intent; | |
| } | |
| @Override | |
| protected void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| mViewStub.setLayoutResource(R.layout.activity_add_source); | |
| mViewStub.inflate(); | |
| mCardMultilineWidget = findViewById(R.id.add_source_card_entry_widget); | |
| mErrorLayout = findViewById(R.id.add_source_error_container); | |
| boolean showZip = getIntent().getBooleanExtra(EXTRA_SHOW_ZIP, false); | |
| mUpdatesCustomer = getIntent().getBooleanExtra(EXTRA_UPDATE_CUSTOMER, false); | |
| mStartedFromPaymentSession = | |
| getIntent().getBooleanExtra(EXTRA_PAYMENT_SESSION_ACTIVE, true); | |
| mCardMultilineWidget.setShouldShowPostalCode(showZip); | |
| if (mUpdatesCustomer && !getIntent().getBooleanExtra(EXTRA_PROXY_DELAY, false)) { | |
| initCustomerSessionTokens(); | |
| } | |
| setTitle(R.string.title_add_a_card); | |
| } | |
| @VisibleForTesting | |
| void initCustomerSessionTokens() { | |
| logToCustomerSessionIf(ADD_SOURCE_ACTIVITY, mUpdatesCustomer); | |
| logToCustomerSessionIf(TOKEN_PAYMENT_SESSION, mStartedFromPaymentSession); | |
| } | |
| @Override | |
| protected void onActionSave() { | |
| Card card = mCardMultilineWidget.getCard(); | |
| if (card == null) { | |
| // In this case, the error will be displayed on the card widget itself. | |
| return; | |
| } | |
| card.addLoggingToken(ADD_SOURCE_ACTIVITY); | |
| Stripe stripe = getStripe(); | |
| stripe.setDefaultPublishableKey(PaymentConfiguration.getInstance().getPublishableKey()); | |
| SourceParams sourceParams = SourceParams.createCardParams(card); | |
| setCommunicatingProgress(true); | |
| stripe.createSource(sourceParams, new SourceCallback() { | |
| @Override | |
| public void onError(Exception error) { | |
| setCommunicatingProgress(false); | |
| // This error is independent of the CustomerSession, so | |
| // we have to surface it here. | |
| showError(error.getLocalizedMessage()); | |
| } | |
| @Override | |
| public void onSuccess(Source source) { | |
| if (mUpdatesCustomer) { | |
| attachCardToCustomer(source); | |
| } else { | |
| finishWithSource(source); | |
| } | |
| } | |
| }); | |
| } | |
| private void attachCardToCustomer(StripePaymentSource source) { | |
| CustomerSession.SourceRetrievalListener listener = | |
| new CustomerSession.SourceRetrievalListener() { | |
| @Override | |
| public void onSourceRetrieved(@NonNull Source source) { | |
| finishWithSource(source); | |
| } | |
| @Override | |
| public void onError(int errorCode, @Nullable String errorMessage) { | |
| // No need to show this error, because it will be broadcast | |
| // from the CustomerSession | |
| setCommunicatingProgress(false); | |
| } | |
| }; | |
| if (mCustomerSessionProxy == null) { | |
| @Source.SourceType String sourceType; | |
| if (source instanceof Source) { | |
| sourceType = ((Source) source).getType(); | |
| } else if (source instanceof Card){ | |
| sourceType = Source.CARD; | |
| } else { | |
| // This isn't possible from this activity. | |
| sourceType = Source.UNKNOWN; | |
| } | |
| CustomerSession.getInstance().addCustomerSource( | |
| this, | |
| source.getId(), | |
| sourceType, | |
| listener); | |
| } else { | |
| mCustomerSessionProxy.addCustomerSource(source.getId(), listener); | |
| } | |
| } | |
| private void logToCustomerSessionIf(@NonNull String logToken, boolean condition) { | |
| if (mCustomerSessionProxy != null) { | |
| logToProxyIf(logToken, condition); | |
| return; | |
| } | |
| if (condition) { | |
| CustomerSession.getInstance().addProductUsageTokenIfValid(logToken); | |
| } | |
| } | |
| private void logToProxyIf(@NonNull String logToken, boolean condition) { | |
| if (mCustomerSessionProxy != null && condition) { | |
| mCustomerSessionProxy.addProductUsageTokenIfValid(logToken); | |
| } | |
| } | |
| private void finishWithSource(@NonNull Source source) { | |
| setCommunicatingProgress(false); | |
| Intent intent = new Intent(); | |
| intent.putExtra(EXTRA_NEW_SOURCE, source.toString()); | |
| setResult(RESULT_OK, intent); | |
| finish(); | |
| } | |
| private Stripe getStripe() { | |
| if (mStripeProvider == null) { | |
| return new Stripe(this); | |
| } else { | |
| return mStripeProvider.getStripe(this); | |
| } | |
| } | |
| @Override | |
| protected void setCommunicatingProgress(boolean communicating) { | |
| super.setCommunicatingProgress(communicating); | |
| if (mCardMultilineWidget != null) { | |
| mCardMultilineWidget.setEnabled(!communicating); | |
| } | |
| } | |
| @VisibleForTesting | |
| void setCustomerSessionProxy(CustomerSessionProxy proxy) { | |
| mCustomerSessionProxy = proxy; | |
| } | |
| @VisibleForTesting | |
| void setStripeProvider(@NonNull StripeProvider stripeProvider) { | |
| mStripeProvider = stripeProvider; | |
| } | |
| interface StripeProvider { | |
| Stripe getStripe(@NonNull Context context); | |
| } | |
| interface CustomerSessionProxy { | |
| void addProductUsageTokenIfValid(String token); | |
| void addCustomerSource(String sourceId, CustomerSession.SourceRetrievalListener listener); | |
| } | |
| } |