|
@@ -0,0 +1,749 @@
|
|
|
+package com.yijia.handpos.device.trade;
|
|
|
+
|
|
|
+import android.annotation.SuppressLint;
|
|
|
+import android.os.Handler;
|
|
|
+import android.os.Looper;
|
|
|
+import android.text.TextUtils;
|
|
|
+import android.util.Log;
|
|
|
+
|
|
|
+import com.pax.cocoa.tools.Convert;
|
|
|
+import com.pax.dal.ICardReaderHelper;
|
|
|
+import com.pax.dal.IPed;
|
|
|
+import com.pax.dal.entity.EPedMacMode;
|
|
|
+import com.pax.dal.entity.EPinBlockMode;
|
|
|
+import com.pax.dal.entity.EReaderType;
|
|
|
+import com.pax.dal.entity.PollingResult;
|
|
|
+import com.pax.dal.entity.PollingResult.EOperationType;
|
|
|
+import com.pax.dal.exceptions.PedDevException;
|
|
|
+import com.pax.eemv.entity.Config;
|
|
|
+import com.pax.eemv.entity.InputPBOCParam;
|
|
|
+import com.pax.eemv.entity.InputParam;
|
|
|
+import com.pax.eemv.entity.InputPayPassParam;
|
|
|
+import com.pax.eemv.entity.InputPayWaveParam;
|
|
|
+import com.pax.eemv.entity.ReaderParam;
|
|
|
+import com.pax.eemv.entity.TagPresent;
|
|
|
+import com.pax.eemv.enums.EChannelType;
|
|
|
+import com.pax.eemv.enums.EFlowType;
|
|
|
+import com.pax.eemv.enums.EKernelType;
|
|
|
+import com.pax.eemv.enums.ETransResult;
|
|
|
+import com.pax.eemv.exception.EmvException;
|
|
|
+import com.yijia.handpos.device.SysteHelper;
|
|
|
+import com.yijia.handpos.device.constants.FieldDefinition;
|
|
|
+import com.yijia.handpos.device.emv.EmvAid;
|
|
|
+import com.yijia.handpos.device.emv.EmvCapk;
|
|
|
+import com.yijia.handpos.device.emv.EmvContactlessListenerImpl;
|
|
|
+import com.yijia.handpos.device.emv.EmvDeviceListenerImpl;
|
|
|
+import com.yijia.handpos.device.emv.EmvListenerImpl;
|
|
|
+import com.yijia.handpos.device.emv.EmvTags;
|
|
|
+import com.yijia.handpos.device.utils.PanUtils;
|
|
|
+import com.yijia.handpos.device.utils.TrackUtils;
|
|
|
+
|
|
|
+import java.math.BigInteger;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+/**
|
|
|
+ * DeviceController
|
|
|
+ * 调用系统读卡,输密,计算MAC等
|
|
|
+ */
|
|
|
+public class DeviceController extends IDeviceController {
|
|
|
+
|
|
|
+ private final String LOG_TAG = "DeviceController";
|
|
|
+
|
|
|
+ // 刷卡
|
|
|
+ private static final int TYPE_MAG = 0;
|
|
|
+ // 插卡
|
|
|
+ private static final int TYPE_ICC = 1;
|
|
|
+ // 非接
|
|
|
+ private static final int TYPE_PICC = 2;
|
|
|
+
|
|
|
+
|
|
|
+ private TradeListener listener = null;
|
|
|
+ private EChannelType channelType = null;
|
|
|
+
|
|
|
+ // 金额
|
|
|
+ private String amount = "";
|
|
|
+
|
|
|
+ // 交易类型
|
|
|
+ private int transType = 0;
|
|
|
+ // 卡号
|
|
|
+ private String pan = "";
|
|
|
+
|
|
|
+ private final Handler handler = new Handler(Looper.getMainLooper());
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 消费
|
|
|
+ ***/
|
|
|
+ private final int CONSUME = 0x00;
|
|
|
+ /**
|
|
|
+ * 预授权交易
|
|
|
+ **/
|
|
|
+ private final int PRE_AUTH = 0x03;
|
|
|
+ /**
|
|
|
+ * 消费撤销或退货
|
|
|
+ **/
|
|
|
+ private final int CONSUME_CANCEL = 0x20;
|
|
|
+
|
|
|
+ private DeviceController() {
|
|
|
+ }
|
|
|
+
|
|
|
+ public static DeviceController getInstance() {
|
|
|
+ return Holder.INSTANCE;
|
|
|
+ }
|
|
|
+
|
|
|
+ static class Holder {
|
|
|
+ static DeviceController INSTANCE = new DeviceController();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String setDeviceType() {
|
|
|
+ Log.d(LOG_TAG, "DeviceController.setDeviceType");
|
|
|
+ String model = android.os.Build.MODEL;
|
|
|
+ return model;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void tradeInit(String transactionType, TradeListener listener) {
|
|
|
+ Log.d(LOG_TAG, "DeviceController.tradeInit >>> transactionType:" + transactionType);
|
|
|
+ this.listener = listener;
|
|
|
+ if (transactionType.equals(FieldDefinition.CONSUME)) {
|
|
|
+ this.transType = CONSUME;
|
|
|
+ } else if (transactionType.equals(FieldDefinition.CONSUME_CANCEL)) {
|
|
|
+ this.transType = CONSUME_CANCEL;
|
|
|
+ } else {
|
|
|
+ this.transType = PRE_AUTH;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void startTrade(String money, String time, String transNo) {
|
|
|
+ Log.d(LOG_TAG, "DeviceController.startTrade >>> money:"
|
|
|
+ + money + " time:" + time + " transNo:" + transNo);
|
|
|
+ this.amount = money;
|
|
|
+ listener.onStartSearchCard();
|
|
|
+ // 开始寻卡
|
|
|
+ new SearchCardThread().start();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void stopTrade() {
|
|
|
+ Log.d(LOG_TAG, "DeviceController.stopTrade");
|
|
|
+ ICardReaderHelper cardReaderHelper = SysteHelper.dal.getCardReaderHelper();
|
|
|
+ cardReaderHelper.stopPolling();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void getPinInput() {
|
|
|
+ Log.d(LOG_TAG, "DeviceController.getPinInput");
|
|
|
+ new Thread() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ try {
|
|
|
+ IPed ped = SysteHelper.getPed();
|
|
|
+ ped.showInputBox(true, "请输入密码");
|
|
|
+ ped.setIntervalTime(1, 1);
|
|
|
+ String cardNo = pan;
|
|
|
+ if (TextUtils.isEmpty(pan)) {
|
|
|
+ cardNo = "0000000000000000";
|
|
|
+ }
|
|
|
+
|
|
|
+ byte[] pindata = getPinBlock(PanUtils.getPanBlock(cardNo, PanUtils.EPanMode.X9_8_WITH_PAN), false);
|
|
|
+ if (pindata != null)
|
|
|
+ listener.onReturnPin(SysteHelper.convert.bcdToStr(pindata));
|
|
|
+ else {
|
|
|
+ listener.onReturnPin("");
|
|
|
+ }
|
|
|
+ } catch (PedDevException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ listener.onError(e.getErrCode(), e.getErrMsg());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }.start();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void getPinInput(final String cardNo) {
|
|
|
+ Log.d(LOG_TAG, "DeviceController.getPinInput >>> cardNo:" + cardNo);
|
|
|
+ new Thread() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ try {
|
|
|
+ IPed ped = SysteHelper.getPed();
|
|
|
+ ped.showInputBox(true, "请输入密码");
|
|
|
+ ped.setIntervalTime(1, 1);
|
|
|
+
|
|
|
+ byte[] pindata = getPinBlock(PanUtils.getPanBlock(cardNo, PanUtils.EPanMode.X9_8_WITH_PAN), false);
|
|
|
+ if (pindata != null)
|
|
|
+ listener.onReturnPin(SysteHelper.convert.bcdToStr(pindata));
|
|
|
+ else {
|
|
|
+ listener.onReturnPin("");
|
|
|
+ }
|
|
|
+ } catch (PedDevException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ listener.onError(e.getErrCode(), e.getErrMsg());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }.start();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public byte[] calcMac(byte[] data, int start, int end) {
|
|
|
+ Log.d(LOG_TAG, "DeviceController.calcMac >>> data:"
|
|
|
+ + SysteHelper.convert.bcdToStr(data) + " start:" + start + " end:" + end);
|
|
|
+ byte[] calData = new byte[end - start + 1];
|
|
|
+ System.arraycopy(calData, 0, data, start, calData.length);
|
|
|
+ return getCUPMac(calData);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 寻卡线程
|
|
|
+ class SearchCardThread extends Thread {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ try {
|
|
|
+ ICardReaderHelper cardReaderHelper = SysteHelper.dal.getCardReaderHelper();
|
|
|
+ PollingResult pollingResult = cardReaderHelper.polling(EReaderType.MAG_ICC_PICC, 60 * 1000, false);
|
|
|
+ cardReaderHelper.stopPolling();
|
|
|
+
|
|
|
+ if (pollingResult.getOperationType() == EOperationType.TIMEOUT) {
|
|
|
+ listener.onError(-1, "捡卡超时");
|
|
|
+ } else if (pollingResult.getOperationType() == EOperationType.CANCEL) {
|
|
|
+ listener.onStopSearchCard();
|
|
|
+ } else if (pollingResult.getOperationType() == EOperationType.PAUSE) {
|
|
|
+ //listener.onStopSearchCard();
|
|
|
+ } else {// 寻卡成功时调用
|
|
|
+ Log.d(LOG_TAG, "DeviceController.startTrade >>> " + pollingResult.getReaderType());
|
|
|
+
|
|
|
+ addCardInfoMap(FieldDefinition.MONEY, amount);
|
|
|
+ if (pollingResult.getReaderType().equals(EReaderType.ICC)) {
|
|
|
+ channelType = EChannelType.ICC;
|
|
|
+ listener.onFoundCard(TYPE_ICC);
|
|
|
+ addCardInfoMap(FieldDefinition.SWIPE_MODE, FieldDefinition.SWIPE_INSERT);
|
|
|
+ closeReadCard();
|
|
|
+ processPBOC();
|
|
|
+ } else if (pollingResult.getReaderType().equals(EReaderType.PICC)) {
|
|
|
+ channelType = EChannelType.PICC;
|
|
|
+ listener.onFoundCard(TYPE_PICC);
|
|
|
+ addCardInfoMap(FieldDefinition.SWIPE_MODE, FieldDefinition.SWIPE_NON_CONTACTED);
|
|
|
+ closeReadCard();
|
|
|
+ processPBOC();
|
|
|
+ } else {
|
|
|
+ listener.onFoundCard(TYPE_MAG);
|
|
|
+ String track2 = pollingResult.getTrack2();
|
|
|
+ String track3 = pollingResult.getTrack3();
|
|
|
+
|
|
|
+ // 有时刷卡成功,但没有磁道II,做一下防护
|
|
|
+ if (track2 == null || track2.length() == 0) {
|
|
|
+ handler.post(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ new SearchCardThread().start();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ pan = TrackUtils.getPan(track2);
|
|
|
+ addCardInfoMap(FieldDefinition.TRACK1, pollingResult.getTrack1());
|
|
|
+ addCardInfoMap(FieldDefinition.TRACK2, track2);
|
|
|
+ addCardInfoMap(FieldDefinition.TRACK3, track3);
|
|
|
+ addCardInfoMap(FieldDefinition.CARD_NO, pan);
|
|
|
+ addCardInfoMap(FieldDefinition.SWIPE_MODE, FieldDefinition.SWIPE_SWIPE);
|
|
|
+ addCardInfoMap(FieldDefinition.EXPIRT_DATE, TrackUtils.getExpDate(track2));
|
|
|
+ closeReadCard();
|
|
|
+
|
|
|
+ handler.post(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ listener.onReturnCardInfo(cardInfoMap);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 读卡失败,重试
|
|
|
+ handler.post(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ new SearchCardThread().start();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void closeReadCard() {
|
|
|
+ SysteHelper.dal.getCardReaderHelper().setIsPause(true);
|
|
|
+ SysteHelper.dal.getCardReaderHelper().stopPolling();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void processPBOC() {
|
|
|
+ Log.d(LOG_TAG, "DeviceController2.processPBOC >>> ");
|
|
|
+
|
|
|
+ try {
|
|
|
+ Log.d(LOG_TAG, "DeviceController.processPBOC >>> emvInit and set Emv Config");
|
|
|
+ SysteHelper.emv.emvInit();
|
|
|
+ setEmvConfig();
|
|
|
+
|
|
|
+ // paypass ,paywave设置参数
|
|
|
+ setPbocParam();
|
|
|
+ setPassParam();
|
|
|
+ setWaveParam();
|
|
|
+ setAEParam();
|
|
|
+
|
|
|
+ } catch (EmvException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ EmvAid emvAid = new EmvAid();
|
|
|
+ SysteHelper.emv.setAidParamList(emvAid.loadAllAid());
|
|
|
+ EmvCapk emvCapk = new EmvCapk();
|
|
|
+ SysteHelper.emv.setCapkList(emvCapk.loadAllCapk());
|
|
|
+ InputParam inputParam = toInputParam();
|
|
|
+
|
|
|
+ EmvListenerImpl emvListener = new EmvListenerImpl();
|
|
|
+ SysteHelper.emv.setListener(emvListener);
|
|
|
+
|
|
|
+ EmvContactlessListenerImpl contactlessListenerImpl = new EmvContactlessListenerImpl();
|
|
|
+ SysteHelper.emv.setContactlessListener(contactlessListenerImpl);
|
|
|
+
|
|
|
+ EmvDeviceListenerImpl deviceListenerImpl = new EmvDeviceListenerImpl();
|
|
|
+ SysteHelper.emv.setDeviceListener(deviceListenerImpl);
|
|
|
+
|
|
|
+ switch (transType) {
|
|
|
+ case CONSUME:
|
|
|
+ Log.w(LOG_TAG, "PbocStub.processPBOC >>> 消费");
|
|
|
+ if (channelType.equals(EChannelType.ICC)) {
|
|
|
+ inputParam.setFlowType(EFlowType.COMPLETE);
|
|
|
+ } else {
|
|
|
+ inputParam.setFlowType(EFlowType.QPBOC);
|
|
|
+ }
|
|
|
+ transProcess(inputParam);
|
|
|
+ break;
|
|
|
+ case PRE_AUTH:
|
|
|
+ Log.d(LOG_TAG, "PbocStub.processPBOC >>> 预授权交易");
|
|
|
+ inputParam.setIsForceOnline(true);
|
|
|
+ if (channelType.equals(EChannelType.ICC)) {
|
|
|
+ inputParam.setFlowType(EFlowType.COMPLETE);
|
|
|
+ } else {
|
|
|
+ inputParam.setFlowType(EFlowType.QPBOC);
|
|
|
+ }
|
|
|
+ transProcess(inputParam);
|
|
|
+ break;
|
|
|
+ case CONSUME_CANCEL:
|
|
|
+ Log.d(LOG_TAG, "PbocStub.processPBOC >>> 消费撤销或退货");
|
|
|
+ if (channelType.equals(EChannelType.ICC)) {
|
|
|
+ inputParam.setFlowType(EFlowType.COMPLETE);
|
|
|
+ } else {
|
|
|
+ inputParam.setFlowType(EFlowType.QPBOC);
|
|
|
+ }
|
|
|
+ transProcess(inputParam);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.processPBOC >>> 交易类型错误");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static byte[] getPinBlock(String panBlock, boolean supportBypass) throws PedDevException {
|
|
|
+ byte[] pinBlock;
|
|
|
+ String pinLen = "0,4,5,6";
|
|
|
+ IPed ped = SysteHelper.getPed();
|
|
|
+ while (true) {
|
|
|
+ pinBlock = ped.getPinBlock(SysteHelper.PIK_INDEX, pinLen, panBlock.getBytes(),
|
|
|
+ EPinBlockMode.ISO9564_0, 50 * 1000);
|
|
|
+ if (!supportBypass) { // 主要处理外置密码键盘凭密的时候,不输入密码直接点确认键;
|
|
|
+ if (pinBlock != null && pinBlock.length == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return pinBlock;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static byte[] getCUPMac(byte[] data) {
|
|
|
+ byte[] tmpbuf = new byte[8];
|
|
|
+ int len;
|
|
|
+ byte[] dataIn = new byte[data.length + tmpbuf.length];
|
|
|
+ len = data.length / tmpbuf.length + 1;
|
|
|
+ System.arraycopy(data, 0, dataIn, 0, data.length);
|
|
|
+ for (int i = 0; i < len; i++) {
|
|
|
+ for (int k = 0; k < tmpbuf.length; k++) {
|
|
|
+ tmpbuf[k] ^= dataIn[i * tmpbuf.length + k];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String beforeCalcMacData = SysteHelper.convert.bcdToStr(tmpbuf);
|
|
|
+ try {
|
|
|
+ byte[] mac = calcMac(beforeCalcMacData.getBytes());
|
|
|
+ return SysteHelper.convert.bcdToStr(mac).substring(0, 8).getBytes();
|
|
|
+ } catch (PedDevException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static byte[] calcMac(byte[] data) throws PedDevException {
|
|
|
+ IPed ped = SysteHelper.getPed();
|
|
|
+ return ped.getMac(SysteHelper.MAK_INDEX, data, EPedMacMode.MODE_00);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void transProcess(InputParam inputParam) {
|
|
|
+ ETransResult result = null;
|
|
|
+ Log.e(LOG_TAG, "DeviceController.transProcess >>> transProcess: ");
|
|
|
+ try {
|
|
|
+ result = SysteHelper.emv.emvProcess(inputParam);
|
|
|
+ } catch (EmvException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ Log.e(LOG_TAG, "DeviceController.transProcess >>> PaxEmvException: code" + e.getErrCode());
|
|
|
+ Log.e(LOG_TAG, "DeviceController.transProcess >>> PaxEmvException: getErrMsg" + e.getErrMsg());
|
|
|
+ listener.onError(e.getErrCode(), e.getErrMsg());
|
|
|
+ return;
|
|
|
+ } catch (Exception e) {
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> Exception");
|
|
|
+ }
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> emv end-------");
|
|
|
+ Log.d(LOG_TAG, "DeviceController2.transProcess >>> result:" + result);
|
|
|
+
|
|
|
+
|
|
|
+ // 卡号
|
|
|
+ String pan = "";
|
|
|
+ String track = "";
|
|
|
+ byte[] track2 = SysteHelper.emv.getTlv(0x57);
|
|
|
+ if (track2 != null && track2.length > 0) {
|
|
|
+ track = Convert.bcdBytesToStr(track2);
|
|
|
+ track = track.split("F")[0];
|
|
|
+ pan = TrackUtils.getPan(track);
|
|
|
+ this.pan = pan;
|
|
|
+ }
|
|
|
+ addCardInfoMap(FieldDefinition.CARD_NO, pan);
|
|
|
+
|
|
|
+ // 有效期
|
|
|
+ byte[] expDate = SysteHelper.emv.getTlv(0x5f24);
|
|
|
+ if (expDate != null && expDate.length > 0) {
|
|
|
+ String temp = SysteHelper.convert.bcdToStr(expDate);
|
|
|
+ addCardInfoMap(FieldDefinition.EXPIRT_DATE, temp.substring(0, 4));
|
|
|
+ }
|
|
|
+ // 获取卡片序列号
|
|
|
+ byte[] cardSeq = SysteHelper.emv.getTlv(0x5f34);
|
|
|
+ if (cardSeq != null && cardSeq.length > 0) {
|
|
|
+ addCardInfoMap(FieldDefinition.SERIAL, Convert.bcdBytesToStr(cardSeq));
|
|
|
+ } else {
|
|
|
+ addCardInfoMap(FieldDefinition.SERIAL, "00");
|
|
|
+ }
|
|
|
+ addCardInfoMap(FieldDefinition.TRACK2, track);
|
|
|
+ addCardInfoMap(FieldDefinition.ICDATA, EmvTags.getARQCTLV());
|
|
|
+
|
|
|
+ saveTvrTsi();
|
|
|
+
|
|
|
+ switch (result) {
|
|
|
+ case ONLINE_APPROVED:
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> emvPorcess result:PAX_EMV_ONLINE_APPROVED");
|
|
|
+ listener.onReturnCardInfo(cardInfoMap);
|
|
|
+ break;
|
|
|
+ case OFFLINE_APPROVED:
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> emvPorcess result:PAX_EMV_OFFLINE_APPROVED");
|
|
|
+ listener.onReturnCardInfo(cardInfoMap);
|
|
|
+ break;
|
|
|
+ case ARQC:
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> emvPorcess result:PAX_EMV_ARQC");
|
|
|
+ listener.onReturnCardInfo(cardInfoMap);
|
|
|
+ break;
|
|
|
+ case SIMPLE_FLOW_END:
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> emvPorcess result:PAX_EMV_SIMPLE_FLOW_END");
|
|
|
+ listener.onReturnCardInfo(cardInfoMap);
|
|
|
+ break;
|
|
|
+ case ONLINE_DENIED:
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> emvPorcess result:PAX_EMV_ONLINE_DENIED");
|
|
|
+ listener.onError(ETransResult.ONLINE_DENIED.getTransResult(), "联机拒绝");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case OFFLINE_DENIED:
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> emvPorcess result:PAX_EMV_OFFLINE_DENIED");
|
|
|
+ listener.onError(ETransResult.OFFLINE_DENIED.getTransResult(), "脱机拒绝");
|
|
|
+ break;
|
|
|
+ case ONLINE_CARD_DENIED:// 卡片的事
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> emvPorcess result:PAX_EMV_ONLINE_CARD_DENIED");
|
|
|
+ //listener.onError(ETransResult.ONLINE_CARD_DENIED.getTransResult(), "联机允许,卡片拒绝");
|
|
|
+ listener.onReturnCardInfo(cardInfoMap);
|
|
|
+ break;
|
|
|
+ case ABORT_TERMINATED:
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> emvPorcess result:PAX_EMV_ABORT_TERMINATED");
|
|
|
+ listener.onError(ETransResult.ABORT_TERMINATED.getTransResult(), "终端终止");
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ Log.e(LOG_TAG, "DeviceController2.transProcess >>> emvPorcess result:PAX_EMV_default");
|
|
|
+ listener.onError(ETransResult.ABORT_TERMINATED.getTransResult(), "终端终止");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void saveTvrTsi() {
|
|
|
+ // ARQC
|
|
|
+ byte[] tc = SysteHelper.emv.getTlv(0x9f26);
|
|
|
+ if (tc != null && tc.length > 0) {
|
|
|
+ Log.e("TAG", "ARQC:" + SysteHelper.convert.bcdToStr(tc));
|
|
|
+ }
|
|
|
+
|
|
|
+ // AID
|
|
|
+ byte[] aid = SysteHelper.emv.getTlv(0x4f);
|
|
|
+ if (aid != null && aid.length > 0) {
|
|
|
+ Log.e("TAG", "aid:" + SysteHelper.convert.bcdToStr(aid));
|
|
|
+ }
|
|
|
+
|
|
|
+ // CVM
|
|
|
+ byte[] CVM = SysteHelper.emv.getTlv(0x9F34);
|
|
|
+ if (CVM != null && CVM.length > 0) {
|
|
|
+ Log.e("TAG", "CVM:" + SysteHelper.convert.bcdToStr(CVM));
|
|
|
+ }
|
|
|
+
|
|
|
+ // ATC
|
|
|
+ byte[] atc = SysteHelper.emv.getTlv(0x9f36);
|
|
|
+ if (atc != null && atc.length > 0) {
|
|
|
+ Log.e("TAG", "atc:" + SysteHelper.convert.bcdToStr(atc));
|
|
|
+ }
|
|
|
+
|
|
|
+ // UNPR_NO
|
|
|
+ byte[] UNPR_NO = SysteHelper.emv.getTlv(0x9F37);
|
|
|
+ if (UNPR_NO != null && UNPR_NO.length > 0) {
|
|
|
+ Log.e("TAG", "UNPR_NO:" + SysteHelper.convert.bcdToStr(UNPR_NO));
|
|
|
+ }
|
|
|
+
|
|
|
+ // AIP
|
|
|
+ byte[] AIP = SysteHelper.emv.getTlv(0x82);
|
|
|
+ if (AIP != null && AIP.length > 0) {
|
|
|
+ Log.e("TAG", "AIP:" + SysteHelper.convert.bcdToStr(AIP));
|
|
|
+ }
|
|
|
+
|
|
|
+ // termCap
|
|
|
+ byte[] termCap = SysteHelper.emv.getTlv(0x9F33);
|
|
|
+ if (termCap != null && termCap.length > 0) {
|
|
|
+ Log.e("TAG", "termCap:" + SysteHelper.convert.bcdToStr(termCap));
|
|
|
+ }
|
|
|
+
|
|
|
+ // IAD
|
|
|
+ byte[] IAD = SysteHelper.emv.getTlv(0x9F10);
|
|
|
+ if (IAD != null && IAD.length > 0) {
|
|
|
+ Log.e("TAG", "IAD:" + SysteHelper.convert.bcdToStr(IAD));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // TVR
|
|
|
+ byte[] tvr = SysteHelper.emv.getTlv(0x95);
|
|
|
+ if (tvr != null && tvr.length > 0) {
|
|
|
+ Log.e("TAG", "TVR:" + SysteHelper.convert.bcdToStr(tvr));
|
|
|
+ }
|
|
|
+
|
|
|
+ // TSI
|
|
|
+ byte[] tsi = SysteHelper.emv.getTlv(0x9b);
|
|
|
+ if (tsi != null && tsi.length > 0) {
|
|
|
+ Log.e("TAG", "tsi:" + SysteHelper.convert.bcdToStr(tsi));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressLint({"SimpleDateFormat", "DefaultLocale"})
|
|
|
+ private InputParam toInputParam() {
|
|
|
+ Log.d(LOG_TAG, "DeviceController2.toInputParam >>> ");
|
|
|
+ InputParam inputParam = new InputParam();
|
|
|
+
|
|
|
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
|
|
|
+ Date date = new Date(System.currentTimeMillis());
|
|
|
+ String time = dateFormat.format(date);
|
|
|
+ Log.d(LOG_TAG, "DeviceController2.toInputParam >>> time=" + time);
|
|
|
+ if (time != null) {
|
|
|
+ inputParam.setTransDate(time.substring(0, 8));
|
|
|
+ inputParam.setTransTime(time.substring(8, 14));
|
|
|
+ }
|
|
|
+ inputParam.setChannelType(channelType);
|
|
|
+ inputParam.setIsNeedInputAmounts(true);
|
|
|
+ inputParam.setAmount(String.format("%012d", Long.parseLong(amount)));
|
|
|
+ inputParam.setCashBackAmount("0");
|
|
|
+ inputParam.setTag9CValue((byte) transType);// Tag9c的值
|
|
|
+ inputParam.setIsSupportSM(true);// 是否支持国密算法
|
|
|
+ inputParam.setIsCardAuth(true);// 是否执行脱机数据认证 0:不执行 ,1执行
|
|
|
+ inputParam.setIsForceOnline(true);// 是否强制联机
|
|
|
+ inputParam.setIsSupportEC(false);// 是否支持电子现金交易,需要根据实际情况设置,默认false
|
|
|
+ inputParam.setIsSupportCvm(true);// 是否支持CVM 非指定账户圈存、电子现金圈存 不执行
|
|
|
+ inputParam.setTransTraceNo(String.format("%06d", 0));
|
|
|
+
|
|
|
+ return inputParam;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setEmvConfig() throws EmvException {
|
|
|
+ Config cfg = SysteHelper.emv.getConfig();
|
|
|
+ cfg.setCapability(new byte[]{(byte) 0xE0, (byte) 0xF8, (byte) 0xC8});
|
|
|
+ cfg.setCountryCode(new byte[]{0x01, 0x56});
|
|
|
+ cfg.setExCapability(new byte[]{(byte) 0xe0, 0x00, (byte) 0xF0, (byte) 0xA0, 0x01});
|
|
|
+ cfg.setForceOnline((byte) 0);
|
|
|
+ cfg.setGetDataPIN((byte) 1);
|
|
|
+ cfg.setMerchCateCode(new byte[]{0x00, 0x00});
|
|
|
+ cfg.setReferCurrCode(new byte[]{0x01, 0x56});
|
|
|
+ cfg.setReferCurrCon(1000);
|
|
|
+ cfg.setReferCurrExp((byte) 0x02);
|
|
|
+ cfg.setSurportPSESel((byte) 1);
|
|
|
+ cfg.setTermType((byte) 0x22);
|
|
|
+ cfg.setTransCurrCode(new byte[]{0x01, 0x56});
|
|
|
+ cfg.setTransCurrExp((byte) 0x02);
|
|
|
+ cfg.setTransType((byte) 0x02);
|
|
|
+ cfg.setTermId("00000000");
|
|
|
+ cfg.setMerchId("000000000000000");
|
|
|
+ cfg.setMerchName("");// 读取商户名称
|
|
|
+ cfg.setTermAIP(new byte[]{0x7c, 0x00});
|
|
|
+ cfg.setBypassPin((byte) 1); // 输密码支持bypass
|
|
|
+ SysteHelper.emv.setConfig(cfg);
|
|
|
+ }
|
|
|
+
|
|
|
+ private int setPbocParam() {
|
|
|
+
|
|
|
+ ReaderParam readerParam = SysteHelper.emv.getReaderParam(EKernelType.PBOC);
|
|
|
+ if (readerParam != null) {
|
|
|
+
|
|
|
+ readerParam.setMerchCatCode(new byte[]{0x00, 0x00});
|
|
|
+ readerParam.setTermCap(new byte[]{(byte) 0xE0, (byte) 0xe1, (byte) 0xc8});
|
|
|
+ readerParam.setTermCapAd(new byte[]{(byte) 0xe0, 0x00, (byte) 0xf0, (byte) 0xa0, 0x01});
|
|
|
+ readerParam.setTermType((byte) 0x22);
|
|
|
+ readerParam.setTermCountryCode(new byte[]{0x01, 0x56});
|
|
|
+ readerParam.setTermRefCurCode(new byte[]{0x01, 0x56});
|
|
|
+ readerParam.setTermTransCur(new byte[]{0x01, 0x56});
|
|
|
+
|
|
|
+ SysteHelper.emv.setReaderParam(EKernelType.PBOC, readerParam);
|
|
|
+ }
|
|
|
+
|
|
|
+ InputPBOCParam pbocParam = new InputPBOCParam();
|
|
|
+
|
|
|
+ pbocParam.setTermFlmt(100000);
|
|
|
+ pbocParam.setTTQ(new byte[]{0x36, 0x00, 0x00, 0x00});
|
|
|
+
|
|
|
+ SysteHelper.emv.contactlessParameterSetPBOC(pbocParam);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int setPassParam() {
|
|
|
+
|
|
|
+ ReaderParam readerParam = SysteHelper.emv.getReaderParam(EKernelType.MC);
|
|
|
+ if (readerParam != null) {
|
|
|
+
|
|
|
+ readerParam.setReferCurrCon(1000);
|
|
|
+ readerParam.setMerchNameLoc("PAX EMV LIBRARY".getBytes());
|
|
|
+ readerParam.setMerchCatCode(new byte[]{0x00, 0x01});
|
|
|
+ readerParam.setAcquierId(new byte[]{0x00, 0x00, 0x00, 0x12, 0x34, 0x56});
|
|
|
+ readerParam.setTermType((byte) 0x22);
|
|
|
+ readerParam.setTermCap(new byte[]{(byte) 0xE8, (byte) 0x20, (byte) 0xc8});
|
|
|
+ readerParam.setTermCapAd(new byte[]{(byte) 0xFF, 0x00, (byte) 0x10, (byte) 0x30, 0x01});
|
|
|
+ readerParam.setTermCountryCode(new byte[]{0x01, 0x56});
|
|
|
+ readerParam.setTermRefCurCode(new byte[]{0x01, 0x56});
|
|
|
+ readerParam.setTermTransCur(new byte[]{0x01, 0x56});
|
|
|
+ readerParam.setTermTransCurExp((byte) 0x02);
|
|
|
+
|
|
|
+ SysteHelper.emv.setReaderParam(EKernelType.MC, readerParam);
|
|
|
+ }
|
|
|
+
|
|
|
+ InputPayPassParam passParam = new InputPayPassParam();
|
|
|
+
|
|
|
+ List<TagPresent> tpList = new ArrayList<TagPresent>();
|
|
|
+ TagPresent tp = null;
|
|
|
+
|
|
|
+ tp = new TagPresent();
|
|
|
+ tp.setTag(new BigInteger(new byte[]{(byte) 0xdf, (byte) 0x81, 0x04}).intValue());
|
|
|
+ tp.setPresent((byte) 0);
|
|
|
+ tpList.add(tp);
|
|
|
+
|
|
|
+ tp = new TagPresent();
|
|
|
+ tp.setTag(new BigInteger(new byte[]{(byte) 0xdf, (byte) 0x81, 0x05}).intValue());
|
|
|
+ tp.setPresent((byte) 0);
|
|
|
+ tpList.add(tp);
|
|
|
+
|
|
|
+ tp = new TagPresent();
|
|
|
+ tp.setTag(new BigInteger(new byte[]{(byte) 0xdf, (byte) 0x81, 0x2d}).intValue());
|
|
|
+ tp.setPresent((byte) 0);
|
|
|
+ tpList.add(tp);
|
|
|
+
|
|
|
+ tp = new TagPresent();
|
|
|
+ tp.setTag(new BigInteger(new byte[]{(byte) 0x9F, 0x5C}).intValue());
|
|
|
+ tp.setPresent((byte) 0);
|
|
|
+ tpList.add(tp);
|
|
|
+
|
|
|
+ tp = new TagPresent();
|
|
|
+ tp.setTag(new BigInteger(new byte[]{(byte) 0xdf, (byte) 0x81, 0x10}).intValue());
|
|
|
+ tp.setPresent((byte) 0);
|
|
|
+ tpList.add(tp);
|
|
|
+
|
|
|
+ tp = new TagPresent();
|
|
|
+ tp.setTag(new BigInteger(new byte[]{(byte) 0xdf, (byte) 0x81, 0x12}).intValue());
|
|
|
+ tp.setPresent((byte) 0);
|
|
|
+ tpList.add(tp);
|
|
|
+
|
|
|
+ tp = new TagPresent();
|
|
|
+ tp.setTag(new BigInteger(new byte[]{(byte) 0xdf, (byte) 0x81, 0x02}).intValue());
|
|
|
+ tp.setPresent((byte) 0);
|
|
|
+ tpList.add(tp);
|
|
|
+
|
|
|
+ tp = new TagPresent();
|
|
|
+ tp.setTag(new BigInteger(new byte[]{(byte) 0xdf, (byte) 0x81, 0x03}).intValue());
|
|
|
+ tp.setPresent((byte) 0);
|
|
|
+ tpList.add(tp);
|
|
|
+
|
|
|
+ tp = new TagPresent();
|
|
|
+ tp.setTag(new BigInteger(new byte[]{(byte) 0xdf, (byte) 0x81, 0x27}).intValue());
|
|
|
+ tp.setPresent((byte) 0);
|
|
|
+ tpList.add(tp);
|
|
|
+
|
|
|
+ tp = new TagPresent();
|
|
|
+ tp.setTag(new BigInteger(new byte[]{(byte) 0xdf, (byte) 0x81, 0x30}).intValue());
|
|
|
+ tp.setPresent((byte) 0);
|
|
|
+ tpList.add(tp);
|
|
|
+
|
|
|
+ passParam.setTagPresents(tpList);
|
|
|
+ SysteHelper.emv.contactlessParameterSetPass(passParam);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int setWaveParam() {
|
|
|
+
|
|
|
+ ReaderParam readerParam = SysteHelper.emv.getReaderParam(EKernelType.VIS);
|
|
|
+ if (readerParam != null) {
|
|
|
+
|
|
|
+ readerParam.setReferCurrCon(1000);
|
|
|
+ readerParam.setMerchNameLoc("PAX EMV LIBRARY".getBytes());
|
|
|
+ readerParam.setMerchCatCode(new byte[]{0x00, 0x01});
|
|
|
+ readerParam.setAcquierId(new byte[]{0x00, 0x00, 0x00, 0x12, 0x34, 0x56});
|
|
|
+ readerParam.setTermType((byte) 0x22);
|
|
|
+ readerParam.setTermCap(new byte[]{(byte) 0xE8, (byte) 0x20, (byte) 0xc8});
|
|
|
+ readerParam.setTermCapAd(new byte[]{(byte) 0xFF, 0x00, (byte) 0x10, (byte) 0x30, 0x01});
|
|
|
+ readerParam.setTermCountryCode(new byte[]{0x01, 0x56});
|
|
|
+ readerParam.setTermRefCurCode(new byte[]{0x01, 0x56});
|
|
|
+ readerParam.setTermTransCur(new byte[]{0x01, 0x56});
|
|
|
+ readerParam.setTermTransCurExp((byte) 0x02);
|
|
|
+
|
|
|
+ SysteHelper.emv.setReaderParam(EKernelType.VIS, readerParam);
|
|
|
+ }
|
|
|
+
|
|
|
+ InputPayWaveParam waveParam = new InputPayWaveParam();
|
|
|
+ waveParam.setTermFlmt(100000);
|
|
|
+ waveParam.setDomesticOnly((byte) 0x00);
|
|
|
+ waveParam.setEnDDAVerNo((byte) 0x00);
|
|
|
+ waveParam.setTTQ(new byte[]{0x26, 0x00, 0x00, 0x00});
|
|
|
+ waveParam.setCvmReq(new byte[]{0x00});
|
|
|
+ SysteHelper.emv.contactlessParameterSetWave(waveParam);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int setAEParam() {
|
|
|
+ ReaderParam readerParam = SysteHelper.emv.getReaderParam(EKernelType.PBOC);
|
|
|
+ if (readerParam != null) {
|
|
|
+ readerParam.setMerchCatCode(new byte[]{0x00, 0x00});
|
|
|
+ readerParam.setTermCap(new byte[]{(byte) 0xE0, (byte) 0xe1, (byte) 0xc8});
|
|
|
+ readerParam.setTermCapAd(new byte[]{(byte) 0xe0, 0x00, (byte) 0xf0, (byte) 0xa0, 0x01});
|
|
|
+ readerParam.setTermType((byte) 0x22);
|
|
|
+ readerParam.setTermCountryCode(new byte[]{0x01, 0x56});
|
|
|
+ readerParam.setTermRefCurCode(new byte[]{0x01, 0x56});
|
|
|
+ readerParam.setTermTransCur(new byte[]{0x01, 0x56});
|
|
|
+ SysteHelper.emv.setReaderParam(EKernelType.AE, readerParam);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|