Stripe - Android Framework

๐Ÿ“˜

UPDATE: As of February 14, 2024 a new version of the SDK is available. Documentation for the new version of the SDK (2.1.0) is available here.

Models

ECPDevice

PropertyTypeDescription
id_numberStringId (serial) number of device.
manufacturerStringManufacturer/brand of device.
modelStringModel of device.
battery_percentageStringBattery percentage of device between 0-100%.
readerTReader object specified by the processor

ECPPaymentParameters

NOTE: There are objects in the SDK for other processors, which are not yet supported.

PropertyTypeDescription
amountStringRequired. Amount to charge. Must be a positive number. Specify using the following format: "1234.50". Do not utilize commas (,), negative numbers, or more than 2 decimal points. The following formats will also be accepted, however we encourage consumers to specify the entire amount as listed above (i.e. "1234.50"):
"1234" for $1234.00
"1234.0" for $1234.00
"1234.5" for $1234.5
paymentDescriptionStringOptional. A string to be displayed on your customerโ€™s credit card statement. This may be up to 22 characters. The statement descriptor must contain at least one letter, may not include <>"' characters, and will appear on your customerโ€™s statement in capital letters. Non-ASCII characters are automatically stripped. While most banks and card issuers display this information consistently, some may display it incorrectly or not at all.
paymentDescriptionSuffixStringOptional. A string to specify details about the transaction so your customer can understand it clearly on their statement. The suffix is concatenated with the statementDescriptor, the * symbol, and a space to form the complete statement descriptor that your customer sees. Maximum 22 characters for the final concatenated descriptor.
currencyStringOptional. Default: "usd". Type of currency to be collected. Only USD supported at this time (default).
external_idStringOptional. <= 50 characters. Unique identifier for the payment in merchant or partner's system.
duplicate_checkStringWORLDPAY/EXPRESS ONLY - NOT SUPPORTED AT THIS TIME
Optional. Default:"enabled" Valid values: "enabled", "disabled". Indicates the duplicate check mode.
captureStringIDYNAMO ONLY - NOT SUPPORTED AT THIS TIME
Optional. Possible values: "completed_sale" "auth_until_capture" "tip_adjustment". 'completed_sale' (default) will authorize and capture the sale at the specified amount. 'auth_until_capture' requires the capture endpoint for the payment to be added to a settlement batch. 'tip_adjustment' allows for the tip_adjustment endpoint to be called up until just prior to the batch close time.
allow_partial_approvalsbooleanWORLDPAY/EXPRESS ONLY - NOT SUPPORTED AT THIS TIME
Optional. Default: FALSE. If true, allows partial approvals. Most useful for gift cards with limited funds.

ECPSaleResponse

PropertyTypeDescription
transaction_idStringUnique Id of transaction.
acqurier_messageStringAcquirer message returned. Do not base application logic on this message as it may change without notice.
authorization_codeStringAcquirer Authorization code.
approved_amountStringAmount approved.
batch_idIntegerSettlement batch id (card only). Value will be null for Stripe processed payments.
cardECPCardDataCard response
outcomeECPSaleOutcomeSale outcome
emvECPEmvDataEMV response data if present
entry_modeStringEntry mode of transaction

ECPSaleOutcome

PropertyTypeDescription
resultStringResult of transaction request. Valid values "success", "failed", "declined"
codeString4-digit PaySimple result code.
outcome_descriptionStringDescription of decline, failure, or success.

ECPCardData

PropertyTypeDescription
card_brandStringCard brand type.
last4StringLast 4 digits of card number.
card_holder_nameStringName of cardholder
expiration_monthintMonth of card expiration
expiration_yearintYear of card expiration in 4 digit format.

ECPEmvData

PropertyTypeDescription
application_identifierStringApplication Identifier.
application_preferred_nameStringApplication Preferred Name.
application_labelStringApplication Label. Value will be null for Stripe payments.
application_cryptogramStringCryptogram value.
authorization_response_codeStringAuthorization Response Code.
authorization_response_messageStringAuthorization Response Message.
is_pin_verifiedbooleanWhether or not the result is pin verified.

Client Token Interface

Authorization via client token is required to use this SDK. In this SDK, we have introduced the concept of a client token service. The client token service ensures the SDK is able to associate and authenticate with the proper merchant / client for each use.

Before integrating to our SDK, you should create an endpoint on your secure backend server which returns the proper PaySimple client token for a particular PaySimple user that you are trying to use the SDK with. How you map your application's users to a PaySimple user is up to you in your backend - you just need to be sure to get a proper PaySimple token tied to the user you would like to utilize the SDK for each time you initialize. The type of authorization token currently supported will be https://documentation.paysimple.com/v2019/docs/authorization#client-token-authorization-rarely-used .

Consumers will implement a client token interface to help out with client token authentication. This client token interface for the Shared ECP SDK is called ClientTokenProvider.

