Java (Android)

In this topic:

Device Requirements

  • Minimum API level is 22 (platform version 5.1Link opens new window)
  • Gradle Plugin 4.2.2
  • The target API the Commerce SDK sample application uses out of the box is 32 (platform version 12Link opens new window). You can lower the target SDK requirements in build.gradle in the sample app and disable the runtime permissions in the code of the sample app.
  • Device cannot be rooted
  • Emulator / simulator is not supported

Workstation Configuration

If your workstation is already configured for Android development then you can most likely jump to the next section. Otherwise you can follow this high-level overview for setting up your environment.

Minimum Requirements

You can review the minimum workstation requirements in Android StudioLink opens new window.

Set Up the Environment

  1. Download and install the latest Oracle 1.8 32-bit JDKLink opens new window.
  2. Set the JAVA_HOME variable to point to the appropriate directory.
  3. Add JAVA_HOME\bin to your shell’s Path variable.
  4. Download and install either Android StudioLink opens new window or IntelliJLink opens new window and the Android SDKLink opens new window.
  5. Set the ANDROID_HOME variable to the appropriate directory.
  6. Configure your IDE to use the JDK and Android SDK as default platforms for new projects.

Refer to the Android Developer DocumentationLink opens new window for more information.

Build the Sample Application

  1. Unzip the sample app zip file. This example will assume you extracted the files into c:\sample-app.

  2. Open build.gradle and look for compileSdkVersion and buildToolsVersion. If you do not have those particular versions of the Android SDK installed, you have two choices:

    • You can change the values of those two variables to match the API level of the SDK you installed. Then save and close build.gradle.
    • You can install the Android SDK platform version to match these versions.
  3. Open your IDE and create a New project from Existing Sources.

  4. Navigate to c:\sample-app and select the build.gradle file. Click Ok to continue through the wizard.

  5. Once the IDE has stopped churning, open up the gradle tool window (View > Tool Windows > Gradle).

  6. In the Gradle tool window, click Tasks > Build then double-click Build.

  7. Once the IDE has stopped processing that task, you will find a new APK in the build/outputs/apk folder.

    At this point you should be able run the application from the IDE or you can manually install the APK onto your device.

  8. When the app starts up, you will want to tap the menu in the top right corner.

  9. Select Credentials which will let you enter your merchant ID, user ID, etc.

Set Up Your App

You can use the sample app’s build.gradle file as a starting point for your app. It is already configured to pull in the Commerce SDK libraries during build processing.

As part of your initial application setup, you will need to include the following permissions in your AndroidManifest.xml file:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />

<!-- Only needed when using RP457c card reader audio connection -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

<uses-feature android:name="android.hardware.telephony" android:required="false"/>

note

If you plan to support any of the Roam readers (RP457c, Moby/5500), then you also need the following permission to establish device pairing:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Some permissions are considered “dangerous” and need to be explicitly requested from the user at runtime. These are:

- READ_PHONE_STATE
- BLUETOOTH_SCAN
- BLUETOOTH_CONNECT
- ACCESS_FINE_LOCATION
- RECORD_AUDIO

You can check the sample app code to see how these permissions are requested.

Here is a high level overview of the steps necessary to perform a Credit Card Sale transaction. For more details, review the sample application.

note

