/* * Copyright (C) 2016 Payworks GmbH (http://www.payworks.com) * * The MIT License (MIT) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package io.mpos.ui.shared; import android.content.Context; import android.content.Intent; import android.text.TextUtils; import io.mpos.Mpos; import io.mpos.errors.MposError; import io.mpos.provider.ProviderMode; import io.mpos.transactionprovider.TransactionProcessDetails; import io.mpos.transactionprovider.TransactionProvider; import io.mpos.transactionprovider.processparameters.TransactionProcessParameters; import io.mpos.transactions.CardDetails; import io.mpos.transactions.Transaction; import io.mpos.transactions.parameters.TransactionParameters; import io.mpos.ui.BuildConfig; import io.mpos.ui.acquirer.ApplicationName; import io.mpos.ui.acquirer.MposUiAccountManager; import io.mpos.ui.acquirer.view.LoginActivity; import io.mpos.ui.acquirer.view.SettingsActivity; import io.mpos.ui.paybutton.controller.StatefulReadCardProcessProxy; import io.mpos.ui.paybutton.controller.StatefulTransactionProviderProxy; import io.mpos.ui.paybutton.view.ReadCardActivity; import io.mpos.ui.paybutton.view.TransactionActivity; import io.mpos.ui.printbutton.view.PrintReceiptActivity; import io.mpos.ui.shared.model.MposUiConfiguration; import io.mpos.ui.shared.util.ErrorHolder; import io.mpos.ui.summarybutton.view.TransactionSummaryActivity; /** * Entry point for the Payworks SDK and paybutton UI. * <p/> * Used to create intents to start activities for: * <ul> * <li>creating a charge/refund transaction,</li> * <li>showing a summary of a transaction,</li> * <li>printing a receipt of a transaction.</li> * </ul> * <p/> * Can be also used for getting the information about the last processed transaction. * <p/> * Implemented as a singleton, make sure to initialize it using {@link #initialize(android.content.Context, io.mpos.provider.ProviderMode, String, String)}. */ public final class MposUi { public static final int REQUEST_CODE_PAYMENT = 1001; public static final int REQUEST_CODE_PRINT_RECEIPT = 1003; public static final int REQUEST_CODE_SHOW_SUMMARY = 1005; public static final int REQUEST_CODE_LOGIN = 1007; public static final int REQUEST_CODE_SETTINGS = 1009; public static final int REQUEST_CODE_READ_CARD = 1011; public static final int RESULT_CODE_APPROVED = 2001; public static final int RESULT_CODE_FAILED = 2004; public static final int RESULT_CODE_PRINT_SUCCESS = 3001; public static final int RESULT_CODE_PRINT_FAILED = 3004; public static final int RESULT_CODE_SUMMARY_CLOSED = 4001; public static final int RESULT_CODE_LOGIN_SUCCESS = 5001; public static final int RESULT_CODE_LOGIN_FAILED = 5002; public static final int RESULT_CODE_SETTINGS_CLOSED = 6001; public static final int RESULT_CODE_READ_CARD_SUCCESS = 7001; public static final int RESULT_CODE_READ_CARD_FAILED = 7002; public static final String RESULT_EXTRA_TRANSACTION_IDENTIFIER = "io.mpos.ui.shared.MposUiController.TRANSACTION_IDENTIFIER"; private static MposUi INSTANCE; private Context mContext; private TransactionProvider mTransactionProvider; private MposUiMode mMposUiMode = MposUiMode.PROVIDER; private MposUiAccountManager mMposUiAccountManager; private enum MposUiMode { PROVIDER, ACQUIRER } private MposUiConfiguration mConfiguration = new MposUiConfiguration(); /** * Initialization method for this singleton class. * * @param context Android context of your application. * @param mode Enum value specifying which backend environment to use. * @param merchantIdentifier Identifier of the merchant which should be used for transactions. * @param merchantSecret Secret (authentication token) of the merchant which should be used for transactions. * @return Initialized singleton object. */ public static MposUi initialize(Context context, ProviderMode mode, String merchantIdentifier, String merchantSecret) { INSTANCE = new MposUi(context.getApplicationContext(), mode, merchantIdentifier, merchantSecret); return INSTANCE; } /** * Initialization method for this singleton class. * * @param context Android context of your application. * @param providerMode Enum value specifying which backend environment to use. * @param applicationName Enum value specifying which Application to use. * @param integratorIdentifier Identifier of the integrator. * @return Initialized singleton object. */ public static MposUi initialize(Context context, ProviderMode providerMode, ApplicationName applicationName, String integratorIdentifier) { INSTANCE = new MposUi(context.getApplicationContext(), providerMode, applicationName, integratorIdentifier); return INSTANCE; } /** * Gets the singleton instance of this class. * * @return Initialized MposUi object. */ public static MposUi getInitializedInstance() { return INSTANCE; } /** * Gets the SDK and MposUi version you are using. * * @return Version code. */ public static String getVersion() { return BuildConfig.VERSION_NAME; } /** * Gets the configuration holder for the MposUi. * * @return Configuration holder. */ public MposUiConfiguration getConfiguration() { return mConfiguration; } /** * Sets the configuration for the MposUi. * * @param configuration Configuration holder. */ public void setConfiguration(MposUiConfiguration configuration) { mConfiguration = configuration; } /** * Returns if a transaction is ongoing. * * @return Whether is transaction ongoing. */ public boolean isTransactionOngoing() { return StatefulTransactionProviderProxy.getInstance().isTransactionOnGoing(); } /** * Returns the current transaction which is ongoing or finished in the MposUi. * * @return The transaction object. */ public Transaction getTransaction() { return StatefulTransactionProviderProxy.getInstance().getCurrentTransaction(); } /** * Returns the current transaction process which is ongoing or finished in the MposUi. * * @return The transaction process object. */ public TransactionProcessDetails getTransactionProcessDetails() { return StatefulTransactionProviderProxy.getInstance().getLastTransactionProcessDetails(); } /** * Returns the latest error which might have occurred in the MposUi. * * @return The last error object. */ public MposError getError() { return ErrorHolder.getInstance().getError(); } /** * Returns the card details if the read card process was successful. * * @return the card details of the last read card process. */ public CardDetails getCardDetails() { return StatefulReadCardProcessProxy.getInstance().getCardDetails(); } /** * Creates an intent for a new transaction from a session identifier * (this identifier is created after registering the transaction on the backend). * <p/> * You should use the returned intent with {@code startActivityForResult()} using request code {@link #REQUEST_CODE_PAYMENT}. * The result code will be either {@link #RESULT_CODE_APPROVED} if the transaction was successfully processed and approved * or {@link #RESULT_CODE_FAILED} otherwise. The identifier of the transaction can be retrieved from the resulting intent * using {@link #RESULT_EXTRA_TRANSACTION_IDENTIFIER} key. * * @param sessionIdentifier The session identifier which should be used for the transaction. * @return The intent which can be used to start a new activity. */ public Intent createTransactionIntent(String sessionIdentifier) { Intent intent = new Intent(mContext, TransactionActivity.class); if (mMposUiMode == MposUiMode.ACQUIRER) { intent.putExtra(TransactionActivity.BUNDLE_EXTRA_ACQUIRER_LOGIN, true); intent.putExtra(TransactionActivity.BUNDLE_EXTRA_ACQUIRER_APPLICATION_ID, mMposUiAccountManager.getApplicationData().getIdentifier()); } intent.putExtra(TransactionActivity.BUNDLE_EXTRA_SESSION_IDENTIFIER, sessionIdentifier); return intent; } /** * Creates an intent for a new transaction from a session identifier * (this identifier is created after registering the transaction on the backend). * Using {@param transactionProcessParameters} you can set additional parameters for the process, e.g. additional steps for the process like asking for tip. * <p/> * You should use the returned intent with {@code startActivityForResult()} using request code {@link #REQUEST_CODE_PAYMENT}. * The result code will be either {@link #RESULT_CODE_APPROVED} if the transaction was successfully processed and approved * or {@link #RESULT_CODE_FAILED} otherwise. The identifier of the transaction can be retrieved from the resulting intent * using {@link #RESULT_EXTRA_TRANSACTION_IDENTIFIER} key. * * @param sessionIdentifier The session identifier which should be used for the transaction. * @return The intent which can be used to start a new activity. */ public Intent createTransactionIntent(String sessionIdentifier, TransactionProcessParameters transactionProcessParameters) { Intent intent = new Intent(mContext, TransactionActivity.class); if (mMposUiMode == MposUiMode.ACQUIRER) { intent.putExtra(TransactionActivity.BUNDLE_EXTRA_ACQUIRER_LOGIN, true); intent.putExtra(TransactionActivity.BUNDLE_EXTRA_ACQUIRER_APPLICATION_ID, mMposUiAccountManager.getApplicationData().getIdentifier()); } intent.putExtra(TransactionActivity.BUNDLE_EXTRA_SESSION_IDENTIFIER, sessionIdentifier); intent.putExtra(TransactionActivity.BUNDLE_EXTRA_TRANSACTION_PROCESS_PARAMETERS, transactionProcessParameters); return intent; } /** * Creates an intent for a new transaction from the supplied transaction parameters * <p/> * You should use the returned intent with {@code startActivityForResult()} using request code {@link #REQUEST_CODE_PAYMENT}. * The result code will be either {@link #RESULT_CODE_APPROVED} if the transaction was successfully processed and approved * or {@link #RESULT_CODE_FAILED} otherwise. The identifier of the transaction can be retrieved from the resulting intent * using {@link #RESULT_EXTRA_TRANSACTION_IDENTIFIER} key. * * @param transactionParameters Transaction parameters for the transaction. * @return The intent which can be used to start a new activity. */ public Intent createTransactionIntent(TransactionParameters transactionParameters) { Intent intent = new Intent(mContext, TransactionActivity.class); if (mMposUiMode == MposUiMode.ACQUIRER) { intent.putExtra(TransactionActivity.BUNDLE_EXTRA_ACQUIRER_LOGIN, true); intent.putExtra(TransactionActivity.BUNDLE_EXTRA_ACQUIRER_APPLICATION_ID, mMposUiAccountManager.getApplicationData().getIdentifier()); } intent.putExtra(TransactionActivity.BUNDLE_EXTRA_TRANSACTION_PARAMETERS, transactionParameters); return intent; } /** * Creates an intent for a new transaction from the supplied transaction parameters. * Using {@param transactionProcessParameters} you can set additional parameters for the process, e.g. additional steps for the process like asking for tip. * <p/> * You should use the returned intent with {@code startActivityForResult()} using request code {@link #REQUEST_CODE_PAYMENT}. * The result code will be either {@link #RESULT_CODE_APPROVED} if the transaction was successfully processed and approved * or {@link #RESULT_CODE_FAILED} otherwise. The identifier of the transaction can be retrieved from the resulting intent * using {@link #RESULT_EXTRA_TRANSACTION_IDENTIFIER} key. * * @param transactionParameters Transaction parameters for the transaction. * @param transactionProcessParameters Transaction process parameters for the transaction process. * @return The intent which can be used to start a new activity. * @since 2.7.0 */ public Intent createTransactionIntent(TransactionParameters transactionParameters, TransactionProcessParameters transactionProcessParameters) { Intent intent = new Intent(mContext, TransactionActivity.class); if (mMposUiMode == MposUiMode.ACQUIRER) { intent.putExtra(TransactionActivity.BUNDLE_EXTRA_ACQUIRER_LOGIN, true); intent.putExtra(TransactionActivity.BUNDLE_EXTRA_ACQUIRER_APPLICATION_ID, mMposUiAccountManager.getApplicationData().getIdentifier()); } intent.putExtra(TransactionActivity.BUNDLE_EXTRA_TRANSACTION_PARAMETERS, transactionParameters); intent.putExtra(TransactionActivity.BUNDLE_EXTRA_TRANSACTION_PROCESS_PARAMETERS, transactionProcessParameters); return intent; } /** * Creates an intent for showing the summary screen of a transaction. * <p/> * You should use the returned intent with {@code startActivity()} or {@code startActivityForResult()} using request code {@link #REQUEST_CODE_SHOW_SUMMARY} * if you want to be notified when the transaction summary screen is closed. The result code will always be {@link #RESULT_CODE_SUMMARY_CLOSED}. * * @param transactionIdentifier The identifier of the transaction to show the summary. * @return The intent which can be used to start a new activity. */ public Intent createTransactionSummaryIntent(String transactionIdentifier) { Intent intent = new Intent(mContext, TransactionSummaryActivity.class); if (mMposUiMode == MposUiMode.ACQUIRER) { intent.putExtra(TransactionSummaryActivity.BUNDLE_EXTRA_ACQUIRER_LOGIN, true); intent.putExtra(TransactionSummaryActivity.BUNDLE_EXTRA_ACQUIRER_APPLICATION_ID, mMposUiAccountManager.getApplicationData().getIdentifier()); } intent.putExtra(TransactionSummaryActivity.BUNDLE_EXTRA_TRANSACTION_IDENTIFIER, transactionIdentifier); return intent; } /** * Creates an intent for reading a card. * <p/> * You should use the returned intent with {{@code startActivityForResult()} using request code {@link #REQUEST_CODE_READ_CARD} * The result code will be either {@link #RESULT_CODE_READ_CARD_SUCCESS} if the card reading was successful * or {@link #RESULT_CODE_READ_CARD_FAILED} if it was aborted/ failed. * <p/> * The card details can be accessed from {@link #getCardDetails()} */ public Intent createReadCardIntent() { Intent intent = new Intent(mContext, ReadCardActivity.class); if (mMposUiMode == MposUiMode.ACQUIRER) { intent.putExtra(ReadCardActivity.BUNDLE_EXTRA_ACQUIRER_LOGIN, true); intent.putExtra(ReadCardActivity.BUNDLE_EXTRA_ACQUIRER_APPLICATION_ID, mMposUiAccountManager.getApplicationData().getIdentifier()); } return intent; } /** * Creates an intent for printing a receipt of a transaction. * <p/> * Use only when MposUi is initialized with an Application. * You should use the returned intent with {@code startActivityForResult()} using request code {@link #REQUEST_CODE_PRINT_RECEIPT}. * The result code will be either {@link #RESULT_CODE_PRINT_SUCCESS} if the receipt data was successfully sent to the printer * or {@link #RESULT_CODE_PRINT_FAILED} otherwise. * * @param transactionIdentifier The transaction identifier for the receipt to be printed. * @return The intent which can be used to start a new activity. */ public Intent createPrintReceiptIntent(String transactionIdentifier) { Intent intent = new Intent(mContext, PrintReceiptActivity.class); if (mMposUiMode == MposUiMode.ACQUIRER) { intent.putExtra(PrintReceiptActivity.BUNDLE_EXTRA_ACQUIRER_LOGIN, true); intent.putExtra(PrintReceiptActivity.BUNDLE_EXTRA_ACQUIRER_APPLICATION_ID, mMposUiAccountManager.getApplicationData().getIdentifier()); } intent.putExtra(PrintReceiptActivity.BUNDLE_EXTRA_TRANSACTION_IDENTIFIER, transactionIdentifier); return intent; } /** * Creates an intent for the login screen * <p/> * Use only when MposUi is initialized with an Application. * The user is logged out forcefully before showing the login screen * <p/> * You should use the returned intent with {@code startActivityForResult()} using request code {@link #REQUEST_CODE_LOGIN}. * The result code will be either {@link #RESULT_CODE_LOGIN_SUCCESS} if the login was successful or {@link #RESULT_CODE_LOGIN_FAILED} otherwise. * * @return The intent which can be used to start a new activity. * @throws IllegalStateException if the MposUi in not initialized with an Application */ public Intent createLoginIntent() throws IllegalStateException { if (mMposUiMode != MposUiMode.ACQUIRER) { throwExceptionForWrongMode(MposUiMode.ACQUIRER); } // Forcing login mMposUiAccountManager.logout(false); Intent intent = new Intent(mContext, LoginActivity.class); intent.putExtra(LoginActivity.BUNDLE_EXTRA_ACQUIRER_APPLICATION_ID, mMposUiAccountManager.getApplicationData().getIdentifier()); return intent; } /** * Creates an intent for the settings screen * <p/> * Use only when MposUi is initialized with an Application. * You should use the returned intent with {@code startActivity()} or {@code startActivityForResult()} using request code {@link #REQUEST_CODE_SETTINGS} * if you want to be notified when the settings screen is closed. The result code will always be {@link #RESULT_CODE_SETTINGS_CLOSED}. * * @return The intent which can be used to start a new activity. * @throws IllegalStateException if the MposUi in not initialized with an Application */ public Intent createSettingsIntent() throws IllegalStateException { if (mMposUiMode != MposUiMode.ACQUIRER) { throwExceptionForWrongMode(MposUiMode.ACQUIRER); } Intent intent = new Intent(mContext, SettingsActivity.class); intent.putExtra(SettingsActivity.BUNDLE_EXTRA_ACQUIRER_APPLICATION_ID, mMposUiAccountManager.getApplicationData().getIdentifier()); return intent; } /** * Logs the user out of the application. * Use only when MposUi is initialized with an Application. * * @throws IllegalStateException if the MposUi in not initialized with an application */ public void logout() throws IllegalStateException { if (mMposUiMode != MposUiMode.ACQUIRER) { throwExceptionForWrongMode(MposUiMode.ACQUIRER); } mMposUiAccountManager.logout(false); } /** * Checks if the user is logged in with the Application. * Use only when MposUi is initialized with an Application. * * @return boolean indicating whether logged in or not. * @throws IllegalStateException if the MposUi in not initialized with an Application */ public boolean isLoggedIn() throws IllegalStateException { if (mMposUiMode != MposUiMode.ACQUIRER) { throwExceptionForWrongMode(MposUiMode.ACQUIRER); } return mMposUiAccountManager.isLoggedIn(); } /** * Returns the transaction provider used for the previous transaction. * Returns null if the transaction hasn't been processed before. * * @return TransactionProvider */ public TransactionProvider getTransactionProvider() { if (mMposUiMode == MposUiMode.PROVIDER) { return mTransactionProvider; } else { return mMposUiAccountManager.getTransactionProvider(); } } private MposUi(Context context, ProviderMode providerMode, String merchantIdentifier, String merchantSecret) { mContext = context; mTransactionProvider = Mpos.createTransactionProvider(context, providerMode, merchantIdentifier, merchantSecret); mMposUiMode = MposUiMode.PROVIDER; } private MposUi(Context context, ProviderMode providerMode, ApplicationName applicationName, String integratorIdentifier) { if (TextUtils.isEmpty(integratorIdentifier)) { throw new IllegalArgumentException("Integrator Identifier cannot be null / empty."); } mMposUiMode = MposUiMode.ACQUIRER; mContext = context; mMposUiAccountManager = MposUiAccountManager.initialize(context, providerMode, applicationName, integratorIdentifier); mConfiguration = mMposUiAccountManager.getApplicationData().getMposUiConfiguration(); if (mMposUiAccountManager.isLoggedIn()) { mTransactionProvider = mMposUiAccountManager.getTransactionProvider(); } } private void throwExceptionForWrongMode(MposUiMode mode) throws IllegalStateException { if (mode == MposUiMode.ACQUIRER) { throw new IllegalStateException("MposUi needs to be initialized with an Application to use this method"); } else { throw new IllegalStateException("MposUi needs to be initialized with a Provider to use this method"); } } }