Consumers will create a class which implements ClientTokenProvider.

See below for the structure of ClientTokenProvider

ClientTokenProvider (Interface)

PropertyTypeDescription
void getClientToken(ClientTokenProviderCallback callback)Interface MethodMethod implemented by consumer to retrieve client token and pass result/error through the ClientTokenProviderCallback, so the ECP SDK can fetch client tokens and utilize them when needed.

When implemented correctly, getClientToken should retrieve the PaySimple client token you would like to use for a particular user from your secure backend.

If you successfully retrieve a client token, pass it back through the callback.onComplete method with a null error.

If you have an error retrieving a client token, pass back a null value for the token and a new ECPSdkCallbackError for the error in the callback.OnComplete method.

Implementation examples will be shown further below.

ClientTokenProviderCallback

PropertyTypeDescription
void onComplete(String clientToken, ECPSdkCallbackError error)Interface MethodCallback provided to utilize alongside getClientToken to inform the SDK of the client token and/or client token error.

Upon successful retrieval, call onComplete with a valid client token and a null error.

Upon an error during retrieval, call onComplete with a null client token and a new ECPSdkCallbackError.

Example Implementation

TokenService.java


import com.evercommerceandroid.evercommercepaymentsandroidsdk.clienttoken.ClientTokenProvider;
import com.evercommerceandroid.evercommercepaymentsandroidsdk.clienttoken.ClientTokenProviderCallback;
import com.evercommerceandroid.evercommercepaymentsandroidsdk.models.ECPSdkCallbackError;
// any other needed imports


public class TokenService implements ClientTokenProvider {


    public TokenService() {
    }
    @Override
    public void getClientToken(ClientTokenProviderCallback callback) {

        try {
            ClientTokenManager clientTokenManager = new ClientTokenManager();
            clientTokenManager.getAndOutputToken(new TokenManager.TokenResponseListener() {
                @Override
                public void onError(Error error) {
                    callback.onComplete(null, new ECPSdkCallbackError("Failed to fetch client token in TokenService"));
                }

                @Override
                public void onResponse(String token) {
                    callback.onComplete(token, null);
                }
            });

        }catch (Exception e) {
            callback.onComplete(null, new ECPSdkCallbackError("Failed to fetch client token. Exception caught."));
        }

    }

}

MainActivity.java (or anywhere that calls initializeSdk), make sure you are creating a new instance of your TokenService set up with any information that you need for determining the proper PaySimple user you should be fetching a client token for. Then pass the tokenService as part of the initialize SDK function, and we will utilize the token service to fetch client tokens when needed.

TokenService tokenService  = new TokenService();

_ecpSdk = SharedECPSdk.getInstance(StripeLandingActivity.this);

 HashSet<ECPEventType> subscribedEvents = new HashSet<ECPEventType>();

 subscribedEvents.add(ECPEventType.CONNECTION_CHANGED_EVENT);
 subscribedEvents.add(ECPEventType.DEVICE_BATTERY_EVENT);
 subscribedEvents.add(ECPEventType.DEVICE_CARD_EVENT);
 subscribedEvents.add(ECPEventType.DEVICE_MESSAGE_EVENT);
 subscribedEvents.add(ECPEventType.CONFIG_STATUS_EVENT);
 subscribedEvents.add(ECPEventType.CONFIG_PROGRESS_EVENT);

_ecpSdk.initializeSdk(StripeLandingActivity.this, environment, tokenService, subscribedEvents, this, new InitializeSdkCallback() {
             @Override
             public void onComplete(boolean isInitializeSdkSuccess, ECPSdkCallbackError errorResponse) {
												// code after initialize here
                    }
                });

โ—๏ธ

The Client Token interface getClientToken method you implement will be called by our SDK as needed during various actions which require PaySimple authorization.

ECPEventType (enum)

Event types to be used to help consumers specify which events they would like to listen to when calling Initialize SDK. The following values can be used for ECPEventType:
ALL
CONFIG_STATUS_EVENT
CONFIG_PROGRESS_EVENT**
CONNECTION_CHANGED_EVENT
DEVICE_BATTERY_EVENT
DEVICE_CARD_EVENT
DEVICE_MESSAGE_EVENT

These values are accessible when using our Shared ECP SDK. See sample code below:

HashSet<ECPEventType> subscribedEvents = new HashSet<ECPEventType>();
// use ECPEventType.ALL if you would like to subscribe to all events by default. 
// subscribedEvents.add(ECPEventType.ALL);
subscribedEvents.add(ECPEventType.CONNECTION_CHANGED_EVENT);
subscribedEvents.add(ECPEventType.DEVICE_BATTERY_EVENT);
subscribedEvents.add(ECPEventType.DEVICE_CARD_EVENT);
subscribedEvents.add(ECPEventType.DEVICE_MESSAGE_EVENT);
subscribedEvents.add(ECPEventType.CONFIG_STATUS_EVENT);
subscribedEvents.add(ECPEventType.CONFIG_PROGRESS_EVENT);