The sample application is provided to help assist you on integrating Commerce SDK. It is not intended to be used to run production transactions. At times additional features may be exposed through the sample application that are not currently functional as these are associated with potential future enhancements to the product. Please refer to the transaction pages for the supported functionality for each transaction type.

  1. Initialize the Commerce Android module and check for errors.

    ECCError error = ECLCommerceAndroid.initialize(getApplication());
    if (error instanceof ECLCommerceError)
    {
        ...
    }
    
  2. Implement the ECLAccountListener interface.

    Refer to AccountListenerFactory for more information.

    The ECLAccountListener interface defines the methods where specific properties can be overridden for a gateway account. Depending on the backend server the application needs to communicate to, implement either the ECLConvergeAccountListener or ECLCreditCallAccountListener interface.

    class AccountListenerFactory
    {
        static ECLAccountListener create(final Context context, final MainActivity activity, final Handler handler)
        {
            ...
            return new ECLConvergeAccountListener()
            {
                @Override
                public Context getApplicationContext()
                {
                    // do something - look in the sample app code for a concrete example
                }
    
                @Override
                public ECCSensitiveData getMerchantId(ECLAccountInterface account)
                {
                    // returns your Converge account's merchant ID
                }
    
                @Override
                public ECCSensitiveData getUserId(ECLAccountInterface account)
                {
                    // returns your Converge account's user ID
                }
    
                @Override
                public ECCSensitiveData getPin(ECLAccountInterface account)
                {
                    // returns your Converge account's PIN
                }
    
                @Override
                public ECCSensitiveData getPartnerAppId(ECLAccountInterface account)
                {
                   // returns your Converge account's partner app ID if you have one
                   // this is optional and can be null
                }
    
                @Override
                public ECCSensitiveData getVendorId(ECLAccountInterface eclAccountInterface)
                {
                    // returns your vendor ID
                }
    
                @Override
                public ECCSensitiveData getVendorAppName(ECLAccountInterface eclAccountInterface)
                {
                    // returns your application name
                }
    
                @Override
                public ECCSensitiveData getVendorAppVersion(ECLAccountInterface eclAccountInterface)
                {
                    // returns your application version
                }
    
                @Override
                public ECLProxyInfo getProxyInfo()
                {
                    // do something - look in the sample app code for a concrete example
                }
    
    
                @Override
                public ECLPersistentSettingsInterface getPersistentSettings()
                {
                    return new ECLPersistentSettingsInterface()
                    {
                        @Override
                        public void saveSetting(String key, String value)
                        {
                            // do something - look in the sample app code for a concrete example
                        }
    
                        @Override
                        public String retrieveSettingForKey(String key)
                        {
                            // do something - look in the sample app code for a concrete example
                        }
    
                        @Override
                        public void clearSettingForKey(String key)
                        {
                            // do something - look in the sample app code for a concrete example
                        }
                    };
                }
    
                @Override
                public void accountDidInitialize(ECLAccountInterface account)
                {
    

    Once the account is initialized, you can override certain properties associated with it, like terminal language or US common debit preferences. You also have the chance to setup listeners for different events associated with the account, like get notifications when a key update occurs.

                    account.setUpdateKeysListener(new ECLUpdateKeysListener()
                    {
                        @Override
                        public void updateKeysFailed(ECCError eccError)
                        {
                            // do something - look in the sample app code for a concrete example
                        }
    
                        @Override
                        public void updateKeysCompleted()
                        {
                            // do something - look in the sample app code for a concrete example
                        }
    
                        @Override
                        public void updateKeysProgress(ECLTransactionProgress eclTransactionProgress)
                        {
                            // do something - look in the sample app code for a concrete example
                        }
                    });
    
                    // set up listener to be notified when a scheduled reboot is about to occur - for V4 pin pads
                    account.setCardReaderDailyRebootNotificationListener(new ECLCardReaderDailyRebootNotificationListener()
                    {
                        @Override
                        public void cardReaderWillPerformDailyReboot(long millisUntilReboot)
                        {
                            // do something - look in the sample app code for a concrete example
                        }
                    });
    

    The language used for transaction can be overridden. This applies to RBA pinpads only and will have no effect for other pinpads. This is completely optional. If not used, a possibly server supplied language preference info is going to be used. You can specify a pair of (language, country) to determine the language to be used on pinpad during a transaction. If the pair you supplied is not supported, the return value will indicate the language CSDK chose to use. This is determined to be the closest match to what you specified. Currently, Commerce SDK supports English in US and English and French in Canada.

                    ECLLanguageInformation desiredLanguage = ...;
                    ECLLanguageInformation finalValue = account.overrideDefaultTerminalLanguage(desiredLanguage);
    

    You can override the Commerce SDK setting for the debit network preference in the US. This applies to US RBA pinpads only and will have no effect for other pinpads. This is completely optional. If not used, a possibly server supplied value is going to be used. The possible choices are: global debit network, us common debit network or no preference at all, in which case the user will be asked to do the selection on the pinpad, if applicable. Be advised that in case of contactless transactions, the pinpad will not ask the user for a selection, but it will select the AID with the highest priority remaining after filtering them based on the setting. For example, if the choice is to use the global network and there are 2 global AIDs on the card, RBA will automatically select the one with the highest priority.

                    ECLDebitNetworkPreferences debitNetworkPreferences = ...;
                    account.overrideDebitNetworkPreferences(debitNetworkPreferences);
                }
    
                @Override
                public void accountDidFailToInitialize(ECLAccountInterface account, ECCError error)
                {
                    // do something - look in the sample app code for a concrete example
                }
    
                @Override
                public void accountDefaultCurrencyDidChange(ECLAccountInterface account, ECLCurrencyCode newCurrencyCode)
                {
                    // do something - look in the sample app code for a concrete example
                }
    
                @Override
                public ECLServerType getServerType()
                {
                    // do something - look in the sample app code for a concrete example
                }
            };
    

    In 5.5, the following methods were added.

    @Override
    public void certificateUpdateRequired(ECLCertificateInfo eclCertificateInfo)
    {
        // do something - look in the sample app code for a concrete example
    }
    
    @Override
    public ECCSensitiveDataInterface getBridgeMaintenanceSystemUsername(ECLAccountInterface eclAccountInterface)
    {
        // return the bmsUsername - each integrator will have unique BMS credentials - get them from your solution engineer
    }
    
    @Override
    public ECCSensitiveDataInterface getBridgeMaintenanceSystemPassword(ECLAccountInterface eclAccountInterface)
    {
        // return the bmsPassword - each integrator will have unique BMS credentials - get them from your solution engineer
    }
    
    @Override
    public void bridgeMaintenanceSystemFailure(ECCError eccError)
    {
        // BMS is the system used to get TMS updates. For example BMS provides updated certificates.
        //
        //                            WARNING WARNING WARNING
        //  !!! Something went wrong when trying to communicate with BMS.                              !!!
        /// !!! If the failure is ECLAccountInvalidCredentials it MUST be addressed.                   !!!
        /// !!! Valid BMS credentials are required in order to keep certificates up to date.           !!!
        /// !!! No transactions will be processed if connecting over IP without valid BMS credentials. !!!
        ///
    }
    
    @Override public void bridgeMaintenanceSystemSuccess()
    {
        // no need to do anything here
    }
    
    @Override
    public ECLProxyInfo getProxyInfo()
    {
        // do something if proxy info is needed - look in the sample app code for a concrete example
    }
    
  3. Kickoff the gateway account initialization process.

    handler = new AndroidHandler(new android.os.Handler(android.os.Looper.getMainLooper()));
    final ECLDispatcher dispatcher = new ECLDispatcher(handler);
    ECLAccountListener delegate =
        AccountListenerFactory.create(new deckard.content.android.AndroidContext(getApplicationContext()), this, handler);
    ECLCommerce.createAccount(delegate, dispatcher);
    

    You will receive some callbacks on the delegate which will allow you to pass your credentials into Commerce SDK. Then you will receive another callback that will let you know whether the account initialization process was successful or not. Once the account has been initialized, you will get back an instance of ECLAccountInterface which is hereby referred to as account.

  4. Start a Sale transaction.

    Create a money object representing $3.00.

    ECLMoney amount = new ECLMoney(ECLCurrencyCode.USD, 300L);
    

    Create a transaction interface.

    ECLCurrencyTransactionInterface transaction = account.getTransactionProcessor().createSaleTransactionWithSubtotal(amount);
    

    Create a card tender.

    ECLCardTenderInterface tender = account.getTransactionProcessor().createCardTender();
    

    Create a transaction listener so we can receive callbacks during transaction processing.

    ECLTransactionProcessingListener transactionListener = new ECLTransactionProcessingListener()
    {
        @Override
        public void uponSearchingDevice(ECLConnectionMethod eclConnectionMethod)
        {
            // do something - look in the sample app code for a concrete example
        }
    
        @Override
        public void transactionDidComplete(ECLTransactionInterface transaction, ECLTenderInterface tender,
            final ECLTransactionOutcome outcome)
        {
            // do something - look in the sample app code for a concrete example
        }
    
        @Override
        public void transactionDidCancel(ECLTransactionInterface transaction, ECLTenderInterface tender)
        {
            // do something - look in the sample app code for a concrete example
        }
    
        @Override
        public void transactionDidFail(ECLTransactionInterface transaction, ECLTenderInterface tender, List<ECCError> errors)
        {
            // do something - look in the sample app code for a concrete example
        }
    
        @Override
        public void shouldProvideInformation(final ECLTransactionInterface transaction, final ECLTenderInterface tender,
            ECLTransactionRequirementsInterface transactionRequires, ECLTenderRequirementsInterface tenderRequires)
        {
            // We need more information to process the transaction!        
            // During transaction processing, this callback may be executed one or more times for the purpose
            // of collecting more information to continue processing the transaction.
            // Look in the sample app code for a concrete example
        }
    
        @Override
        public void shouldSetCardReaderToUse(final ECLTransactionInterface transaction, final ECLTenderInterface tender,
            final List<String> cardReadersReadyForUse)
        {
            // Commerce detected more than one card reader so you need to let the user choose which one from the list should be used
            // Should this scenario arise, provide a mechanism to select the appropriate card reader.
            // Look in the sample app code for a concrete example
        }
    
        public void shouldSetCardReaderToUse(ECLTransactionInterface transaction, ECLTenderInterface tender)
        {
            // do something - look in the sample app code for a concrete example
        }
    
        @Override
        public void transactionProgress(final ECLTransactionProgress progress, final ECLTransactionInterface transaction,
            final ECLTenderInterface tender)
        {
            // Always good to know what is happening while the transaction is processing!        
            // Use this callback to provide status information (i.e. "progress" messages)
            // Look in the sample app code for a concrete example
        }
    };
    

    Now it is time to actually start processing the transaction.

    account.getTransactionProcessor().processTransaction(transaction, tender, transactionListener);
    

    Your transactionListener will receive various callbacks throughout the lifecycle of a transaction. At some point, you will receive a transactionDidCancel, transactionDidFail, or transactionDidComplete callback signaling the end of a transaction.

Client Certificate for IP Communication

POS must implement certificateUpdateRequired(). In this method, POS should

  • store the certificate files

    note

    It is recommended to store the files in the application’s data directory.

  • upon connecting, supply information in connection criteria (see [doclink id=“device-connection-criteria” product=“commerce-sdk”]Device Connection Criteria[/doclink])

    • supply certificate files using setConnectionParameters().
    • supply client keystore date using setClientKeyStoreDate().

POS must implement connectWithUpdatedKeystoreInfo(). In this method POS should

  • call ECLCardReaderInterface.connectWithUpdatedKeystoreInfo() passing ECLConnectionParameters.

note

Before CSDK 5.6, when using RBASDKAdapter, POS should pass null as ECLConnectionParameters and the certificate files should be passed to RBASDKAdapter. See 5.5.0 sample app.

Starting from CSDK 5.6, CSDK can handle certificate files internally on Android as described above. This is recommended over using RBASDKAdapter in the POS application to handle certificate file streams.