# API Guide (/global/en/docs/Terminal/EMVL3/API-Guide)

---

## Introduction

### What's Newland EMV Level 3 SDK

Newland EMV Level 3 provides an application layer for EMV Contact/Contactless processing on top of the EMV Level 2 kernels.

EMVL3 integrates the APIs of various EMVL2 Kernels, encapsulates the interface process of EMVL2, and provides a unified API, allowing applications to easily and quickly process EMV transactions.

### References

\_\_ORDER\_Ⅰ\_\_For API usage questions : please refer to **NPT\_SDK\Android\doc\EMV\L3\_SDK\EMVL3 FAQ.pdf\*\*\*\*ENDORDER**

\_\_ORDER\_Ⅱ\_\_For API details, please refer to **NPT\_SDK\Android\doc\EMV\L3\_SDK\emv\_l3\_api\index.html\*\*\*\*ENDORDER**

\_\_ORDER\_Ⅲ\_\_For API calling demo, please refer to **NPT\_SDK\Android\demos\EMV\_L3\_Demo\*\*\*\*ENDORDER**

### Device Requirements

For now, EMV Level 3 can be used on the following devices:

| Device Model      | OS Firmware       | Platform |   |
| :---------------- | :---------------- | :------- | - |
| N910 A7 or higher | V1.0.19 or higher | Android  |   |
| N910 Pro          | V1.1.02 or higher | Android  |   |
| N850 A7 or higher | V1.0.05 or higher | Android  |   |
| N700 A7 or higher | V1.0.06 or higher | Android  |   |
| CPOS X5           | V1.0.60 or higher | Android  |   |

And EMV Level 3 supports to communicate with external PIN pad devices as below:

| Device Model | OS Firmware                      |   |
| :----------- | :------------------------------- | - |
| ME30SU       | V2.6.8 or higherV3.0.3 or higher |   |

### What EMV Level 3 SDK Provides

Packages that contain both internal and external modules:

|                                      |                                                                                                                      |
| :----------------------------------- | :------------------------------------------------------------------------------------------------------------------- |
| `Newland-EMVL3-x.x.x.aar`            | Including internal modules.                                                                                          |
| `Newland-EMVL3-Plugin-Ext-x.x.x.jar` | Including external modules to interact with external pinpad devices.                                                 |
| `Newland-EMVL3-Ext-x.x.x.aar`        | used in Mobile. Usually is used when developing applications on common android devices (e.g., android mobile phones) |

### EMV Level 3 SDK Scenarios

|                                   | **Newland-EMVL3-x.x.x.aar** : | **Newland-EMVL3-x.x.x.aar** : **Newland-EMVL3-Plugin-Ext-x.x.x.jar** : | **Newland-EMVL3-Ext-x.x.x.aar** : |   |
| :-------------------------------- | :---------------------------- | :--------------------------------------------------------------------- | :-------------------------------- | - |
| **N950**                          | √                             |                                                                        |                                   |   |
| **N910 Pro**                      | √                             |                                                                        |                                   |   |
| **N910**                          | √                             |                                                                        |                                   |   |
| **N850**                          | √                             |                                                                        |                                   |   |
| **N750**                          | √                             |                                                                        |                                   |   |
| **N700**                          | √                             |                                                                        |                                   |   |
| **N550**                          | √                             |                                                                        |                                   |   |
| **N510**                          | √                             |                                                                        |                                   |   |
| **X800**                          | √                             |                                                                        |                                   |   |
| **CPOS X5**                       | √                             |                                                                        |                                   |   |
| **N850+SP100/SP130/ME51P/ME30SU** |                               | √                                                                      |                                   |   |
| **CPOS+SP100/ME51P/ME30SU**       |                               | √                                                                      |                                   |   |
| **Mobile+ME30SU**                 |                               |                                                                        | √                                 |   |

---

## General Module Use

### Initialize L3 Module

Initialize Level 3 API environment, setup callback function initialization and configuration need only be performed once at module startup.