Class Methods

Shared Instance

Returns a shared instance of the ECPSdk service. If you would like, you can store this in a variable to later be accessed by your class.

public static synchronized ISharedECPSdk getInstance(Context context);

Example Implementation:

private ISharedECPSdk _ecpSdk;

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    		
        _ecpSdk = SharedECPSdk.getInstance(MyActivity.this);
    
    }

Instance Methods

๐Ÿšง

Important

As best practice, make sure the completion handler of one operation within the ECPSdk is called prior to attempting to execute an additional operation, to avoid unintended behavior. One exception to this may be using stopCurrentFlow to cancel a payment.

Initialize SDK

๐Ÿšง

No instance methods should be used until the SDK has been successfully initialized. One exception to this case may be checking Is Initialized if needed for your application's flow.

Initializes the SDK. Provides a callback to determine the result of the SDK initialization. Returns isInitializedSuccess = true and error = null if initialization occurred without error. Consumers must initialize the SDK prior to any other SDK actions. User must pass in context, environment, ClientTokenProvider, list of events they would like to subscribe to, ECPSdkListener, and an InitializeSdkCallback.

    void initializeSdk(Context context, 
                       ECPEnvironment environment, 
                       ClientTokenProvider clientTokenBlock, 
                       HashSet<ECPEventType> subscribedEvents, 
                       ECPSdkListener listener, InitializeSdkCallback callback);
PropertyTypeDescription
contextContextRequired. Android context.
environmentECPEnvironmentRequired. Environment to use. Possible values: "SBX" for sandbox or "PROD" for production
clientTokenBlockClientTokenProviderRequired. ClientTokenProvider which returns a PaySimple client token and an error so the SDK can hook into your client/merchant.
subscribedEventsHashSetSet of events consumer would like to listen to. If a null or empty set is passed in, by default user will subscribe to all events. ECPEventType.ALL will also subscribe to all events, if it is present in the HashSet. If you only want to listen to specific events, please specify those events using ECPEventType. For example, if you only wanted to listen to ECPDeviceMessageEvent and ECPConnectionChangedEvent, you would pass in a set as that has been initialized as follows:

HashSet subscribedEvents = new HashSet(); subscribedEvents.add(ECPEventType.DEVICE_MESSAGE_EVENT); subscribedEvents.add(ECPEventType.CONNECTION_CHANGED_EVENT);
listenerECPSdkListenerThis is the listener that will send events from the sdk to your application.
callbackInitializeSdkCallbackRequired. Upon execution passes back isSdkInitialized to provide information on the result of initialization. Also passes ECPSdkCallbackError reference to pass back error information in case of initialization issue.

Example Implementation:

public class StripeLandingActivity extends AppCompatActivity implements ECPSdkListener {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
  	
    ECPEnvironment environment = ECPEnvironment.PROD;
    HashSet<ECPEventType> subscribedEvents = new HashSet<ECPEventType>();
    subscribedEvents.add(ECPEventType.ALL);
    TokenService tokenService = new TokenService();
    
    _ecpSdk.initializeSdk(StripeLandingActivity.this, environment, tokenService, subscribedEvents, this, new InitializeSdkCallback() {
     
      @Override
      public void onComplete(boolean isInitializeSdkSuccess, ECPSdkCallbackError errorResponse) {
        // Handle callback
      }
    });
    
  }
  
}

Subscribe To Events

This adds an object to the list of listeners that will receive notifications of events from the ECPSdk. The object must implement the ECPSdkListener interface. This does not change the events that are sent by the ECPSdk (this is setup in the Initialization as outlined above). See the Delegates / Listeners / Events section below for more information on handling events.

void subscribeToEvents(ECPSdkListener ecpSdkListener, ECPCallback callback);
PropertyTypeDescription
ecpSdkListenerECPSdkListenerRequired. An object that implements the ECPSdkListener interface.
ecpCallbackECPCallbackRequired. Callback which indicates the subscribe to events process has finished. onComplete will be called and will return a boolean indicating whether the processes completed successfully. Also reports back an ECPSdkCallback error to pass back any error information that occurs during the subscribe to events process, so errors can be handled appropriately.

Example Implementation:

// somewhere in your class you have stored the sdk, accessing it via sharedECPSdk variable
// the class this is called from in this example implements ECPSdkListener.

_ecpSdk.subscribeToEvents(this, new ECPCallback() {
  @Override
  public void onComplete(boolean success, ECPSdkCallbackError error) {
    Log.i(TAG, "Subscribed to events: " + success);
  }
});

Unsubscribe From Events

This removes an object from the list of listeners that will receive notifications of events from the ECPSdk. The object must implement the ECPSdkListener interface.

