Online documentation (Javadoc)
The online API documentation can be found at the following address: https://fbe-host.ca/agnos/agnos-2.0.0-javadoc/index.html .
Basic transaction
A basic OLA transaction includes the following steps:
OLA classes instantiation (once at startup)
private final Ola ola; private final OlaEmv emv; private final OlaContactless contactless; this.ola = Ola.getInstance(); this.contactless = OlaContactless.getInstance(); this.emv = OlaEmv.getInstance();
OLA component initialisation (once at startup)
/** * Configures OLA layer (key files paths, trace, etc...) */ private void olaConfig() { final byte[] path = {(byte)0xdf, 0x01, 28}; final String pathValue = "/data/data/ca.amadis.tester/"; final byte[] cakeys = {(byte)0xdf, 0x02, 34}; final String cakeysValue = "/data/data/ca.amadis.tester/CAKeys"; final byte[] crl = {(byte)0xdf, 0x03, 31}; final String crlValue = "/data/data/ca.amadis.tester/CRL"; final byte[] efl = {(byte)0xdf, 0x04, 31}; final String eflValue = "/data/data/ca.amadis.tester/EFL"; final byte[] pcsc = {(byte)0xdf, 0x05, 0x00}; // pcsc not used final byte[] lang = {(byte)0xdf, 0x06, 0x00}; // lang not used final byte[] runtimeParams = {(byte)0xdf, 0x07, 0x07, 0x00, 0x0F, 0x04, 0x0F, 0x0A, 0x00, 0x01}; final byte[] traceLevel = {(byte)0xdf, 0x08, 0x01, 0x05}; final byte[] pollingTechno = {(byte)0xdf, 0x10, 0x01, 0x04}; // Contactless only final byte[] sredMode = {(byte)0xdf, 0x17, 0x01, 0x01}; // SRED mode active try { ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(path); out.write(pathValue.getBytes()); out.write(cakeys); out.write(cakeysValue.getBytes()); out.write(crl); out.write(crlValue.getBytes()); out.write(efl); out.write(eflValue.getBytes()); out.write(pcsc); out.write(lang); out.write(runtimeParams); out.write(traceLevel); out.write(pollingTechno); out.write(sredMode); byte[] tlv = out.toByteArray(); ola.initializeAtStartUp(tlv); } catch (IOException e) { } }
AID configuration (once at startup)
private void terminalContactlessConfig() { contactless.flushAIDSupported(); for (OLAConfig.ContactlessCfg config : OLAConfig.contactlessCfg) { contactless.addAIDSupported( config.aid, config.partial, (byte)config.kernelId, config.additionalData ); } contactless.commitSupportedAIDs(); }
Keys configuration (once at startup)
private void terminalPublicKeyConfig() { publicKey.flush(); byte rid[] = {(byte)0xA0, 0x00, 0x00, 0x00, 0x03}; byte idx = (byte)0x92; byte modulus[] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}; byte exponentValue[] = {0x03}; byte expirDate[] = {0x22, 0x12, 0x31}; Holders.SingleObjectHolder<Boolean> wasMaxReached_holder = new Holders.SingleObjectHolder<Boolean>(false); OlaPublicKey.PublicKeyData key = publicKey.new PublicKeyData(rid, idx, modulus, exponentValue, expirDate); publicKey.add(key, null, wasMaxReached_holder); publicKey.commit(); }
Transaction related data (before each transaction)
private void txnSetTransactionRelatedData() { emv.setTag(OlaTag.TRANSACTION_DATE, new byte[]{0x20, 0x10, 0x28}); // 9A emv.setTag(OlaTag.TRANSACTION_TIME, new byte[]{0x12, 0x00, 0x00}); // 9F21 emv.setTag(OlaTag.AMOUNT_AUTHORISED, new byte[]{0x00, 0x00, 0x00, 0x00, 0x01, 0x50}); // 9F02 emv.setTag(OlaTag.AMOUNT_OTHER_NUM, new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x50}); // 9F03 emv.setTag(OlaTag.TRANSACTION_CURRENCY_CODE, new byte[]{0x08, 0x40}); // 5F2A emv.setTag(OlaTag.TRANSACTION_CURRENCY_EXPONENT, new byte[]{0x02}); // 5F36 emv.setTag(OlaTag.TRANSACTION_TYPE, new byte[]{0x00}); // 9C /* * Other possible tags to set here: * Account Type (5F57) * Transaction Category Code (9F53) * * All other tags must be set through the combinations! */ }
Preprocessing
private OlaError txnPreProcess() { OlaError ret = contactless.preprocess(); if (ret != OlaError.OLA_OK) { Log.e("OLA-TESTER", "contactless pre-process failed"); } return ret; }
Card detection
private short txnGetCard() { Log.d("OLA-TESTER", "PRESENT CARD"); int foundTechnos = dev.technoPolling(60000); l("Result of foundTechnos: "+ foundTechnos); if (foundTechnos==4) { return clcEMV_CARD; //TODO remove hard-coding } else { return 0; } }
Do transaction
private OlaError doTransaction() { SingleObjectHolder<Integer> nbCandidatesHolder = new SingleObjectHolder<Integer>(); OlaError ret = contactless.buildCandidateList(nbCandidatesHolder); if (ret != OlaError.OLA_OK) { showOutcome(ret); } /* * For now, finalSelectCandidate is useless. Everything from preprocessing to card * processing is done in "buildCandidateList". This will change as soon as exit conditions * are availble in OLA 2.x, hence we keep all the function calls here */ SingleObjectHolder<Byte> kernel_id_holder = new SingleObjectHolder<Byte>(); ret = contactless.finalSelectCandidate(1, kernel_id_holder); if (ret != OlaError.OLA_OK) { showOutcome(ret); } ret = contactless.doTransaction(); showOutcome(ret); if (ret == OlaError.OLA_OK) { SingleObjectHolder<byte[]> bytesHolder = new SingleObjectHolder<byte[]>(); for (int olaTag : batch) { OlaError result = emv.getTag(olaTag, bytesHolder); if (result == OlaError.OLA_OK) l("Result for ola_contactless_get_tag(): "+result+" => "+ Arrays.toString(bytesHolder.get())); else l("Result for ola_contactless_get_tag(): "+result+" => tag missing"); } } Log.d("OLA-TESTER", "**** REMOVE CARD **** "); return ret; }