![](https://docs.newlandnpt.us/assets/_shared/24ca80f37715/image.png)

#### EmvL3Impl.init(String filePath, byte\[ ] configuration) ;

Initialize kernel status and set kernel configuration.

Initialization and configuration need only be performed once at module startup and whilst configuration remains the same during processing. And you can also use **com.newland.sdk.emvl3.api.internal.EmvL3.setConfig** to set configuration alone.

| EmvL3Const.CONFIG                      | Value  | Description                                            |   |
| :------------------------------------- | :----- | :----------------------------------------------------- | - |
| L3\_CFG\_SUPPORT\_EC                   | 0x0001 | Support pboc election currency transaction             |   |
| L3\_CFG\_SUPPORT\_SM                   | 0x0002 | Support SM algorithm                                   |   |
| L3\_CFG\_SUPPORT\_GET\_RFAPDU          | 0x0010 | Support get contactless APDU                           |   |
| L3\_CFG\_SUPPORT\_RF\_AFTERFINALSELECT | 0x0020 | Support callbcak after\_final\_select for contactless. |   |
| L3\_CFG\_DISABLE\_TRACK2\_LEN\_CHECK   | 0x0101 | Support disable check Track2 length                    |   |

> **WARN**
>
> In order to use L3 functions normally, EMVL3 **init** function must be used first.

#### EmvL3Impl.setConfig(int offset, byte mode) ;

Set "support/not support" the specified configuration.

Used to determine the config support functions. Use this function and **Configuration Item** to set the **config** parameters required for **EmvL3Impl.init** function.

#### EmvL3Impl.getConfig(int offset) ;

Get the specified configuration.

Get the result of whether the specified configuration is supported.Confirm that the current configuration supports this parameter.

### Load EMV Configuration

Lack of AID or CAPK configuration can lead to transaction failure.

#### Terminal Config

**Terminal Configuration :**

> 1. The Newland Reader maintains two separate Terminal configurations, one each for **contact** and **contactless** interfaces. A terminal configuration for a card >interface applies to all card applications (AIDs) supported by the Reader for that card interface. The terminal configurations are retained over power cycles.
> 2. When the Reader powers up for the first time, it will have no terminal configurations.

**AidImpl.loadTerminalConfig(byte\[] config);**

Load Terminal Configuration.

> **WARN**
>
> make sure TAG 9F06 in the parameter **config**(TLVs) with 16 bytes of “\x00”.

**Terminal Configuration management:**

\*\*ORDER\_Ⅰ\*\*\*\*getTerminalConfig();\*\***ENDORDER**
Get terminal configuration.

\*\*ORDER\_Ⅱ\*\*\*\*flushTerminalConfig();\*\***ENDORDER**
Flush Terminal configuration ( will delete Terminal configuration. )

#### AID Config

**AID Configuration :**

> 1. Every AID can share Terminal Configuration parameters
> 2. Each AID has its own configuration Tags, which can be unique to itself or duplicated with Terminal Configuration parameters. When the Tags duplicated with Terminal >Configuration, the Tags of AID configuration will be used for transactions.

**AidImpl.loadAID(byte\[] config);**

Load/Update one AID configuration.

**AID Configuration management:**

\*\*ORDER\_Ⅰ\*\*\*\*getAID(AIDEntry aidentry);\*\***ENDORDER**
Get AID configuration.

```java
/**
 * Value of TAG 9F06.
 */
private byte[] aid = new byte[16];
/**
 * Length of AID.
 */
private int aidlen;
/**
 * Value of TAG DF37.
 */
private byte[] kernelid= new byte[8];
/**
 * Extend usage
 * <p>
 * 0x00 - default, will no check<br>
 * |0x01 - should be matching transactionType<br>
 * |0x02 - should be matching externString</p>
 */
private int externCheckFlag;
/**
 * Value of TAG 9C.
 */
private byte transactionType;
private byte[]externString = new byte[50];
private int externStrlen;
```

\*\*ORDER\_Ⅱ\*\*\*\*remove(AIDEntry aidentry);\*\***ENDORDER**
Remove the specified AID

\*\*ORDER\_Ⅲ\*\*\*\*flush();\*\***ENDORDER**
Flush EMV configuration ( will delete all of the configuration (Terminal and AIDs) )

\*\*ORDER\_Ⅳ\*\*\*\*flushAID();\*\***ENDORDER**
Flush EMV configuration ( will delete all of the configuration (Terminal and AIDs) )

\*\*ORDER\_Ⅴ\*\*\*\*getAidCount();\*\***ENDORDER**
Get aid count.

\*\*ORDER\_Ⅵ\*\*\*\*getAIDList();\*\***ENDORDER**
numerate all of the aid configuration, include terminal configuration.

#### CAPK Config

> CAPK ：Certification Authority Public Key.

**CapkImpl.load(CAPKEntry capk);**

Load one CAPK.

```java
private byte[] modulus = new byte[248];
private int pkModuluslen;
private byte[] exponent = new byte[3];
private byte[] hash = new byte[20];
private byte[] expiredDate = new byte[4];
private byte[] rid = new byte[5];
private int index;
private byte algorithmIndicator;
private byte hashAlgorithm;
private byte[] rfu = new byte[4];
```

**CAPK Configuration management:**

**ORDER\_Ⅰ\*\*\*\*CapkImpl.get(byte\[] rid, int index);** **ENDORDER**
Get one Certification Authority Public Key.

\*\*ORDER\_Ⅱ\*\*\*\*CapkImpl.remove(byte\[] rid, int index);\*\***ENDORDER**
Remove one Certification Authority Public Key.

\*\*ORDER\_Ⅲ\*\*\*\*CapkImpl.flush();\*\***ENDORDER**
Remove ALL Certification Authority Public Key.

\*\*ORDER\_Ⅳ\*\*\*\*CapkImpl.getCapkCount();\*\***ENDORDER**
Get CAPK Count.

\*\*ORDER\_Ⅴ\*\*\*\*CapkImpl.getCAPKList();\*\***ENDORDER**
Get the whole capk configuration(rid + index)

#### Certification Revocation List

**CertRevocationImpl.load(CRLEntry crl);**

Load one Certification Revocation List

```java
/**
 * Registered Application Provider Identifier
 */
private byte[] rid = new byte[5];
/**
 * Certification Authority Public Key Index
 */
private int index;
/**
 * Certificate Serial Number
 */
private byte[] əcsn = new byte[3];
/**
 * Reserved for Futrue Use
 */
private byte[] rfu = new byte[3];
```

**Certification Revocation list management:**

**ORDER\_Ⅰ\*\*\*\*isExist(byte\[] rid, int index, byte\[] csn);** **ENDORDER**
Get one Certification Revocation List

\*\*ORDER\_Ⅱ\*\*\*\*remove(byte\[] rid, int index, byte\[] csn);\*\***ENDORDER**
Remove one Certification Revocation List

\*\*ORDER\_Ⅲ\*\*\*\*flush();\*\***ENDORDER**
Remove ALL Certification Revocation List

#### Exception list

**load(ExceptionFileEntry exceptionFile);**

Load one exception file

```java
/**
 * The Pan 19byte ascii
 */
private byte[] pan = new byte[19];
/**
 * Lenth of PAN
 */
private int panlen;
/**
 * PAN Serial Number. OxFF: ignore
 */
private int panSN;
/**
 * Reserved for Futrue Use
 */
private byte[] rfu = new byte[4];
```

**Exception list Management:**

**ORDER\_Ⅰ\*\*\*\*isExist(String pan, byte panSN);** **ENDORDER**
Get one exception file from list.

\*\*ORDER\_Ⅱ\*\*\*\*isExist(byte\[] pan, int panSN);\*\***ENDORDER**
Get one exception file from list.

\*\*ORDER\_Ⅲ\*\*\*\*remove(String pan, byte panSN);\*\***ENDORDER**
Remove one exception file from List.

\*\*ORDER\_Ⅳ\*\*\*\*flush();\*\***ENDORDER**
Remove All exception file from list.

(Is the card number on the blacklist affecting transaction results related to the configuration of **ICS** and **TAC/IAC**.

Byte 4 Terminal Risk Management\
bit 8 Floor Limit Checking\
bit 7 Random Transaction Selections\
bit 6 Velocity checking\
bit 5 Transaction Log\
bit 4 Exception File\
bit 3 Terminal Risk Management irrespective of AIP setting\
bit 2 Transaction Log mode (1-EMV, 0-PBOC)\
bit 1 Rfu

![](https://docs.newlandnpt.us/assets/_shared/dd44abec9e4e/image-5.png)

)

### Perform Transactions

MSR/Contact/Contactless transactions are performed during normal processing.

![](https://docs.newlandnpt.us/assets/_shared/3230496b39c9/image-6.png)

#### EmvL3Impl.performTransaction(int cardInputType, int timeout, byte\[ ] data, PerfromTransactionListener listener);

Perform transactions on the MSR, contact and contactless card interfaces.

Returns transaction result ( Declined, Approved, Online, Terminated, OK, Try\_Another )

**cardInputType :**

| EmvL3Const.CardInterface | Value |   |
| :----------------------- | :---- | - |
| MAGSTRIPE                | 0x01  |   |
| CONTACT                  | 0x02  |   |
| CONTACTLESS              | 0x04  |   |
| MANUAL                   | 0x08  |   |

**timeout :** Time in seconds for which the Reader will look for a card on the specified interfaces before returning a timeout error.

**data :** transaction data (TLVs).

**listener :** The detailed use of **PerformTransactionListener** can be found in Listener 4.1

```java
PerformTransactionListener extends UIEventListener, APDUListener, TransResultListener
```

#### EmvL3Impl.completeTransaction(boolean onlineResult, byte\[] data, CompleteTransactionListener completeListener);

Continue to perform transactions after **online processing** (for MSR /contact/ contactless transaction).

After going online to the backend/acquirer host for online authorization, this API can be used by the terminal to convey the result of the online authorization to the Reader and to complete the transaction.

**onlineResult :**
Possible Values:
true: Online Processing with back-end host was completed
false: Online Processing not completed. Could not connect to host or no response from host.

**data :** transaction data (TLVs).

**completeListener :** The detailed use of **CompleteTransactionListener** can be found in Listener 4.2

```java
CompleteTransactionListener extends UIEventListener, APDUListener, TransResultListener
```

### Terminate Transaction

This Functionality is used to handle transaction cleanup and release resource.

#### EmvL3Impl.terminateTransaction();

Terminate transaction and release resource.

> **WARN**
>
> Must be called after every transaction ( Mandatory )

---

## Other Modules

### In/Out

#### EmvL3Impl.getData(int tag);

Get the EMVL3 data according L3\_DATA type (The type L3 data) or EMVL2 specified tag.

| **EmvL3Const.L3\_DATA** | **Value** | **Description**                                                   |   |
| :---------------------- | :-------- | :---------------------------------------------------------------- | - |
| PAN                     | 0         | Application Primary Account Number (PAN)                          |   |
| TRACK1                  | 1         | Track 1 Data                                                      |   |
| TRACK2                  | 2         | Track 2 Data                                                      |   |
| TRACK3                  | 3         | Track 3 Data                                                      |   |
| DD\_CARD\_TRACK1        | 4         | DD Card Track1                                                    |   |
| DD\_CARD\_TRACK2        | 5         | DD Card Track2                                                    |   |
| EXPIRE\_DATE            | 6         | Expired Date                                                      |   |
| SERVICE\_CODE           | 7         | Service Code                                                      |   |
| CARDHOLDER\_NAME        | 8         | Cardholder Name                                                   |   |
| POS\_ENTRY\_MODE        | 9         | POS Entry Mode. Indicates the method by which the PAN was entered |   |
| CARD\_SCHEME\_ID        | 10        | Card Scheme ID                                                    |   |
| SIGNAtrue               | 11        | Signatrue Flag                                                    |   |
| ADVISE                  | 12        | Advise Flag, used for Contact EMV                                 |   |
| ISSUER\_SCRIPT\_RESULT  | 13        | Issuer Script Results                                             |   |
| CVM\_OUTCOME            | 14        | CVM outcome. this data type only used for clss transction         |   |

#### EmvL3Impl.setData(int tag, byte\[] val);

Update kernel data.

#### EmvL3Impl.getListData(List\<Integer> tagList, boolean isPackZeroLen);

Get the TLV format data from current kernel.

### Debug

#### EmvL3Impl.setDebugMode(int debugLv);

Set Debug Mode/Level

LV\_CLOSE : 0x00  Close debug.

LV\_DEBUG : 0x01  Debug mode. log with normal debug.

LV\_ALL : 0x03  Debug mode. log with all of the debug information.

> When debugLv is **LV\_DEBUG** or **LV\_ALL**, the transaction log information will output in the Command line tool — **Logcat**

### Version Management

#### EmvL3Impl.getVersion(int module);

Get the version of EMVL3 module and L2 kernel.

| **EmvL3Const.MODULE**  | **Value** | **Description**   |   |
| :--------------------- | :-------- | :---------------- | - |
| L3\_MODULE\_API        | 0         | EMVL3 SDK         |   |
| L3\_MODULE\_EMV        | 1         | EMV               |   |
| L3\_MODULE\_EP         | 2         | Entrypoint        |   |
| L3\_MODULE\_QPBOC      | 3         | QPBOC             |   |
| L3\_MODULE\_PAYPASS    | 4         | Paypass           |   |
| L3\_MODULE\_PAYWAVE    | 5         | Paywave           |   |
| L3\_MODULE\_EXPRESSPAY | 6         | Express           |   |
| L3\_MODULE\_DPAS       | 7         | D-pass (Discover) |   |
| L3\_MODULE\_JCB        | 8         | JCB               |   |
| L3\_MODULE\_PURE       | 9         | Pure              |   |
| L3\_MODULE\_RUPAY      | 10        | Rupay             |   |
| L3\_MODULE\_INTERAC    | 11        | Interac           |   |
| L3\_MODULE\_MIR        | 12        | MIR               |   |
| L3\_MDDULE\_MULTIBANCO | 13        | Multibanco        |   |
| L3\_MDDULE\_CPACE      | 14        | CAPCE             |   |

### Detect Card

#### EmvL3Impl.detectCard(int input, int timeout, int\[ ] currentInterface);##\#

Detect card(Optional)

**input :** Card input mode, indicate card interfaces on which to look for a card.

**timeout :** Time in seconds for which the Reader will look for a card on the specified interfaces before returning a timeout error.

**currentInterface :** Current card interface if the card reading successfully.

**Input / currentInterface :**

0x01: MSR interface

0x02: Contact Interface

0x04: Contactless interface

0x08: Manul interface

(This function can be used to separate the detect card operation from the **EmvL3Impl.performTransaction** function and **perform it in advance**.By placing the detect card result of this function in the data of the EmvL3Impl.performTransactio parameter Tag-**1F8121**, the built-in detect card operation of the EmvL3Impl.performTransaction function can be skipped.

![](https://docs.newlandnpt.us/assets/_shared/5048165aadf6/image-7.png)

)

### responseEvent

#### EmvL3Impl.responseEvent(int eventResult, byte\[] data);##\#

Response listener result and exchange L2/L3 data or Send Card Detect Message.

**eventResult :** listener result or response Card Detect event

listener result:

ErrorCode.L3\_ERR\_SUCC : Sucess

ErrorCode.L3\_ERR\_CANCEL : Cancel

ErrorCode.L3\_ERR\_TIMEOUT : Timeout

ErrorCode.L3\_ERR\_FAIL : Other failure

ErrorCode.L3\_ERR\_BYPASS : Bypass PIN

response Card Detect event:

EMVL3Const.ResponseEvent.CANCEL : 0x01

EMVL3Const.ResponseEvent.SUCC\_MANUAL : 0x02

additional data of listener result or other special L2/L3 data you want to exchange, you can realize by the parameter **data**.

---

## Listener

Callback function interface.

The following will introduce the functions of **Listener** interface based on the content of the callback functions set in **EMVL3APIDemo**.

### PerfromTransactionListener

#### getPIN(int pinType, int pinTryCnt, publickey pinPK);

Online/Offline PIN entry.(Online Enciphered Pin, Offline Plaintext Pin, Offline Enciphered Pin)

| EmvL3Const.PINType       | Value | Description             |   |
| :----------------------- | :---- | :---------------------- | - |
| PIN\_ONLINE              | 0     | Online PIN.             |   |
| PIN\_OFFLINE             | 1     | Offline PIN.            |   |
| PIN\_OFFLINE\_ENCIPHERED | 2     | Offline enciphered PIN. |   |

**pinTryCnt :** The rest PIN try counter of offline PIN

**pinPK :** NULL or PIN public key( used for enciphered offline PIN)

```java
@Override
public void getPIN(int pinType, int pinTryCnt, publickey pinPK) {
    Log.d(getClass().getName(), String.format("PerfromTransactionListener::getPIN():  %d, %d", pinType, pinTryCnt));
    byte[] pan = mEmvL3Module.getData(EmvL3Const.L3_DATA.PAN);

    if(pinType == EmvL3Const.PINType.PIN_OFFLINE_ENCIPHERED && pinPK == null){
        showMessage("OfflinePin Without publickey");
        mEmvL3Module.responseEvent(ErrorCode.L3_ERR_CANCEL, null);
    }

    ((MainActivity) context).startEnterPin(pinType, new String(pan), pinPK);
}

public void startEnterPin(int Pintype, String pan, publickey pinPK) {
   appendText("Into Enter Pin");
   if(getPinKCV(2) == null){
      appendText("Withput Pin Key,Skip Enter Pin");
      mEmvL3Flow.ResponseEvent(ErrorCode.L3_ERR_SUCC, new byte[]{(byte)0x90,0x00});
      return;
   }
   try {
      NSDKModuleManager moduleManager = NSDKModuleManagerImpl.getInstance();
      DeviceManager deviceManager = (DeviceManager) moduleManager.getModule(ModuleType.DEVICE_MANAGER);
      DeviceInfo deviceInfo = deviceManager.getDeviceInfo();
      String model = deviceInfo.getDeviceModel();
      Log.d(getClass().getName(), "device model : "+model);
      if("X800".equalsIgnoreCase(model)) {
         Intent intent = new Intent(MainActivity.activity, SecondDisplayActivity.class);
         Bundle bundle = new Bundle();
         bundle.putBoolean("isRandomLayout", false);
         bundle.putInt("keyType", KEY_TYPE_DES);
         bundle.putBoolean("isX800", true);
         bundle.putString("moduleItem", "Online PIN");
         bundle.putString("PAN",  new String(pan));
         intent.putExtras(bundle);
         MainActivity.activity.startActivityForResult(intent,MainActivity.REQUEST_DISPLAY_ACTIVITY);
         return;
      }
   } catch (NSDKException e) {
      e.printStackTrace();
   }

   isNeedStart = false;
   Intent intent = new Intent(MainActivity.this, KeyBoardNumberActivity.class);
   intent.putExtra("pinType", Pintype);
   intent.putExtra("pan", pan);
   if(Pintype == EmvL3Const.PINType.PIN_OFFLINE_ENCIPHERED){
      byte[] pk_mod = new byte[pinPK.pk_mod_len];
      System. arraycopy(pinPK.pk_modulus,0,pk_mod,0,pinPK.pk_mod_len);
      intent.putExtra("module", ISOUtils.hexString(pinPK.pk_modulus));
      intent.putExtra("exponent", ISOUtils.hexString(pinPK.pk_exponent));
   }
   startActivityForResult(intent, 1);

}
```

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.

#### selectCandidateList(ArrayList\<Candidate> candidateList);

Candidate selection.

Application selection process, control the behavior of devices when making card application selections.

```java
@Override
public void selectCandidateList(ArrayList<Candidate> arrayList) {
    Log.d(getClass().getName(), "PerfromTransactionListener::selectCandidateList");
    selectCandidate(arrayList);
    // m_EmvL3Module.responseEvent(ErrorCode.L3_ERR_SUCC, nSelect);
}

/**
 * Show the candidate list for customer to choose
 *
 * @param candidates The candidate list
 * @return Result of UI,ErrorCode.L3_ERR_SUCC for success, ErrorCode.L3_ERR_CANCEL for cancelled
 */
private void selectCandidate(final ArrayList<Candidate> candidates) {
    Log.d(getClass().getName(), " selectCandidate:" + candidates.size());
    String[] items = new String[candidates.size()];
    int index = 0;
    for (Candidate candidate : candidates) {
        String name = null;
        int n = 1;
        if (candidate.getIssuerCodeTableIndex() > 8) {
            n -= 1;
            candidate.setIssuerCodeTableIndex((byte)(candidate.getIssuerCodeTableIndex()-8));
        }

        //boolean supportIsscode = ((candidate.getTerminalCodeTable()[n] & (1L << (candidate.getIssuerCodeTableIndex() - 1))) != 0x00);
        if ( candidate.getPreferName()[0] != 0x00) {
            name = new String(candidate.getPreferName());
        } else {
            if (candidate.getLabel()[0] != 0x00) {
                name = new String(candidate.getLabel());
            } else {
                name = BytesUtils.bytesToHex(candidate.getAID());
            }
        }

        items[index] = name;
        index++;
    }

    selectItems("Select Candidates", items);
}

protected void selectItems(String title, String[] items) {

    ((MainActivity) context).runOnUiThread(new Runnable() {
        @Override
        public void run() {
            selectMenu(title, items);
        }
    });
}

private void selectMenu(String title, String[] items) {

    final byte[] choice = {0};

    AlertDialog.Builder builderDiaLog = new AlertDialog.Builder(context).setIcon(R.mipmap.ic_launcher).setTitle(title)
            .setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    choice[0] = (byte) i;
                }
            }).setPositiveButton("sure", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mEmvL3Module.responseEvent(ErrorCode.L3_ERR_SUCC, choice);
                }
            }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mEmvL3Module.responseEvent(ErrorCode.L3_ERR_CANCEL, choice);
                }
            });
    builderDiaLog.create().show();
}
```

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> Success:\**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC,*\* data);\
> Cancel:\**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_CANCEL,*\* data);

#### selectAccount();

Account type selection

control the behavior of the application when selecting card accounts.

```java
@Override
public void selectAccount() {
	Log.d(getClass().getName(), "PerfromTransactionListener::selectAccount()");
	String[] items = new String[4];
	items[0] = "Default";
	items[1] = "Savings";
	items[2] = "Cheque/debit";
	items[3] = "Credit";

	selectItems("Select Account", items);
//  m_EmvL3Module.responseEvent(ErrorCode.L3_ERR_SUCC, null);
}
protected void selectItems(String title, String[] items) {

    ((MainActivity) context).runOnUiThread(new Runnable() {
        @Override
        public void run() {
            selectMenu(title, items);
        }
    });
}

private void selectMenu(String title, String[] items) {

    final byte[] choice = {0};

    AlertDialog.Builder builderDiaLog = new AlertDialog.Builder(context).setIcon(R.mipmap.ic_launcher).setTitle(title)
            .setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    choice[0] = (byte) i;
                }
            }).setPositiveButton("sure", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mEmvL3Module.responseEvent(ErrorCode.L3_ERR_SUCC, choice);
                }
            }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mEmvL3Module.responseEvent(ErrorCode.L3_ERR_CANCEL, choice);
                }
            });
    builderDiaLog.create().show();
}
```

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> Success:\**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC,*\* data);\
> Cancel:\**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_CANCEL,*\* data);