void unsubscribeFromEvents(ECPSdkListener ecpSdkListener, ECPCallback ecpCallback);
PropertyTypeDescription
ecpSdkListenerECPSdkListenerRequired. An object that implements the ECPSdkListener interface.
ecpCallbackECPCallbackRequired. Callback which indicates the unsubscribe process has finished. onComplete will be called and will return a boolean indicating whether the unsubscribe processes completed successfully. Also reports back an ECPSdkCallback error to pass back any error information that occurs during the unsubscribe from events process, so errors can be handled appropriately.

Example Implementation:

// somewhere in your class you have stored the sdk, accessing it via sharedECPSdk variable
// the class this is called from in this example implements ECPSdkListener.

_ecpSdk.unsubscribeFromEvents(this, new ECPCallback() {
  @Override
  public void onComplete(boolean success, ECPSdkCallbackError error) {
    Log.i(TAG, "Unsubscribed from events: " + success);
  }
});

Is Initialized

Returns boolean to indicate if the SDK has been initialized.

boolean isInitialized();

Example Implementation:

// somewhere in your class you have stored the sdk, accessing it via sharedECPSdk variable

if (_ecpSdk.isInitialized()) {
	// Your logic here
}

Reset SDK

Clears out SDK data. Clears processor data, client token provider data, event subscriptions, any data that was setup in Initialize SDK. Disconnects device. Allows consumer to start fresh with a reset instance of the SDK to help with changing users, clearing config.

void resetSdk(ResetSdkCallback resetSdkCallback);
PropertyTypeDescription
resetSdkCallbackResetSdkCallbackRequired. Callback which indicates the reset process has finished. onComplete will be called and will return a boolean indicating whether the reset processes completed successfully. Also reports back an ECPSdkCallback error to pass back any error information that occurs during the reset process, so errors can be handled appropriately.

Example Implementation:

private void resetSdk(){
  _ecpSdk.resetSdk(new ResetSdkCallback() {
   
    @Override
    public void onComplete(boolean isReset, ECPSdkCallbackError error) {
      // handle callback
    }
  });
}

Discover Devices

Discovers devices powered on and within range of the Android device to be used with the SDK. Currently only officially supported for the Stripe M2 Reader Device. Note - battery percentage on the ECPDevice objects coming back from Discover Devices may appear as null. Battery percentage cannot reliably be reported on until a consumer connects to a device. If you have another brand of bluetooth reader turned on and in range, discover devices may show the device. However, only Stripe M2 will currently work with Connect Device.

โ—๏ธ

Mobile device settings warning (Stripe M2)

For the Stripe M2 Reader, users should not use the own mobile device's settings when pairing with an M2 reader using the SDK. Pairing the reader through your mobile device's settings may make the reader unavailable to connect through our SDK. Please rely on our ECPSdk to help guide the connection process.

    void discoverDevices(int scanTime, DiscoverCallback discoverCallback);
PropertyTypeDescription
scanTimeintRequired. Amount of time in seconds you would like to attempt to scan to discover devices. If 0 is passed in, the scanTime will default to a value of 5.
discoverCallbackDiscoverCallbackRequired. Callback which indicates the discover process has finished. onComplete will be called with an ArrayList of type ECPDevice indicating all devices that were successfully discovered. Also reports back an ECPSdkCallback error to pass back any error information that occurs during the discover process, so errors can be handled appropriately.

Example Implementation (in the example below you can also see how information in discoverDevices is directly used to then call in to connectDevice):

	_ecpSdk.discoverDevices(5, new DiscoverCallback<Reader>() {
		@Override
		public void onComplete(ArrayList<ECPDevice<Reader>> devices, ECPSdkCallbackError error) {
			if (error == null && devices != null && devices.size() > 0) {
				String[] deviceSerials = new String[devices.size()];

				StringBuilder devicesFoundInfo = new StringBuilder("Found the following devices on Scan:");

				for (int i = 0; i < devices.size(); i++) {
					deviceSerials[i] = devices.get(i).id_number;
					devicesFoundInfo = devicesFoundInfo.append("\n" + "  Id: " + devices.get(i).id_number +
							" Manufacturer: " + devices.get(i).manufacturer +
							" Model: " + devices.get(i).model +
							" Battery Percentage: " + devices.get(i).battery_percentage + "\n");
				}
				String finalDevicesFoundString = devicesFoundInfo.toString();
				runOnUiThread(new Runnable() {
					@Override
					public void run() {
						AlertDialog.Builder builder = new AlertDialog.Builder(StripeLandingActivity.this);
						builder.setTitle("Devices");
						responseView.setText(finalDevicesFoundString);
						builder.setItems(deviceSerials, new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialogInterface, int i) {
								// access clicked deviceSerial through deviceSerials[i]
								java.util.Optional<ECPDevice<Reader>> ecpDeviceOptional = devices.stream().filter(p -> p.id_number.equals(deviceSerials[i])).findFirst();
								if (!ecpDeviceOptional.isPresent()) {
									Toast.makeText(StripeLandingActivity.this, "Error connecting to device id: " + deviceSerials[i], Toast.LENGTH_SHORT).show();
									return;
								}

								ECPDevice<Reader> ecpDevice = ecpDeviceOptional.get();
								_ecpSdk.connectDevice(ecpDevice, new ConnectCallback() {
									@Override
									public void onComplete(boolean connected, ECPSdkCallbackError error) {
										Log.i(TAG, "connected: " + connected);
										runOnUiThread(new Runnable() {
											@Override
											public void run() {
												if (connected) {
													Toast.makeText(StripeLandingActivity.this, "Device connected!", Toast.LENGTH_SHORT).show();
												} else {
													Toast.makeText(StripeLandingActivity.this, "Device connection failed!", Toast.LENGTH_SHORT).show();
												}
											}
										});
									}
								});
							}
						});

						builder.show();
					}
				});
			} else {
				runOnUiThread(new Runnable() {
					@Override
					public void run() {
						responseView.setText("No devices found to report info on from scan");
						AlertDialog.Builder builder = new AlertDialog.Builder(StripeLandingActivity.this);
						if (error != null && error.errorDescription != null) {
							builder.setTitle("No devices found! Discover error was " + error.errorDescription);
						} else {
							builder.setTitle("No devices found!");
						}
						builder.show();
					}
				});
			}
		}
	});

