This commit is contained in:
moon 2026-03-12 14:58:04 +06:30
commit 3e4b3e88a4
4 changed files with 137 additions and 206 deletions

View File

@ -244,7 +244,7 @@ public class EmvTransactionFragment extends DataBindingFragment {
isCardTaped("Please try again",new CardDetectCallback() { isCardTaped("Please try again",new CardDetectCallback() {
@Override @Override
public void onComplete() { public void onComplete() {
sharedViewModel.setIsSeePhone(true); sharedViewModel.setIsSeePhone(false);
navigateToCheckCard(); navigateToCheckCard();
} }
}); });

View File

@ -413,6 +413,7 @@ public class EmvParamHelper {
aidV2.setTransType("FF"); aidV2.setTransType("FF");
aidV2.setOnlinePinCap(1); aidV2.setOnlinePinCap(1);
aidV2.setAsi(1); aidV2.setAsi(1);
aidV2.setThreshold(99);
if (!(contactAid.getCvmLimit() < 0)) { if (!(contactAid.getCvmLimit() < 0)) {
aidV2.setContactlessCvmLimit(contactAid.getCvmLimit()); aidV2.setContactlessCvmLimit(contactAid.getCvmLimit());

View File

@ -6,6 +6,7 @@ import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -260,8 +261,8 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
unionPayTransDataEntity.setSupportCDCVM(true); unionPayTransDataEntity.setSupportCDCVM(true);
//if support QPS, please enable below lines //if support QPS, please enable below lines
unionPayTransDataEntity.setSupportContactlessQps(true); unionPayTransDataEntity.setSupportContactlessQps(true);
// unionPayTransDataEntity.setContactlessQpsLimit("000090000000");
unionPayTransDataEntity.setContactlessQpsLimit("000000030000"); unionPayTransDataEntity.setContactlessQpsLimit("000000030000");
transData.setUnionPayTransDataEntity(unionPayTransDataEntity); transData.setUnionPayTransDataEntity(unionPayTransDataEntity);
@ -426,213 +427,142 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
initKeyboard(isOnlinePin == 1); initKeyboard(isOnlinePin == 1);
} }
private void initKeyboard(boolean isOnlinePin) { private void initKeyboard(boolean isOnlinePin) {
LogUtil.d(TAG, "init keyboard!");
LogUtil.d(TAG,"init keyboard!");
pinPadVisibility.setValue(0); pinPadVisibility.setValue(0);
LogUtil.d(TAG,"pin pad is visible now!"); LogUtil.d(TAG, "pin pad is visible now!");
customPinPadKeyboard.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
customPinPadKeyboard.getViewTreeObserver().removeOnGlobalLayoutListener(this);
LogUtil.d(TAG,"inside the global layout!"); // Check if the view is already laid out
PinpadLayoutEntity pinpadLayout = new PinpadLayoutEntity(); if (customPinPadKeyboard.getWidth() > 0 && customPinPadKeyboard.getHeight() > 0) {
int[] location = new int[2]; // View already laid out call setup directly
Rect r; setupPinPadLayout(isOnlinePin);
customPinPadKeyboard.getKey_1().getLocationOnScreen(location); } else {
r = new Rect(); // View not yet laid out wait for layout
r.left = location[0]; customPinPadKeyboard.getViewTreeObserver().addOnGlobalLayoutListener(
r.top = location[1]; new ViewTreeObserver.OnGlobalLayoutListener() {
r.right = customPinPadKeyboard.getKey_1().getWidth() + r.left; @Override
r.bottom = customPinPadKeyboard.getKey_1().getHeight() + r.top; public void onGlobalLayout() {
pinpadLayout.setKey1(r); if (customPinPadKeyboard.getWidth() > 0 && customPinPadKeyboard.getHeight() > 0) {
customPinPadKeyboard.getViewTreeObserver().removeOnGlobalLayoutListener(this);
customPinPadKeyboard.getKey_2().getLocationOnScreen(location); setupPinPadLayout(isOnlinePin);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_2().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_2().getHeight() + r.top;
pinpadLayout.setKey2(r);
customPinPadKeyboard.getKey_3().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_3().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_3().getHeight() + r.top;
pinpadLayout.setKey3(r);
customPinPadKeyboard.getKey_4().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_4().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_4().getHeight() + r.top;
pinpadLayout.setKey4(r);
customPinPadKeyboard.getKey_5().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_5().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_5().getHeight() + r.top;
pinpadLayout.setKey5(r);
customPinPadKeyboard.getKey_6().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_6().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_6().getHeight() + r.top;
pinpadLayout.setKey6(r);
customPinPadKeyboard.getKey_7().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_7().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_7().getHeight() + r.top;
pinpadLayout.setKey7(r);
customPinPadKeyboard.getKey_8().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_8().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_8().getHeight() + r.top;
pinpadLayout.setKey8(r);
customPinPadKeyboard.getKey_9().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_9().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_9().getHeight() + r.top;
pinpadLayout.setKey9(r);
customPinPadKeyboard.getKey_0().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_0().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_0().getHeight() + r.top;
pinpadLayout.setKey10(r);
customPinPadKeyboard.getKey_cancel().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_cancel().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_cancel().getHeight() + r.top;
pinpadLayout.setKeyCancel(r);
customPinPadKeyboard.getKey_clear().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_clear().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_clear().getHeight() + r.top;
pinpadLayout.setKeyClear(r);
customPinPadKeyboard.getKey_ok().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_ok().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_ok().getHeight() + r.top;
pinpadLayout.setKeyConfirm(r);
byte[] number = pinPad.setPinpadLayout(pinpadLayout);
OnPinPadInputListener pinPadInputListener = new OnPinPadInputListener() {
@Override
public void onInputResult(final int retCode, final byte[] data) {
if (retCode == SdkResult.Success) {
LogUtil.d(TAG, "Success");
if(isOnlinePin) {
mPayDetail.setPINCipher(ByteUtil.bytes2HexStr(data));
}
mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
} else if (retCode == SdkResult.Fail) {
LogUtil.d(TAG, "Failure");
} else if (retCode == SdkResult.PinPad_Input_Cancel) {
LogUtil.d(TAG, "Cancel");
mHandler.obtainMessage(PIN_CLICK_CANCEL).sendToTarget();
} else if (retCode == SdkResult.PinPad_Input_Timeout) {
mHandler.obtainMessage(PIN_TIME_OUT,-7009).sendToTarget();
} else if (retCode == SdkResult.PinPad_No_Pin_Input) {
mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
} else {
mHandler.obtainMessage(PIN_ERROR).sendToTarget();
}
LogUtil.d(TAG, "RetCode:" + retCode);
LogUtil.d(TAG, "data bytes:" + ByteUtil.bytes2HexStr(data));
}
@Override
public void onSendKey(byte keyCode) {
increaseCount();
if (keyCode == PinPadKeyCode.KEYCODE_CLEAR) {
LogUtil.d(TAG, "on clear");
mHandler.obtainMessage(PIN_CLICK_CLEAR).sendToTarget();
} else if (keyCode == PinPadKeyCode.KEYCODE_CANCEL) {
LogUtil.d(TAG, "on click cancel");
mHandler.obtainMessage(PIN_CLICK_CANCEL).sendToTarget();
} else if (keyCode == PinPadKeyCode.KEYCODE_CONFIRM) {
LogUtil.d(TAG, "on click confirm");
mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
} else {
LogUtil.d(TAG, "on click number");
mHandler.obtainMessage(PIN_CLICK_NUMBER, pinEnterCount, 0).sendToTarget();
}
LogUtil.d(TAG, "SendKey: " + ByteUtil.byte2HexStr(keyCode));
}
};
if (number != null) {
customPinPadKeyboard.setKeyBoard(number);
// customPinPadKeyboard.setKeyBoard(ByteUtil.bytes2HexStr(number));
LogUtil.d(TAG, "PinPad: " + ByteUtil.bytes2HexStr(number));
int[] supperLen = new int[]{0x00, 0x04, 0x06, 0x0c};
pinPad.setPinKeyboardViewMode(PinKeyboardViewModeEnum.DEFAULT);
pinPad.setPinKeyboardMode(PinKeyboardModeEnum.FIXED);
// pinPad.setAlgorithmMode(AlgorithmModeEnum.DES);
if(cardNo == null){
cardNo = emvHandler.getEmvCardDataInfo().getCardNo();
}
int length = cardNo.length();
byte[] panBytes = cardNo.substring( length- 13).getBytes(StandardCharsets.US_ASCII);
LogUtil.d(TAG,"card num :"+cardNo);
LogUtil.d(TAG,"Is Online Pin:"+isOnlinePin);
// pinPad.inputOnlinePin(supperLen, 60, pan, 0, PinAlgorithmModeEnum.ISO9564FMT0, pinPadInputListener);
if (isOnlinePin) {
pinPad.inputOnlinePin(supperLen, 60, panBytes, pinIndex, PinAlgorithmModeEnum.ISO9564FMT0, pinPadInputListener);
} else {
mPayDetail.transCVM = TransCVM.OFFLINE_PIN;
pinPad.inputOfflinePin(supperLen, 60, pinPadInputListener);
} }
} }
} }
);
}
}
private void setupPinPadLayout(boolean isOnlinePin) {
LogUtil.d(TAG, "inside the global layout!");
PinpadLayoutEntity pinpadLayout = new PinpadLayoutEntity();
// Helper to avoid repetition
pinpadLayout.setKey1(getRectForView(customPinPadKeyboard.getKey_1()));
pinpadLayout.setKey2(getRectForView(customPinPadKeyboard.getKey_2()));
pinpadLayout.setKey3(getRectForView(customPinPadKeyboard.getKey_3()));
pinpadLayout.setKey4(getRectForView(customPinPadKeyboard.getKey_4()));
pinpadLayout.setKey5(getRectForView(customPinPadKeyboard.getKey_5()));
pinpadLayout.setKey6(getRectForView(customPinPadKeyboard.getKey_6()));
pinpadLayout.setKey7(getRectForView(customPinPadKeyboard.getKey_7()));
pinpadLayout.setKey8(getRectForView(customPinPadKeyboard.getKey_8()));
pinpadLayout.setKey9(getRectForView(customPinPadKeyboard.getKey_9()));
pinpadLayout.setKey10(getRectForView(customPinPadKeyboard.getKey_0()));
pinpadLayout.setKeyCancel(getRectForView(customPinPadKeyboard.getKey_cancel()));
pinpadLayout.setKeyClear(getRectForView(customPinPadKeyboard.getKey_clear()));
pinpadLayout.setKeyConfirm(getRectForView(customPinPadKeyboard.getKey_ok()));
byte[] number = pinPad.setPinpadLayout(pinpadLayout);
OnPinPadInputListener pinPadInputListener = new OnPinPadInputListener() {
@Override
public void onInputResult(final int retCode, final byte[] data) {
if (retCode == SdkResult.Success) {
LogUtil.d(TAG, "Success");
if(isOnlinePin) {
mPayDetail.setPINCipher(ByteUtil.bytes2HexStr(data));
}
mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
} else if (retCode == SdkResult.Fail) {
LogUtil.d(TAG, "Failure");
} else if (retCode == SdkResult.PinPad_Input_Cancel) {
LogUtil.d(TAG, "Cancel");
mHandler.obtainMessage(PIN_CLICK_CANCEL).sendToTarget();
} else if (retCode == SdkResult.PinPad_Input_Timeout) {
mHandler.obtainMessage(PIN_TIME_OUT,-7009).sendToTarget();
} else if (retCode == SdkResult.PinPad_No_Pin_Input) {
mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
} else {
mHandler.obtainMessage(PIN_ERROR).sendToTarget();
} }
);
LogUtil.d(TAG, "RetCode:" + retCode);
LogUtil.d(TAG, "data bytes:" + ByteUtil.bytes2HexStr(data));
}
@Override
public void onSendKey(byte keyCode) {
increaseCount();
if (keyCode == PinPadKeyCode.KEYCODE_CLEAR) {
LogUtil.d(TAG, "on clear");
mHandler.obtainMessage(PIN_CLICK_CLEAR).sendToTarget();
} else if (keyCode == PinPadKeyCode.KEYCODE_CANCEL) {
LogUtil.d(TAG, "on click cancel");
mHandler.obtainMessage(PIN_CLICK_CANCEL).sendToTarget();
} else if (keyCode == PinPadKeyCode.KEYCODE_CONFIRM) {
LogUtil.d(TAG, "on click confirm");
mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
} else {
LogUtil.d(TAG, "on click number");
mHandler.obtainMessage(PIN_CLICK_NUMBER, pinEnterCount, 0).sendToTarget();
}
LogUtil.d(TAG, "SendKey: " + ByteUtil.byte2HexStr(keyCode));
}
};
if (number != null) {
customPinPadKeyboard.setKeyBoard(number);
// customPinPadKeyboard.setKeyBoard(ByteUtil.bytes2HexStr(number));
LogUtil.d(TAG, "PinPad: " + ByteUtil.bytes2HexStr(number));
int[] supperLen = new int[]{0x00, 0x04, 0x06, 0x0c};
pinPad.setPinKeyboardViewMode(PinKeyboardViewModeEnum.DEFAULT);
pinPad.setPinKeyboardMode(PinKeyboardModeEnum.FIXED);
// pinPad.setAlgorithmMode(AlgorithmModeEnum.DES);
if(cardNo == null){
cardNo = emvHandler.getEmvCardDataInfo().getCardNo();
}
int length = cardNo.length();
byte[] panBytes = cardNo.substring( length- 13).getBytes(StandardCharsets.US_ASCII);
LogUtil.d(TAG,"card num :"+cardNo);
LogUtil.d(TAG,"Is Online Pin:"+isOnlinePin);
// pinPad.inputOnlinePin(supperLen, 60, pan, 0, PinAlgorithmModeEnum.ISO9564FMT0, pinPadInputListener);
if (isOnlinePin) {
pinPad.inputOnlinePin(supperLen, 60, panBytes, pinIndex, PinAlgorithmModeEnum.ISO9564FMT0, pinPadInputListener);
} else {
mPayDetail.transCVM = TransCVM.OFFLINE_PIN;
pinPad.inputOfflinePin(supperLen, 60, pinPadInputListener);
}
}
}
// Reusable rect helper
private Rect getRectForView(View view) {
int[] location = new int[2];
view.getLocationOnScreen(location);
Rect r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = view.getWidth() + r.left;
r.bottom = view.getHeight() + r.top;
return r;
} }
private void increaseCount() { private void increaseCount() {
@ -677,11 +607,11 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
} }
} else { } else {
//contact terminal capability ; if different card brand(depend on aid) have different terminal capability //contact terminal capability ; if different card brand(depend on aid) have different terminal capability
if (ByteUtils.byteArray2HexString(aid).toUpperCase().contains("A000000004")) { // if (ByteUtils.byteArray2HexString(aid).toUpperCase().contains("A000000004")) {
emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x33}, ByteUtil.hexStr2Bytes(terminalCapability)); // emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x33}, ByteUtil.hexStr2Bytes(terminalCapability));
emvHandler.setTlv(new byte[]{(byte) 0xE0, (byte) 0x1D}, ByteUtils.hexString2ByteArray("6C00800000000000"));//terminal risk // emvHandler.setTlv(new byte[]{(byte) 0xE0, (byte) 0x1D}, ByteUtils.hexString2ByteArray("6C00800000000000"));//terminal risk
//
} // }
} }
emvHandler.onSetTransInitBeforeGPOResponse(true); emvHandler.onSetTransInitBeforeGPOResponse(true);
@ -744,7 +674,6 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
@Override @Override
public void onPrompt(PromptEnum promptEnum) { public void onPrompt(PromptEnum promptEnum) {
LogUtil.d(TAG, "onPrompt->" + promptEnum); LogUtil.d(TAG, "onPrompt->" + promptEnum);
// emvHandler.onSetPromptResponse(true);
if( promptEnum == PromptEnum.OFFLINE_PIN_INCORRECT_TRY_AGAIN) { if( promptEnum == PromptEnum.OFFLINE_PIN_INCORRECT_TRY_AGAIN) {
emvHandler.onSetPromptResponse(false); emvHandler.onSetPromptResponse(false);
} else { } else {

View File

@ -341,7 +341,8 @@ public class FieldUtils {
} else if (BaseCardType.IC.getValue() == cardType) { // IC } else if (BaseCardType.IC.getValue() == cardType) { // IC
value = "05"; value = "05";
} else if (FALLBACK == cardType){ // Fallback } else if (FALLBACK == cardType){ // Fallback
value = "08"; value = "72";
// value = "08";
} else { // Hand-in card number } else { // Hand-in card number
value = "01"; value = "01";
} }