#### selectLanguage(byte\[ ] language);

Multi-language selection

The application should match the language Preference and complete the language selection. The **selectLanguage** Listener can control the behavior of devices when selecting language.

**selectAccount** and **selectLanguage Listener** can be optionally executed at the end of application initialization stage.

![](https://docs.newlandnpt.us/assets/_shared/1c74ff1deef4/image-9.png)

```java
@Override
public void selectLanguage(byte[] languageNo) {
    Log.d(getClass().getName(), "PerfromTransactionListener::selectLanguage()");
    if (languageNo == null) {
        mEmvL3Module.responseEvent(ErrorCode.L3_ERR_SUCC, null);
        return;
    }

    String[] items = new String[2];
    items[0] = "Chinese";
    items[1] = "English";

    selectItems("Select Language", items);

}

protected void selectItems(String title, String[] items) {

    ((MainActivity) context).runOnUiThread(new Runnable() {
        @Override
        public void run() {
            selectMenu(title, items);
        }
    });
}

private void selectMenu(String title, String[] items) {

    final byte[] choice = {0};

    AlertDialog.Builder builderDiaLog = new AlertDialog.Builder(context).setIcon(R.mipmap.ic_launcher).setTitle(title)
            .setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    choice[0] = (byte) i;
                }
            }).setPositiveButton("sure", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mEmvL3Module.responseEvent(ErrorCode.L3_ERR_SUCC, choice);
                }
            }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mEmvL3Module.responseEvent(ErrorCode.L3_ERR_CANCEL, choice);
                }
            });
    builderDiaLog.create().show();
}
```

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> Success:\**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC,*\* data);\
> Cancel:\**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_CANCEL,*\* data);