Connect Device

Currently only officially supported for Stripe M2 Reader device. Connects to the card reader device and prepares the device to take payments, fire off events, and report information. A reader can only connect to one instance of the SDK at a time. If a device is already connected and another connection attempt is made, the ConnectCallback will return true. If you want to connect to a different device, be sure to disconnect from any connected devices first. Note - a reader may need to update on the connect process. The reader will not finish the connect process until required updates succeed. If a reader needs to update, ensure your reader is charged greater than 50 percent. Monitor ECPDeviceConfigStatusEvent and ECPDeviceConfigProgressEvent to track update status.

<T> void connectDevice(ECPDevice<T> ecpDevice, ConnectCallback connectCallback);
PropertyTypeDescription
ecpDeviceECPDeviceDevice object which you would like to attempt to connect to. This should be a recently discovered device from the Discover Devices method. Note - this device must be charged and turned on in order to connect. The generic represents the reader specific to the processor. For example, the Stripe reader would come from the Stripe SDK in com.stripe.stripeterminal.external.models.Reader.
connectCallbackConnectCallbackRequired. Callback which indicates the connect process has finished. onComplete will be called and will return boolean indicating whether the connection processes completed successfully. Also reports back an ECPSdkCallback error to pass back any error information that occurs during the connect process, so errors can be handled appropriately.

Example Implementation: See the example below. This example assumes that the discoverDevices method has been called and a device was found. The selected discovered device from the devices array returned from discoverDevices is then passed into the connectDevice method.

_ecpSdk.connectDevice(ecpDevice, new ConnectCallback() {
  @Override
  public void onComplete(boolean connected, ECPSdkCallbackError error) {
    Log.i(TAG, "connected: " + connected);
    runOnUiThread(new Runnable() {
      @Override
      public void run() {
        if (connected) {
          Toast.makeText(StripeLandingActivity.this, "Device connected!", Toast.LENGTH_SHORT).show();
        } else {
          Toast.makeText(StripeLandingActivity.this, "Device connection failed!", Toast.LENGTH_SHORT).show();
        }
      }
    });
  }
});

โ—๏ธ

Low Battery / Device Powered off Troubleshooting

When connecting to a reader for use, ensure the reader is charged greater than 20 percent to avoid unintended behavior due to low battery. Also ensure the device is turned on. If you attempt to connect to a reader with low battery or a powered off reader, you may notice connectDevice or the SDK stalling. If stalling behavior is noticed, try the following trouble shooting steps:

  1. Manually power down M2 reader device.
  2. Manually turn M2 reader device back on.
  3. Reset the SDK.
  4. Initialize SDK.
  5. Attempt to use SDK again.

If all else fails, force close your application, ensure your reader device is charged/powered on, and try again.

Disconnect Device

Disconnects the currently connected device.

void disconnectDevice(DisconnectCallback disconnectCallback);
PropertyTypeDescription
disconnectCallbackDisconnectCallbackRequired. Callback which indicates the disconnect device process has finished. onComplete will be called and will return a boolean indicating whether the disconnect processes completed successfully. Also reports back an ECPSdkCallback error to pass back any error information that occurs during the disconnect process, so errors can be handled appropriately.

Example Implementation:

_ecpSdk.disconnectDevice(new DisconnectCallback() {
  @Override
  public void onComplete(boolean didDisconnect, ECPSdkCallbackError error) {
    // Your logic here
  }
});

Make Sale

Makes a sale for the amount specified. This requires that the SDK is initialized and that the Client Token Service is set up correctly in order to retrieve a current client token for communication with PaySimple.

void makeSale(ECPPaymentParameters parameters, MakeSaleCallback makeSaleCallback);
PropertyTypeDescription
parametersECPPaymentParametersRequired. The parameters used to create the payment.
makeSaleCallbackMakeSaleCallbackRequired. Upon execution calls back onComplete. Passes back a boolean to provide information on if the sale flow completed (Note: this can return true even if the payment fails. This only indicates that the flow completed successfully). Passes back an ECPSaleResponse object with information about the payment. Also reports back an ECPSdkCallback error to pass back any error information that occurs during the sale process, so errors can be handled appropriately.

Example implementation:

ECPPaymentParameters params = new ECPPaymentParameters();
params.amount = "100.00";
params.external_id = "TestExternalId";
params.paymentDescription = "Test Description";
params.paymentDescriptionSuffix = "Test Suffix";

_ecpSdk.makeSale(params, new MakeSaleCallback() {
  @Override
  public void onComplete(boolean success, ECPSaleResponse saleResponse, ECPSdkCallbackError error) {
    Log.i(TAG, "make sale completed. Success: " + success);
  }
});

Stop Current Flow

Stops a payment from completing. This can be done before the payment method is collected. Once the payment method is collected, the payment flow will run to completion.

void stopCurrentFlow(ECPCallback callback);
PropertyTypeDescription
callbackECPCallbackRequired. Callback which indicates the stop current flow process has finished. onComplete will be called and will return a boolean indicating whether the stop current flow process completed successfully. Also reports back an ECPSdkCallback error to pass back any error information that occurs during the stop current flow process, so errors can be handled appropriately.

Example implementation:

_ecpSdk.stopCurrentFlow(new ECPCallback() {
  @Override
  public void onComplete(boolean success, ECPSdkCallbackError error) {
  	// Your logic here
  }
});

Get Device Info

Returns information about the connected device.

    void getDeviceInfo(DeviceInfoCallback deviceInfoCallback);
PropettyTypeDescription
deviceInfoCallbackDeviceInfoCallbackRequired. Upon execution calls back onComplete with device information. Passes back isDeviceConnected to provide information on if a device is currently connected to the SDK. Passes back an ECPDevice object with up to date properties for the specific device. Also passes back an ECPSdkCallbackError reference in case of an issue with getDeviceInfo.

Example Implementation:

deviceInfoBtn.setOnClickListener(v -> {
            _ecpSdk.getDeviceInfo(new DeviceInfoCallback() {
                @Override
                public void onComplete(boolean isDeviceConnected, ECPDevice ecpDevice, ECPSdkCallbackError error) {
                    if (isDeviceConnected && ecpDevice != null && error == null) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                StringBuilder deviceInfo = new StringBuilder("Get Device Info Result: \n "
                                        + "isDeviceConnected :" + isDeviceConnected + "\n"
                                        + "id: " + ecpDevice.id_number + "\n"
                                        + "manufacturer: " + ecpDevice.manufacturer + "\n"
                                        + "model: " + ecpDevice.model + "\n"
                                        + "battery_percentage: " + ecpDevice.battery_percentage + "\n"
                                        + "type: " + ecpDevice.reader.getClass());

                                responseView.setText(deviceInfo);
                            }
                        });
                    } else {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                StringBuilder deviceInfoError = new StringBuilder("Error on Get Device Info: " + "\n"
                                        + "isDeviceConnected : " + isDeviceConnected + "\n"
                                        + "error: " + error.errorDescription != null ? error.errorDescription : "");
                                responseView.setText(deviceInfoError);
                            }
                        });
                    }
                }
            });
        });

Delegates / Listeners / Events

The SDK provides an ECPSdkListener to help expose methods to report on SDK events. Currently, the ECPSdkListener provides one optional method void onDeviceEvent(ECPSdkEvent event) . In order to use the ECPSdkListener in your application, make your class implements ECPSdkListener. Additionally, pass the class which you would like to be a listener to the ECPSdk into the Initialize SDK method. You can also see Subscribe To Events for how to wire up additional listeners. See an example code block below for initialize:

public class LandingActivity extends AppCompatActivity implements ECPSdkListener {
 ////.....
  