#### checkCredentials(byte type, byte\[ ] number);

Credentials checking

**only used for Unionpay PBOC**

**type :** Credential type

**number :** The Credential number you need to check

```java
@Override
public void checkCredentials(byte type, byte[] number) {
    com.nlutils.util.LoggerUtils.e(" checkCredentials:");
    String credentTials;
    switch (type) {
        case 0:
            credentTials = "ID CARD:" + BytesUtils.bytesToBinaryString(number);
            break;
        case 1:
            credentTials = "OFFICER:" + BytesUtils.bytesToBinaryString(number);
            break;
        case 2:
            credentTials = "PASSPORT:" + BytesUtils.bytesToBinaryString(number);
            break;
        case 3:
            credentTials = "ENTRY CARD:" + BytesUtils.bytesToBinaryString(number);
            break;
        case 4:
            credentTials = "TEMP IDCARD:" + BytesUtils.bytesToBinaryString(number);
            break;
        default:
            credentTials = "OTHER:" + BytesUtils.bytesToBinaryString(number);
            break;
    }
    userConfirm("CheckCredenTials", credentTials);
}

protected void userConfirm(String title, String cardNum) {

    ((MainActivity) context).runOnUiThread(new Runnable() {
        @Override
        public void run() {
            confirm(title, cardNum);
        }
    });
}

private void confirm(String title, String cardNum) {

    AlertDialog.Builder builderDiaLog = new AlertDialog.Builder(context).setIcon(R.mipmap.ic_launcher).setTitle(title)
            .setMessage(cardNum).setPositiveButton("sure", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mEmvL3Module.responseEvent(ErrorCode.L3_ERR_SUCC, null);
                }
            }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mEmvL3Module.responseEvent(ErrorCode.L3_ERR_CANCEL, null);
                }
            });
    builderDiaLog.create().show();
}
```

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> Success:\**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC, null);\*\*\
> Cancel:\**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_CANCEL, null);**

#### dek\_det(int type, byte\[ ] data);

Data Exchange

**Only used for mastercard contactless \[PAYPASS]**

**type :** 0x01-DEK, 0x02-DET

**data :** DEK sent command or DET response command

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> \**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC, null);*\*

#### onFinalSelect(int cardInterface, byte\[ ] aid);

Listener after Final Selection

This function used after Final Selection but before GPO We can update the Terminal/AID Configurations according to the different AID in current **Contact** transaction by using \*\*EmvL3Impl.setData(int, byte\[])**, For **contactless** trasaction you need use \*\*EmvL3Impl.responseEvent(int eventResult, byte\[] data)**.

**cardInterface :**\
`EmvL3Const.CardInterface.CONTACT`\
or\
`EmvL3Const.CardInterface.CONTACTLESS`

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> \**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC, null);*\*

#### getManualData();

Get Manual Data (Expiry date and CVV2, or other data you need)

**Used for manual transaction.**

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> \**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC, null);*\*

#### confirmPAN(String pan);

Display the card number to double check.

**Used for contact, MSR and manual transaction.**

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> \**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC, null);*\*

### CompleteTransactionListener

#### voiceReferrals();

Issuer Voice Referrals

An attended terminal shall either display the ‘CALL YOUR BANK’ message to the attendant, or shall alert the attendant in some other way that the Issuer has requested a voice referral. Appropriate application data, such as the Application PAN, should be displayed or printed to the attendant in order to perform the referral. Appropriate messages should be displayed requesting the attendant to enter data indicating that the transaction has been approved or declined as a result of the referral process.

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> \**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC, null);*\*