 exampleMethod() {																																							// here is listener
     _ecpSdk.initializeSdk(StripeLandingActivity.this, environment, tokenService, subscribedEvents, this, new InitializeSdkCallback() {
     }
  }
//.... more code here
// .....
// .....    
                           
                           
                           
// Later on down in your file, you can implement onDeviceEvent to listen to events coming in. 
  @Override
    public void onDeviceEvent(ECPSdkEvent event) {
		//code goes here to  process each ECPSdkEvent coming in
    }
}

ECPSdkListener

PropertyTypeDescription
void onDeviceEvent(ECPSdkEvent event)Interface MethodMethod which can be implemented to listen for device events related to the SDK.

ECPSdkEvent Types

A generic type of event will be used as the base class for SDK events. This type is represented by a base class of ECPSdkEvent.

ECPSdkEvent

PropertyTypeDescription
messageStringReadable description of event.
errorECPEventErrorCustom error object to help indicate any errors that may have occurred on ECPSdkEvent.

ECPEventError

Custom error object used for error reporting within SDK.

PropertyTypeDescription
errorMessageStringString containing error message description.

๐Ÿ‘

Different subclasses of ECPSdkEvent will be utilized to represent different events. These classes are represented in the charts below.

ECPConnectionChangedEvent

Event that fires when a device connection status change is reported.

๐Ÿšง

When a Stripe M2 reader is powered off, both an UNEXPECTED_DISCONNECT event and a NOT_CONNECTED event will fire. Ensure to handle this case in your app.

PropertyTypeDescription
statusenum
(ECPConnectionStatus)
Indicates connection status of device. This enum can have the following potential enum values:
UNKNOWN_STATUS,
UNEXPECTED_DISCONNECT,
NOT_CONNECTED,
CONNECTING,
CONNECTED

ECPDeviceBatteryEvent

Event that fires when a battery event is reported.

PropertyTypeDescription
statusenum
(ECPBatteryEventStatus)
Indicates type of battery event that took place. This enum can have the following potential enum values:
BATTERY_LOW

ECPDeviceCardEvent

Event that fires when a card is inserted or removed.

PropertyTypeDescription
eventStatusenum
(ECPCardEventStatus)
Indicates the type of device card event that took place. This enum can have the following potential values:
UNKNOWN_EVENT,
CARD_REMOVED,
CARD_INSERTED

ECPDeviceMessageEvent

Event that fires when a device prompts a user.

PropertyTypeDescription
inputOptionsSet

Note - ECPInputOption is an enum, so the type above is a set of enum.
Indicates the type of input options the reader is prompting for. Also indicates the reader is waiting for input.

ECPInputOption can have the following enum values:
NONE,
MANUAL_ENTRY,
TAP,
SWIPE,
INSERT
messageCodeenum
(ECPDeviceMessageCode)
Indicates a message should be displayed to your user.

ECPDeviceMessageCode can have the following enum values:
NONE,
CARD_REMOVED_TOO_EARLY,
TRY_ANOTHER_CARD,
TRY_ANOTHER_READ_METHOD,
MULTIPLE_CONTACTLESS_CARDS_DETECTED,
REMOVE_CARD,
SWIPE_CARD,
INSERT_OR_SWIPE_CARD,
INSERT_CARD,
RETRY_CARD,
CHECK_MOBILE_DEVICE,
INPUT_REQUESTED

ECPDeviceConfigProgressEvent

Event that fires to report on config event progress.

PropertyTypeDescription
progressfloatIndicates the progress of a config event in the range of 0-1.

ECPDeviceConfigStatusEvent

Event that fires when a config event takes place from a device. Note - on a config update event some readers may be unusable until required updates are completed.

PropertyTypeDescription
statusenum
(ECPDeviceConfigStatus)
Indicates the type of config event that took place. This enum can have the following potential values:
UNKNOWN,
UPDATE_STARTING,
UPDATE_IN_PROGRESS,
UPDATE_FINISHED

onDeviceEvent - Sample Implementation

This method will fire when an event is reported from the SDK, and the SDK consumer has chosen to subscribe in a particular file. See the code block below for sample implementation of listening and reporting on device events. Note - consumers are free to determine their own best practice for their particular use case to determine the type of ECPSdkEvent, below is just one example. Consumers can then utilize the specific event type that is known to exist and access event specific information to utilize in their application.

๐Ÿšง

Important: If you are utilizing information in delegates to update UI, please follow best practices and dispatch UI changes to the main thread.