### APDUListener

#### getApduData(int cardInterface, byte\[ ] reqdata, int reqdatalen, byte\[ ] resdata, int resdatalen);

allowing applications to access APDU exchange data for use during APDU interaction between terminals and cards.

**Used for Contact/contactless transaction**

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> \**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC, null);*\*

### TransResultListener

#### transResult(int result, int errorCode);

Listener for get transresult and errorcode.

This function used after for get transaction result and errorcode.

| EmvL3Const.TransResult | Value | Description                                                                         |   |
| :--------------------- | :---- | :---------------------------------------------------------------------------------- | - |
| L3\_TXN\_OK            | 0     | Transaction is performing well.                                                     |   |
| L3\_TXN\_TERMINATE     | 1     | Transaction is terminated because of unexpected errors,                             |   |
| L3\_TXN\_TRY\_ANOTHER  | 2     | Try another interface (Contactless transaction).                                    |   |
| L3\_TXN\_DECLINE       | 3     | Transaction decline (Offline /Online)                                               |   |
| L3\_TXN\_APPROVED      | 4     | Transaction approved(Offline /Online)                                               |   |
| L3\_TXN\_ONLINE        | 5     | Transaction request online, you must send the transaction online for authorization. |   |

**PerfromTransactionListener :**

```java
@Override
public void transResult(int result, int errcode) {
    Log.d(getClass().getName(), String.format("PerfromTransactionListener::transResult():  %d, %d ", result, errcode));
    Log.d(getClass().getName(), mEmvL3Module.errorMessage(errcode));
    /**
     * Handle transaction result
     */
    switch (result) {
        case EmvL3Const.TransResult.L3_TXN_APPROVED:
            getKernelData(false);
            showToast("approve offline");
            endTransaction();
            break;
        case EmvL3Const.TransResult.L3_TXN_DECLINE:
            showToast("declined offline");
            getKernelData(false);
            endTransaction();
            break;
        case EmvL3Const.TransResult.L3_TXN_ONLINE:
            getKernelData(false);
            goOnline();
            break;
        default:
            if (result == EmvL3Const.TransResult.L3_TXN_TRY_ANOTHER) {
                showMessage("Try Another Interface");
            } else if (errcode == ErrorCode.L3_ERR_TIMEOUT) {
                showMessage("User Timeout");
            } else if (errcode == ErrorCode.L3_ERR_CANCEL || errcode == ErrorCode.EMV_ERR_CANCEL) {
                showMessage("Transaction Cancelled");
            } else {
                showMessage("Transaction Aborted");
            }
            getKernelData(true);
            showToast("transaction terminate");
            endTransaction();
            break;
    }
}
```

**CompleteTransactionListener :**

```java
@Override
public void transResult(int result, int errcode) {
    Log.d(getClass().getName(), String.format("CompleteTransactionListener::transResult():  %d, %d ", result, errcode));
    Log.d(getClass().getName(), mEmvL3Module.errorMessage(errcode));
    /**
     * Handle transaction result
     */
    switch (result) {
        case EmvL3Const.TransResult.L3_TXN_APPROVED:
            getKernelData(false);
            showToast("approve online");
            endTransaction();
            break;
        case EmvL3Const.TransResult.L3_TXN_DECLINE:
            getKernelData(false);
            showToast("decline online");
            endTransaction();
            break;
        default:
            getKernelData(true);
            if (result == EmvL3Const.TransResult.L3_TXN_TRY_ANOTHER) {
                showMessage("Try Another Interface");
            } else if (errcode == ErrorCode.L3_ERR_TIMEOUT) {
                showMessage("User Timeout");
            } else if (errcode == ErrorCode.L3_ERR_CANCEL || errcode == ErrorCode.EMV_ERR_CANCEL) {
                showMessage("Transaction Cancelled");
            } else {
                showMessage("Transaction Aborted");
            }
            showToast("Transaction terminate");
            endTransaction();
            break;

    }
}
```

> This listener does not need to call **responseEvent**.