   @Override
    public void onDeviceEvent(ECPSdkEvent event) {
        Log.i(TAG, "On Device Event triggered for event: " + event.message);
        if (event instanceof ECPConnectionChangedEvent) {
            ECPConnectionChangedEvent connectionChangedEvent = (ECPConnectionChangedEvent) event;
            StringBuffer stringBuffer = new StringBuffer("ECPConnectionChangedEvent object details: ");
            stringBuffer.append("\n" + "ECPConnectionChangedEvent Status: " + connectionChangedEvent.status);
            stringBuffer.append("\n" + "ECPConnectionChangedEvent Message: " + connectionChangedEvent.message);
            if(event.error != null) {
                stringBuffer.append("\n" + "ECPConnectionChangedEvent Error present. Error message: " + event.error.errorMessage);
            }

            switch (connectionChangedEvent.status) {
                case NOT_CONNECTED:
                    stringBuffer.append("\n" + "ConnectionChangedEvent - device not connected");
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            responseView.setText(stringBuffer);
                        }
                    });
                    break;
                case CONNECTING:
                    stringBuffer.append("\n" + "ConnectionChangedEvent - device connecting");
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            responseView.setText(stringBuffer);
                        }
                    });
                    break;
                case CONNECTED:
                    stringBuffer.append("\n" + "ConnectionChangedEvent - device connected");
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            responseView.setText(stringBuffer);
                        }
                    });
                    break;
                case UNEXPECTED_DISCONNECT:
                    stringBuffer.append("\n" + "ConnectionChangedEvent - unexpected disconnect");
                    new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            responseView.setText(stringBuffer);
                        }
                    }, 1000);
                    break;
                case UNKNOWN_STATUS:
                    stringBuffer.append("\n" + "ConnectionChangedEvent - unknown status");
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            responseView.setText(stringBuffer);
                        }
                    });
                    break;
                default:
                    break;
            }
        } else if (event instanceof ECPDeviceConfigStatusEvent) {

            if (((ECPDeviceConfigStatusEvent) event).status == ECPDeviceConfigStatus.UPDATE_STARTING) {

                if(event.error == null) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(StripeLandingActivity.this, "Device has updates to install. Message: " + event.message, Toast.LENGTH_SHORT).show();
                            responseView.setText("Update starting...");
                        }
                    });
                } else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(StripeLandingActivity.this, "ECPDeviceConfigStatusEvent update starting event has error. Error message: " + event.error.errorMessage , Toast.LENGTH_SHORT);
                            responseView.setText("Error object on ECPDeviceConfigStatusEvent with status of starting");
                        }
                    });
                }
            } else if (((ECPDeviceConfigStatusEvent) event).status == ECPDeviceConfigStatus.UPDATE_FINISHED) {
                if(event.error == null) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(StripeLandingActivity.this, "Device has finished updating. Message: " + event.message, Toast.LENGTH_SHORT).show();
                            responseView.setText("Update complete");
                        }
                    });
                } else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(StripeLandingActivity.this, "ECPDeviceConfigStatusEvent update finished event has error. Error message: " + event.error.errorMessage, Toast.LENGTH_SHORT);
                            responseView.setText("Error object on ECPDeviceConfigStatusEvent with status of finished");
                        }
                    });
                }
            }
        } else if (event instanceof ECPDeviceConfigProgressEvent) {

            if(event.error == null) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        responseView.setText("Update in progress: " + ((ECPDeviceConfigProgressEvent) event).progress);
                    }
                });
            } else {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        responseView.setText("Error object on ECPDeviceConfigProgressEvent. Error message was: "
                                + event.error.errorMessage);
                    }
                });
            }

        } else if (event instanceof ECPDeviceMessageEvent) {
            StringBuffer sb = new StringBuffer();
            sb.append("Device Message: ").append(event.message);
            sb.append("\nCode: ")
                    .append(((ECPDeviceMessageEvent) event).messageCode == null ? "null" : ((ECPDeviceMessageEvent) event).messageCode.toString());
            Log.i(TAG, "message code: " + ((ECPDeviceMessageEvent) event).messageCode.toString());
            if (((ECPDeviceMessageEvent) event).inputOptions != null) {
                for (ECPInputOption option : ((ECPDeviceMessageEvent) event).inputOptions) {
                    Log.i(TAG, "Input option: " + option.toString());
                    sb.append("\nInput option: ").append(option);
                }
            }

            if(event.error != null) {
                sb.append("\nECPDeviceMessageEvent error present. Error message: " + event.error.errorMessage);
            }
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    responseView.setText(sb.toString());
                }
            });
        } else if (event instanceof ECPDeviceCardEvent) {
            StringBuffer sb = new StringBuffer();
            sb.append("Card Event: ").append(event.message);
            sb.append("\nStatus: ")
                    .append(((ECPDeviceCardEvent) event).eventStatus == null ? "null" : ((ECPDeviceCardEvent) event).eventStatus.toString());
            if (event.error != null) {
                sb.append("\nECPDeviceCardEvent error present. Error message: " + event.error.errorMessage);
            }
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    responseView.setText(sb.toString());
                }
            });
        }
        else if(event instanceof ECPDeviceBatteryEvent) {
            ECPDeviceBatteryEvent batteryEvent = (ECPDeviceBatteryEvent) event;
            StringBuffer stringBuffer = new StringBuffer();
            stringBuffer.append("Battery Event object details: ");
            stringBuffer.append("\n" + "ECPDeviceBatteryEvent Status: " + batteryEvent.status);
            stringBuffer.append("\n" + "ECPDeviceBatteryEvent Message: " + batteryEvent.message);
            if(event.error != null) {
                stringBuffer.append("\n" + "ECPDeviceBatteryEvent Error present. Error message: " + batteryEvent.error.errorMessage);
            }
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    responseView.setText(stringBuffer);
                }
            });
        }
    }