### UIEventListener

#### uiEvent(int uiEventID, byte\[] uiEventData);

Display the message according uiEventID.(control the display effect of the device screen during various UI events.)

| EmvL3Const.UIEvent   | Value | Description                                                                                                                                     |   |
| :------------------- | :---- | :---------------------------------------------------------------------------------------------------------------------------------------------- | - |
| UI\_PRESENT\_CARD    | 0     | Reader is ready to read a cardthe \*\*first byte \*\*in 'UI Event Data' indicates the specified event \[L3\_UI\_CARD] (see `EmvL3Const.UICard`) |   |
| UI\_PROCESSING       | 1     | The Reader is processing the transaction                                                                                                        |   |
| UI\_CAPK\_LOAD\_FAIL | 2     | Load CAPK fails, checksum error.                                                                                                                |   |
| UI\_SEE\_PHONE       | 3     | The cardholder must interact with their mobile device to complete the transaction.                                                              |   |
| UI\_CHIP\_ERR\_RETRY | 5     | Reading Chip error, Retry 3 times before Fallback                                                                                               |   |
| UI\_PIN\_STATUS      | 6     | Used for external trasaction. You can get pinblock and ksn after entering pin.                                                                  |   |

```java
@Override
public void transResult(int result, int errcode) {
    Log.d(getClass().getName(), String.format("PerfromTransactionListener::transResult():  %d, %d ", result, errcode));
    Log.d(getClass().getName(), mEmvL3Module.errorMessage(errcode));
    /**
     * Handle transaction result
     */
    switch (result) {
        case EmvL3Const.TransResult.L3_TXN_APPROVED:
            getKernelData(false);
            showToast("approve offline");
            endTransaction();
            break;
        case EmvL3Const.TransResult.L3_TXN_DECLINE:
            showToast("declined offline");
            getKernelData(false);
            endTransaction();
            break;
        case EmvL3Const.TransResult.L3_TXN_ONLINE:
            getKernelData(false);
            goOnline();
            break;
        default:
            if (result == EmvL3Const.TransResult.L3_TXN_TRY_ANOTHER) {
                showMessage("Try Another Interface");
            } else if (errcode == ErrorCode.L3_ERR_TIMEOUT) {
                showMessage("User Timeout");
            } else if (errcode == ErrorCode.L3_ERR_CANCEL || errcode == ErrorCode.EMV_ERR_CANCEL) {
                showMessage("Transaction Cancelled");
            } else {
                showMessage("Transaction Aborted");
            }
            getKernelData(true);
            showToast("transaction terminate");
            endTransaction();
            break;
    }
}
```

**CompleteTransactionListener :**

```java
@Override
public void uiEvent(int i, byte[] bytes) {
    processUIEvent(i, bytes);
    mEmvL3Module.responseEvent(ErrorCode.L3_ERR_SUCC, null);
}

private void processUIEvent(int uiEvent, byte[] uiEventData) {
    Log.d(getClass().getName(), "ProcessUIEvent() called");

    switch (uiEvent) {
        /**
         * Prompt the customer to tap or insert or swipe the card.
         * The ui event data will be used to distinguish the type .
         */
        case EmvL3Const.UIEvent.UI_PRESENT_CARD:
            //Present card again.
            if (uiEventData[0] == EmvL3Const.UICard.UI_PRESENTCARD_AGAIN) {
                showMessage("PRESENT CARD AGAIN");
                break;
            }

            //Contact card fallback,prompting customer to swipe card
            if (uiEventData[0] == EmvL3Const.UICard.UI_FALLBACK_CT) {
                showMessage("CONTACT FALLBACK");
                break;
            }

            //Contactless card fallback,prompting customer to insert or swipe card
            if (uiEventData[0] == EmvL3Const.UICard.UI_FALLBACK_CLSS) {
                showMessage("CONTACTLESS FALLBACK");
                break;
            }

            //Swiped card which has chip,need to insert the card
            if (uiEventData[0] == EmvL3Const.UICard.UI_USE_CHIP) {
                showMessage("PLS USE CHIP");
                break;
            }

            //To show the current card interface type, like EmvL3Const.UICard.UI_STRIPE{@}
            if (uiEventData[0] != EmvL3Const.UICard.UI_KEYIN) {
                showMessage("TAP/INSERT/SWIP");
                break;
            }
            break;
        case EmvL3Const.UIEvent.UI_SEE_PHONE:
            // You can show that See Phone for Instructions
            showMessage("PLS SEE PHONE FOR STRUCTION");
            break;
        case EmvL3Const.UIEvent.UI_CHIP_ERR_RETRY:
            //The chip is error or card is reverse inserted
            showMessage("CHIP ERR ,PLS RETRY");
            break;
        case EmvL3Const.UIEvent.UI_PROCESSING:
            showMessage("Processing...");
            break;
        case EmvL3Const.UIEvent.UI_PIN_STATUS:
            showMessage("PIN STATUS");
            break;
    }
}
```

> After completing this listener,you need to call **responseEvent** to notify EMVL3 to process.\
> \**EmvL3Impl.responseEvent(ErrorCode.L3\_ERR\_SUCC, null);*\*