Updated on 2026-08-14
This commit is contained in:
commit
ab13ff8636
16 changed files with 530 additions and 175 deletions
|
|
@ -21,16 +21,23 @@ public class ReadCardInfoTask extends Thread {
|
|||
private Context mContext;
|
||||
private NfcManager mNfcManager;
|
||||
|
||||
private ArrayList<String> lastRead_UnsuccessfullPINs = new ArrayList<>();
|
||||
private TangemCard.EncryptionMode lastRead_Encryption = null;
|
||||
private String lastRead_UID;
|
||||
// this fields are static to optimize process when need enter pin and scan card again
|
||||
private static ArrayList<String> lastRead_UnsuccessfullPINs = new ArrayList<>();
|
||||
private static TangemCard.EncryptionMode lastRead_Encryption = null;
|
||||
private static String lastRead_UID;
|
||||
|
||||
public ReadCardInfoTask(Context context, NfcManager nfcManager, String lastRead_UID, IsoDep isoDep, CardProtocol.Notifications notifications) {
|
||||
public static void resetLastReadInfo() {
|
||||
lastRead_UID="";
|
||||
lastRead_Encryption=null;
|
||||
lastRead_UnsuccessfullPINs.clear();
|
||||
}
|
||||
|
||||
public ReadCardInfoTask(Context context, NfcManager nfcManager, IsoDep isoDep, CardProtocol.Notifications notifications) {
|
||||
mContext = context;
|
||||
mIsoDep = isoDep;
|
||||
mNotifications = notifications;
|
||||
mNfcManager = nfcManager;
|
||||
this.lastRead_UID = lastRead_UID;
|
||||
// ReadCardInfoTask.lastRead_UID = lastRead_UID;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -56,9 +63,7 @@ public class ReadCardInfoTask extends Thread {
|
|||
byte[] UID = mIsoDep.getTag().getId();
|
||||
String sUID = Util.byteArrayToHexString(UID);
|
||||
if (!lastRead_UID.equals(sUID)) {
|
||||
lastRead_UID = sUID;
|
||||
lastRead_UnsuccessfullPINs.clear();
|
||||
lastRead_Encryption = null;
|
||||
resetLastReadInfo();
|
||||
}
|
||||
|
||||
Log.i(TAG, "[-- Start read card info --]");
|
||||
|
|
@ -146,6 +151,7 @@ public class ReadCardInfoTask extends Thread {
|
|||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
mNfcManager.notifyReadResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,13 @@ import android.nfc.tech.IsoDep;
|
|||
import android.util.Log;
|
||||
|
||||
import com.tangem.domain.cardReader.CardProtocol;
|
||||
import com.tangem.domain.cardReader.FW;
|
||||
import com.tangem.domain.cardReader.NfcManager;
|
||||
import com.tangem.domain.wallet.PINStorage;
|
||||
import com.tangem.domain.wallet.TangemCard;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by dvol on 04.02.2018.
|
||||
*/
|
||||
|
|
@ -59,23 +62,26 @@ public class VerifyCardTask extends Thread {
|
|||
protocol.setPIN(PIN);
|
||||
protocol.run_Read(false);
|
||||
PINStorage.setLastUsedPIN(PIN);
|
||||
mNotifications.OnReadProgress(protocol, 30);
|
||||
mNotifications.OnReadProgress(protocol, 20);
|
||||
if (isCancelled) return;
|
||||
protocol.run_VerifyCard();
|
||||
mNotifications.OnReadProgress(protocol, 60);
|
||||
mNotifications.OnReadProgress(protocol, 50);
|
||||
Log.i(TAG, "Manufacturer: " + protocol.getCard().getManufacturer().getOfficialName());
|
||||
if (isCancelled) return;
|
||||
if (protocol.getCard().getStatus() == TangemCard.Status.Loaded) {
|
||||
protocol.run_CheckWalletWithSignatureVerify();
|
||||
mNotifications.OnReadProgress(protocol, 90);
|
||||
mNotifications.OnReadProgress(protocol, 80);
|
||||
}
|
||||
|
||||
|
||||
// if (isCancelled) return;
|
||||
// if (protocol.getCard().getStatus() == TangemCard.Status.Loaded) {
|
||||
// protocol.run_CheckWithSignatureVerify();
|
||||
// }
|
||||
|
||||
if (isCancelled) return;
|
||||
FW.VerifyCodeRecord record=FW.selectRandomVerifyCodeBlock(mCard.getFirmwareVersion());
|
||||
if (isCancelled) return;
|
||||
if( record!=null ) {
|
||||
byte[] returnedDigest = protocol.run_VerifyCode(record.hashAlg, record.blockIndex, record.blockCount, record.challenge);
|
||||
mCard.setCodeConfirmed(Arrays.equals(returnedDigest, record.digest));
|
||||
}else{
|
||||
mCard.setCodeConfirmed(null);
|
||||
}
|
||||
mNotifications.OnReadProgress(protocol, 90);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
protocol.setError(e);
|
||||
|
|
|
|||
|
|
@ -5,5 +5,4 @@ enum class BitcoinNodeTestNet(val host: String, val port: Int) {
|
|||
n2("testnet.hsmiths.com", 53011),
|
||||
n3("testnet.qtornado.com", 51001),
|
||||
n4("testnet1.bauerj.eu", 50001),
|
||||
|
||||
}
|
||||
|
|
@ -179,12 +179,12 @@ public class CardCrypto {
|
|||
Log.e("cardCrypto","enc:" +Util.bytesToHex(enc));
|
||||
throw new Exception("unsupported s-length - r-length:" + String.valueOf(rLength)+",s-length:" + String.valueOf(sLength)+",enc:" +Util.bytesToHex(enc));
|
||||
}
|
||||
|
||||
|
||||
if(!VerifySignature(GeneratePublicKey(privateKeyArray), data, res))
|
||||
{
|
||||
throw new Exception("Signature self verify failed - r-length:" + String.valueOf(rLength)+",s-length:" + String.valueOf(sLength)+",enc:" +Util.bytesToHex(enc)+",res:"+Util.bytesToHex(res));
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ public class CardCrypto {
|
|||
* @return the PBDKF2 hash of the password
|
||||
*/
|
||||
public static byte[] pbkdf2(byte[] password, byte[] salt, int iterations)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
|
||||
throws InvalidKeyException {
|
||||
return PBKDF2.deriveKey(password, salt, iterations);
|
||||
}
|
||||
|
||||
|
|
@ -219,22 +219,20 @@ public class CardCrypto {
|
|||
return mEncryptedData;
|
||||
}
|
||||
|
||||
public static byte[] Decrypt(byte[] key, byte[] data) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
|
||||
try {
|
||||
public static byte[] Decrypt(byte[] key, byte[] data, boolean UsePKCS7)
|
||||
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
|
||||
if (UsePKCS7) {
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES/CBC/PKCS7PADDING");
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING");
|
||||
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
|
||||
byte[] decryptedData = cipher.doFinal(Arrays.copyOfRange(data, 0, data.length ));
|
||||
byte[] decryptedData = cipher.doFinal(Arrays.copyOfRange(data, 0, data.length));
|
||||
return decryptedData;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
} else {
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES/CBC/NOPADDING");
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
|
||||
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
|
||||
byte[] decryptedData = cipher.doFinal(Arrays.copyOfRange(data, 0, data.length ));
|
||||
Log.e("decrypt",Util.bytesToHex(decryptedData));
|
||||
throw e;
|
||||
byte[] decryptedData = cipher.doFinal(Arrays.copyOfRange(data, 0, data.length));
|
||||
return decryptedData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -470,7 +470,11 @@ public class CardProtocol {
|
|||
|
||||
// try read denomination
|
||||
if (tlvIssuerData != null && tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination) != null) {
|
||||
mCard.setDenomination(tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination).Value);
|
||||
if(tlvIssuerData.getTLV(TLV.Tag.TAG_DenominationText) != null) {
|
||||
mCard.setDenomination(tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination).Value, tlvIssuerData.getTLV(TLV.Tag.TAG_DenominationText).getAsString());
|
||||
}else{
|
||||
mCard.setDenomination(tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination).Value);
|
||||
}
|
||||
} else {
|
||||
mCard.clearDenomination();
|
||||
}
|
||||
|
|
@ -504,6 +508,8 @@ public class CardProtocol {
|
|||
|
||||
TLVList tlvCardData = TLVList.fromBytes(readResult.getTLV(TLV.Tag.TAG_CardData).Value);
|
||||
|
||||
mCard.setBatch(tlvCardData.getTLV(TLV.Tag.TAG_Batch).getAsHexString());
|
||||
|
||||
TLV tokenSymbol = tlvCardData.getTLV(TLV.Tag.TAG_Token_Symbol);
|
||||
TLV contractAddress = tlvCardData.getTLV(TLV.Tag.TAG_Token_Contract_Address);
|
||||
TLV tokens_decimal = tlvCardData.getTLV(TLV.Tag.TAG_Token_Decimal);
|
||||
|
|
@ -553,7 +559,7 @@ public class CardProtocol {
|
|||
} catch (Exception ee) {
|
||||
ee.printStackTrace();
|
||||
Log.e(logTag, "Cannot get issuer");
|
||||
mCard.setIssuer(Issuer.Unknown);
|
||||
mCard.setIssuer(Issuer.Unknown());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -848,7 +854,7 @@ public class CardProtocol {
|
|||
rqApdu.addTLV(TLV.Tag.TAG_Issuer_Transaction_Signature, issuerSignature);
|
||||
}
|
||||
if (issuerData != null) {
|
||||
if (issuer == null || issuer == Issuer.Unknown)
|
||||
if (issuer == null || issuer == Issuer.Unknown())
|
||||
throw new Exception("Need known Issuer to write issuer Data");
|
||||
rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data, issuerData);
|
||||
byte[] issuerSignature = CardCrypto.Signature(issuer.getPrivateTransactionKey(), issuerData);
|
||||
|
|
@ -905,7 +911,7 @@ public class CardProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
private byte[] run_VerifyCode(String hashAlgID, int codePageAddress, int codePageCount, byte[] challenge) throws Exception {
|
||||
public byte[] run_VerifyCode(String hashAlgID, int codePageAddress, int codePageCount, byte[] challenge) throws Exception {
|
||||
if (readResult == null) run_Read();
|
||||
CommandApdu rqApdu = StartPrepareCommand(INS.VerifyCode);
|
||||
rqApdu.addTLV(TLV.Tag.TAG_HashAlgID, hashAlgID.getBytes("US-ASCII"));
|
||||
|
|
@ -978,6 +984,9 @@ public class CardProtocol {
|
|||
Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" ")));
|
||||
TLV issuerData = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Issuer_Data);
|
||||
TLV issuerDataSignature = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Issuer_Data_Signature);
|
||||
TLV issuerDataCounter = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Issuer_Data_Counter);
|
||||
|
||||
boolean protectIssuerDataAgainstReplay=(readResult.getTagAsInt(TLV.Tag.TAG_SettingsMask)&SettingsMask.ProtectIssuerDataAgainstReplay)!=0;
|
||||
|
||||
if (issuerData == null || issuerDataSignature == null)
|
||||
throw new TangemException("Invalid answer format (GetIssuerData)");
|
||||
|
|
@ -985,6 +994,9 @@ public class CardProtocol {
|
|||
ByteArrayOutputStream bsDataToVerify = new ByteArrayOutputStream();
|
||||
bsDataToVerify.write(mCard.getCID());
|
||||
bsDataToVerify.write(issuerData.Value);
|
||||
if( protectIssuerDataAgainstReplay ) {
|
||||
bsDataToVerify.write(issuerDataCounter.Value);
|
||||
}
|
||||
try {
|
||||
if (CardCrypto.VerifySignature(mCard.getIssuer().getPublicDataKey(), bsDataToVerify.toByteArray(), issuerDataSignature.Value)) {
|
||||
mCard.setIssuerData(issuerData.Value, issuerDataSignature.Value);
|
||||
|
|
|
|||
62
app/src/main/java/com/tangem/domain/cardReader/FW.java
Normal file
62
app/src/main/java/com/tangem/domain/cardReader/FW.java
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package com.tangem.domain.cardReader;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.tangem.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class FW {
|
||||
private static JsonArray jaFirmwares=null;
|
||||
|
||||
public static boolean needInit() {
|
||||
return jaFirmwares == null;
|
||||
}
|
||||
|
||||
public static void Init(Context context) {
|
||||
try(InputStream is=context.getAssets().open("fw_hashes.json")) {
|
||||
try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
||||
JsonParser parser = new JsonParser();
|
||||
jaFirmwares = parser.parse(reader).getAsJsonArray();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static class VerifyCodeRecord
|
||||
{
|
||||
public String hashAlg;
|
||||
public int blockIndex;
|
||||
public int blockCount;
|
||||
public byte[] challenge;
|
||||
public byte[] digest;
|
||||
}
|
||||
|
||||
public static VerifyCodeRecord selectRandomVerifyCodeBlock(String firmwareVersion) throws IOException {
|
||||
|
||||
for(int i=0; i<jaFirmwares.size(); i++) {
|
||||
JsonObject jsVersion = jaFirmwares.get(i).getAsJsonObject();
|
||||
if( jsVersion.get("fw").getAsString().equals(firmwareVersion) )
|
||||
{
|
||||
VerifyCodeRecord result=new VerifyCodeRecord();
|
||||
result.hashAlg = "sha-256";
|
||||
JsonArray jsHashes = jsVersion.get(result.hashAlg).getAsJsonArray();
|
||||
result.challenge = Util.hexToBytes(jsVersion.get("challenge").getAsString());
|
||||
int caseIndex= Util.byteArrayToInt(Util.generateRandomBytes(4))%jsHashes.size();
|
||||
JsonObject jsRecord = jsHashes.get(caseIndex).getAsJsonObject();
|
||||
result.blockIndex = jsRecord.get("block").getAsInt();
|
||||
result.blockCount = jsRecord.get("count").getAsInt();
|
||||
result.digest = Util.hexToBytes(jsRecord.get("digest").getAsString());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ import android.os.Build;
|
|||
import android.os.Bundle;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.tangem.presentation.dialog.NFCEnableDialog;
|
||||
|
||||
|
|
@ -76,6 +77,27 @@ public class NfcManager {
|
|||
// }
|
||||
}
|
||||
|
||||
int errorCount=0;
|
||||
public void notifyReadResult(boolean success)
|
||||
{
|
||||
if(success)
|
||||
{
|
||||
errorCount=0;
|
||||
}else{
|
||||
errorCount++;
|
||||
}
|
||||
if( errorCount>=3 )
|
||||
{
|
||||
disableReaderMode();
|
||||
mNfcAdapter=null;
|
||||
Toast.makeText(mActivity,"NFC restarted!",Toast.LENGTH_SHORT).show();
|
||||
mActivity.runOnUiThread(()->{
|
||||
mNfcAdapter = NfcAdapter.getDefaultAdapter(mActivity);
|
||||
enableReaderMode();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void showNFCEnableDialog() {
|
||||
mEnableNfcDialog = new NFCEnableDialog();
|
||||
mEnableNfcDialog.show(mActivity.getFragmentManager(), NFCEnableDialog.TAG);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public class ResponseApdu {
|
|||
responseApdu.mSw2 = ((int) data[1] & 0xFF);
|
||||
return responseApdu;
|
||||
}else if( data.length>=18 ){
|
||||
byte[] decryptedData = CardCrypto.Decrypt(key, Arrays.copyOfRange(data, 0, data.length - 2));
|
||||
byte[] decryptedData = CardCrypto.Decrypt(key, Arrays.copyOfRange(data, 0, data.length - 2),true);
|
||||
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(decryptedData);
|
||||
byte[] baLength = new byte[2];
|
||||
|
|
|
|||
|
|
@ -90,7 +90,8 @@ public class TLV {
|
|||
TAG_Token_Decimal(0xA2),
|
||||
TAG_Denomination(0xC0),
|
||||
TAG_ValidatedBalance(0xC1),
|
||||
TAG_LastSign_Date(0xC2);
|
||||
TAG_LastSign_Date(0xC2),
|
||||
TAG_DenominationText(0xC3);
|
||||
|
||||
|
||||
Tag(int Code) {
|
||||
|
|
|
|||
|
|
@ -1,130 +1,192 @@
|
|||
package com.tangem.domain.wallet;
|
||||
|
||||
import com.tangem.domain.cardReader.CardCrypto;
|
||||
import android.content.Context;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.tangem.domain.cardReader.CardCrypto;
|
||||
import com.tangem.util.Util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by dvol on 14.11.2017.
|
||||
*/
|
||||
|
||||
public enum Issuer {
|
||||
Unknown("Unknown", "Unknown", null, null, null, null),
|
||||
SMART_CASH_AG("SMART CASH AG", "SMART CASH AG",
|
||||
IssuerKeyStorage.sdkPrivateDataKey, IssuerKeyStorage.GeneratePublicKey(IssuerKeyStorage.sdkPrivateDataKey),
|
||||
IssuerKeyStorage.sdkPrivateTransactionKey, IssuerKeyStorage.GeneratePublicKey(IssuerKeyStorage.sdkPrivateTransactionKey)),
|
||||
TANGEM_SDK("TANGEM SDK", "TANGEM SDK",
|
||||
IssuerKeyStorage.sdkPrivateDataKey, IssuerKeyStorage.GeneratePublicKey(IssuerKeyStorage.sdkPrivateDataKey),
|
||||
IssuerKeyStorage.sdkPrivateTransactionKey, IssuerKeyStorage.GeneratePublicKey(IssuerKeyStorage.sdkPrivateTransactionKey)),
|
||||
TANGEM("TANGEM", "TANGEM", null, IssuerKeyStorage.tangemPublicDataKey, null, IssuerKeyStorage.tangemPublicTransactionKey)
|
||||
;
|
||||
public class Issuer {
|
||||
|
||||
static class KeyPair {
|
||||
String privateKey;
|
||||
String publicKey;
|
||||
|
||||
static class IssuerKeyStorage {
|
||||
private static final byte[] sdkPrivateDataKey = new byte[]{
|
||||
(byte) 0x11, (byte) 0x12, (byte) 0x13, (byte) 0x14, (byte) 0x15, (byte) 0x16, (byte) 0x17, (byte) 0x18,
|
||||
(byte) 0x47, (byte) 0x71, (byte) 0xED, (byte) 0x81, (byte) 0xF2, (byte) 0xBA, (byte) 0xCF, (byte) 0x57,
|
||||
(byte) 0x47, (byte) 0x9E, (byte) 0x47, (byte) 0x35, (byte) 0xEB, (byte) 0x14, (byte) 0x05, (byte) 0x08,
|
||||
(byte) 0x39, (byte) 0x27, (byte) 0x37, (byte) 0x2D, (byte) 0x40, (byte) 0xDA, (byte) 0x9E, (byte) 0x92};
|
||||
|
||||
private static final byte[] sdkPrivateTransactionKey = new byte[]{
|
||||
(byte) 0x11, (byte) 0x12, (byte) 0x13, (byte) 0x14, (byte) 0x15, (byte) 0x16, (byte) 0x17, (byte) 0x18,
|
||||
(byte) 0x47, (byte) 0x71, (byte) 0xED, (byte) 0x81, (byte) 0xF2, (byte) 0xBA, (byte) 0xCF, (byte) 0x57,
|
||||
(byte) 0x47, (byte) 0x9E, (byte) 0x47, (byte) 0x35, (byte) 0xEB, (byte) 0x14, (byte) 0x05, (byte) 0x08,
|
||||
(byte) 0x19, (byte) 0x18, (byte) 0x17, (byte) 0x16, (byte) 0x15, (byte) 0x14, (byte) 0x13, (byte) 0x12};
|
||||
|
||||
private static byte[] tangemPublicDataKey = {
|
||||
(byte) 0x04 ,
|
||||
(byte) 0x81 ,(byte) 0x96 ,(byte) 0xAA ,(byte) 0x4B ,(byte) 0x41 ,(byte) 0x0A ,(byte) 0xC4 ,(byte) 0x4A,
|
||||
(byte) 0x3B ,(byte) 0x9C ,(byte) 0xCE ,(byte) 0x18 ,(byte) 0xE7 ,(byte) 0xBE ,(byte) 0x22 ,(byte) 0x6A,
|
||||
(byte) 0xEA ,(byte) 0x07 ,(byte) 0x0A ,(byte) 0xCC ,(byte) 0x83 ,(byte) 0xA9 ,(byte) 0xCF ,(byte) 0x67,
|
||||
(byte) 0x54 ,(byte) 0x0F ,(byte) 0xAC ,(byte) 0x49 ,(byte) 0xAF ,(byte) 0x25 ,(byte) 0x12 ,(byte) 0x9F,
|
||||
(byte) 0x6A ,(byte) 0x53 ,(byte) 0x8A ,(byte) 0x28 ,(byte) 0xAD ,(byte) 0x63 ,(byte) 0x41 ,(byte) 0x35,
|
||||
(byte) 0x8E ,(byte) 0x3C ,(byte) 0x4F ,(byte) 0x99 ,(byte) 0x63 ,(byte) 0x06 ,(byte) 0x4F ,(byte) 0x7E,
|
||||
(byte) 0x36 ,(byte) 0x53 ,(byte) 0x72 ,(byte) 0xA6 ,(byte) 0x51 ,(byte) 0xD3 ,(byte) 0x74 ,(byte) 0xE5,
|
||||
(byte) 0xC2 ,(byte) 0x3C ,(byte) 0xDD ,(byte) 0x37 ,(byte) 0xFD ,(byte) 0x09 ,(byte) 0x9B ,(byte) 0xF2};
|
||||
|
||||
private static byte[] tangemPublicTransactionKey = {
|
||||
(byte) 0x04 ,
|
||||
(byte) 0x34 ,(byte) 0x3D ,(byte) 0x40 ,(byte) 0x49 ,(byte) 0x6C ,(byte) 0xBE ,(byte) 0x1F ,(byte) 0xE8,
|
||||
(byte) 0xA8 ,(byte) 0xC0 ,(byte) 0x26 ,(byte) 0x57 ,(byte) 0x5C ,(byte) 0x43 ,(byte) 0x5A ,(byte) 0x29,
|
||||
(byte) 0x14 ,(byte) 0x1E ,(byte) 0xA3 ,(byte) 0xBC ,(byte) 0x33 ,(byte) 0x5D ,(byte) 0xA5 ,(byte) 0x54,
|
||||
(byte) 0x9A ,(byte) 0xB6 ,(byte) 0xC6 ,(byte) 0x46 ,(byte) 0x85 ,(byte) 0xA6 ,(byte) 0x46 ,(byte) 0x84,
|
||||
(byte) 0x80 ,(byte) 0x36 ,(byte) 0xD4 ,(byte) 0x81 ,(byte) 0xCF ,(byte) 0x9A ,(byte) 0x98 ,(byte) 0x93,
|
||||
(byte) 0x90 ,(byte) 0xA8 ,(byte) 0xB0 ,(byte) 0x34 ,(byte) 0xB2 ,(byte) 0x29 ,(byte) 0xD9 ,(byte) 0x9B,
|
||||
(byte) 0xD4 ,(byte) 0x9E ,(byte) 0x6F ,(byte) 0x07 ,(byte) 0xD2 ,(byte) 0xFF ,(byte) 0x02 ,(byte) 0x74,
|
||||
(byte) 0x6E ,(byte) 0xA2 ,(byte) 0x65 ,(byte) 0xEF ,(byte) 0x99 ,(byte) 0x38 ,(byte) 0x0A ,(byte) 0x80};
|
||||
|
||||
public static byte[] GeneratePublicKey(byte[] privateKey) {
|
||||
try {
|
||||
return CardCrypto.GeneratePublicKey(privateKey);
|
||||
byte[] getPrivateKey() throws Exception {
|
||||
if (privateKey != null) {
|
||||
return CardCrypto.GeneratePublicKey(Util.hexToBytes(privateKey));
|
||||
} else {
|
||||
throw new Exception("No private key!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] getPublicKey() throws Exception {
|
||||
if (publicKey == null) {
|
||||
if (privateKey != null) {
|
||||
return CardCrypto.GeneratePublicKey(Util.hexToBytes(privateKey));
|
||||
} else {
|
||||
throw new Exception("Invalid key format: no public and no private");
|
||||
}
|
||||
} else {
|
||||
return Util.hexToBytes(publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String id;
|
||||
private String officialName;
|
||||
private KeyPair dataKey;
|
||||
private KeyPair transactionKey;
|
||||
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private static List<Issuer> instances=new ArrayList<>();
|
||||
|
||||
public static boolean needInit() {
|
||||
return instances.size() == 0;
|
||||
}
|
||||
|
||||
public static void Init(Context context) {
|
||||
try {
|
||||
|
||||
// JsonArray jaIssuers=loadIssuersFile();
|
||||
//
|
||||
Issuer unknown = new Issuer();
|
||||
unknown.id = "UNKNOWN";
|
||||
unknown.officialName = "UNKNOWN";
|
||||
|
||||
try(InputStream is=context.getAssets().open("issuers.json")) {
|
||||
try ( InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
||||
Type listType = new TypeToken<List<Issuer>>() {
|
||||
}.getType();
|
||||
instances = new Gson().fromJson(reader, listType);
|
||||
}
|
||||
}
|
||||
instances.add(0, unknown);
|
||||
// for (JsonElement jeIssuer : jaIssuers) {
|
||||
// Issuer instance = new Gson().fromJson(jeIssuer, Issuer.class);
|
||||
// instances.add(instance);
|
||||
// }
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String ID;
|
||||
private String officialName;
|
||||
private byte[] privateDataKeyArray;
|
||||
private byte[] publicDataKeyArray;
|
||||
private byte[] privateTransactionKeyArray;
|
||||
private byte[] publicTransactionKeyArray;
|
||||
// private static JsonArray loadIssuersFile() throws IOException {
|
||||
// String result;
|
||||
// JsonParser jsonParser = new JsonParser();
|
||||
// try (BufferedReader reader = Files.newReader(new File("Issuers.json"), StandardCharsets.UTF_8)) {
|
||||
// String str;
|
||||
// StringBuilder buf = new StringBuilder();
|
||||
// while ((str = reader.readLine()) != null) {
|
||||
// buf.append(str);
|
||||
// buf.append("\n");
|
||||
// }
|
||||
// result = buf.toString();
|
||||
// }
|
||||
// return jsonParser.parse(result).getAsJsonArray();
|
||||
// }
|
||||
//
|
||||
// static String ReadJSONResource(Context mContext, int id) {
|
||||
// Resources resources = mContext.getResources();
|
||||
// InputStream resourceReader = resources.openRawResource(id);
|
||||
// Writer writer = new StringWriter();
|
||||
// try {
|
||||
// try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceReader, "UTF-8"))) {
|
||||
// String line = reader.readLine();
|
||||
// while (line != null) {
|
||||
// writer.write(line);
|
||||
// line = reader.readLine();
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// Log.e("ReadJSONResource", "Unhandled exception while using JSONResourceReader", e);
|
||||
// } finally {
|
||||
// try {
|
||||
// resourceReader.close();
|
||||
// } catch (Exception e) {
|
||||
// Log.e("ReadJSONResource", "Unhandled exception while using JSONResourceReader", e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return writer.toString();
|
||||
// }
|
||||
|
||||
Issuer(String id, String officialName, byte[] privateDataKey, byte[] publicDataKey, byte[] privateTransactionKey, byte[] publicTransactionKey) {
|
||||
this.ID = id;
|
||||
this.officialName = officialName;
|
||||
this.privateDataKeyArray = privateDataKey;
|
||||
this.privateTransactionKeyArray = privateTransactionKey;
|
||||
this.publicDataKeyArray = publicDataKey;
|
||||
this.publicTransactionKeyArray = publicTransactionKey;
|
||||
public byte[] getPublicDataKey() throws Exception {
|
||||
if (dataKey == null)
|
||||
throw new Exception("Data key not specified!");
|
||||
return dataKey.getPublicKey();
|
||||
}
|
||||
|
||||
public byte[] getPublicDataKey() {
|
||||
return publicDataKeyArray;
|
||||
public byte[] getPublicTransactionKey() throws Exception {
|
||||
if (dataKey == null)
|
||||
throw new Exception("Transaction key not specified!");
|
||||
return transactionKey.getPublicKey();
|
||||
}
|
||||
|
||||
public byte[] getPublicTransactionKey() {
|
||||
return publicTransactionKeyArray;
|
||||
public byte[] getPrivateDataKey() throws Exception {
|
||||
if (dataKey == null)
|
||||
throw new Exception("Data key not specified!");
|
||||
return dataKey.getPrivateKey();
|
||||
}
|
||||
|
||||
public byte[] getPrivateDataKey() {
|
||||
return privateDataKeyArray;
|
||||
}
|
||||
|
||||
public byte[] getPrivateTransactionKey() {
|
||||
return privateTransactionKeyArray;
|
||||
}
|
||||
|
||||
public byte[] getID() {
|
||||
return ID.getBytes();
|
||||
public byte[] getPrivateTransactionKey() throws Exception {
|
||||
if (transactionKey == null)
|
||||
throw new Exception("Transaction key not specified!");
|
||||
return transactionKey.getPrivateKey();
|
||||
}
|
||||
|
||||
public String getOfficialName() {
|
||||
return officialName;
|
||||
}
|
||||
|
||||
public static Issuer FindIssuer(String ID, byte[] publicDataKey) {
|
||||
Issuer[] issuers = Issuer.values();
|
||||
for (int i = 1; i < issuers.length; i++) {
|
||||
if (issuers[i].ID.equals(ID) && Arrays.equals(issuers[i].getPublicDataKey(), publicDataKey)) {
|
||||
return issuers[i];
|
||||
}
|
||||
}
|
||||
return Issuer.Unknown;
|
||||
return officialName != null ? officialName : id;
|
||||
}
|
||||
|
||||
public static Issuer FindIssuer(String ID) {
|
||||
Issuer[] issuers = Issuer.values();
|
||||
for (int i = 1; i < issuers.length; i++) {
|
||||
if (issuers[i].ID.equals(ID)) {
|
||||
return issuers[i];
|
||||
for (int i = 0; i < instances.size(); i++) {
|
||||
try {
|
||||
if (instances.get(i).id.equals(ID)) {
|
||||
return instances.get(i);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return Issuer.Unknown;
|
||||
return Unknown();
|
||||
}
|
||||
|
||||
public static Issuer FindIssuer(String ID, byte[] publicDataKey) {
|
||||
for (int i = 0; i < instances.size(); i++) {
|
||||
try {
|
||||
if (instances.get(i).id.equals(ID) && Arrays.equals(instances.get(i).getPublicDataKey(), publicDataKey)) {
|
||||
return instances.get(i);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return Unknown();
|
||||
}
|
||||
|
||||
public static Issuer Unknown() {
|
||||
return instances.get(0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ import com.tangem.wallet.R;
|
|||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Created by dvol on 16.07.2017.
|
||||
|
|
@ -271,6 +271,7 @@ public class TangemCard {
|
|||
}
|
||||
|
||||
private Boolean codeConfirmed;
|
||||
|
||||
public void setCodeConfirmed(Boolean codeConfirmed) {
|
||||
this.codeConfirmed = codeConfirmed;
|
||||
}
|
||||
|
|
@ -280,6 +281,7 @@ public class TangemCard {
|
|||
}
|
||||
|
||||
private Boolean onlineVerified;
|
||||
|
||||
public void setOnlineVerified(Boolean verified) {
|
||||
this.onlineVerified = verified;
|
||||
}
|
||||
|
|
@ -289,6 +291,7 @@ public class TangemCard {
|
|||
}
|
||||
|
||||
private Boolean onlineValidated;
|
||||
|
||||
public void setOnlineValidated(Boolean validated) {
|
||||
this.onlineValidated = validated;
|
||||
}
|
||||
|
|
@ -297,15 +300,6 @@ public class TangemCard {
|
|||
return onlineValidated;
|
||||
}
|
||||
|
||||
private boolean balanceRecieved = false;
|
||||
public boolean isBalanceRecieved() {
|
||||
return balanceRecieved;
|
||||
}
|
||||
public void setBalanceRecieved(boolean balanceRecieved)
|
||||
{
|
||||
this.balanceRecieved = balanceRecieved;
|
||||
}
|
||||
|
||||
public int getRemainingSignatures() {
|
||||
return remainingSignatures;
|
||||
}
|
||||
|
|
@ -615,7 +609,7 @@ public class TangemCard {
|
|||
return health == 0;
|
||||
}
|
||||
|
||||
private Issuer issuer = Issuer.Unknown;
|
||||
private Issuer issuer = Issuer.Unknown();
|
||||
|
||||
public void setIssuer(Issuer issuer) {
|
||||
this.issuer = issuer;
|
||||
|
|
@ -663,8 +657,8 @@ public class TangemCard {
|
|||
return issuer.getOfficialName();
|
||||
}
|
||||
|
||||
byte[] issuerData;
|
||||
byte[] issuerDataSignature;
|
||||
private byte[] issuerData;
|
||||
private byte[] issuerDataSignature;
|
||||
|
||||
public byte[] getIssuerData() {
|
||||
return issuerData;
|
||||
|
|
@ -676,9 +670,10 @@ public class TangemCard {
|
|||
|
||||
public void setIssuerData(byte[] value, byte[] signature) {
|
||||
issuerData = value;
|
||||
issuerDataSignature = signature;
|
||||
}
|
||||
|
||||
boolean needWriteIssuerData = false;
|
||||
private boolean needWriteIssuerData = false;
|
||||
|
||||
public boolean getNeedWriteIssuerData() {
|
||||
return needWriteIssuerData;
|
||||
|
|
@ -862,6 +857,16 @@ public class TangemCard {
|
|||
return numbers1[0] > numbers2[0] || (numbers1[0] == numbers2[0] && numbers1[1] > numbers2[1]);
|
||||
}
|
||||
|
||||
private String batch;
|
||||
|
||||
public void setBatch(String batch) {
|
||||
this.batch = batch;
|
||||
}
|
||||
|
||||
public String getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
private String validationNodeDescription = "";
|
||||
|
||||
public String getValidationNodeDescription() {
|
||||
|
|
@ -1187,9 +1192,22 @@ public class TangemCard {
|
|||
}
|
||||
|
||||
private byte[] Denomination;
|
||||
private String DenominationText;
|
||||
|
||||
public void setDenomination(byte[] denomination) {
|
||||
public void setDenomination(byte[] denomination, String denominationText) {
|
||||
this.Denomination = denomination;
|
||||
this.DenominationText=denominationText;
|
||||
}
|
||||
|
||||
public void setDenomination(byte[] denomination)
|
||||
{
|
||||
this.Denomination=denomination;
|
||||
try {
|
||||
this.DenominationText=CoinEngineFactory.Create(getBlockchain()).ConvertByteArrayToAmount(this, denomination);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
this.DenominationText="N/A";
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getDenomination() {
|
||||
|
|
@ -1206,8 +1224,17 @@ public class TangemCard {
|
|||
}
|
||||
|
||||
|
||||
public String getDenominationText() {
|
||||
return DenominationText;
|
||||
}
|
||||
|
||||
public void setDenominationText(String denominationText) {
|
||||
DenominationText = denominationText;
|
||||
}
|
||||
|
||||
public void clearDenomination() {
|
||||
Denomination = null;
|
||||
DenominationText=null;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
|
|
@ -1274,9 +1301,10 @@ public class TangemCard {
|
|||
if (signingMethod != null) B.putString("signingMethod", signingMethod.name());
|
||||
if (manufacturer != null) B.putString("Manufacturer", manufacturer.name());
|
||||
if (encryptionMode != null) B.putString("EncryptionMode", encryptionMode.name());
|
||||
if (issuer != null) B.putString("Issuer", issuer.name());
|
||||
if (issuer != null) B.putString("Issuer", issuer.getID());
|
||||
if (firmwareVersion != null) B.putString("FirmwareVersion", firmwareVersion);
|
||||
if(balanceEqual != null) B.putBoolean("isBalanceEqual", balanceEqual);
|
||||
if (batch != null) B.putString("Batch", batch);
|
||||
B.putString("BalanceDecimal", balanceDecimal);
|
||||
B.putString("BalanceDecimalAlter", balanceDecimalAlter);
|
||||
B.putBoolean("ManufacturerConfirmed", manufacturerConfirmed);
|
||||
|
|
@ -1346,6 +1374,19 @@ public class TangemCard {
|
|||
if( onlineValidated!=null )
|
||||
B.putBoolean("onlineValidated", onlineValidated);
|
||||
|
||||
|
||||
if (codeConfirmed != null)
|
||||
B.putBoolean("codeConfirmed", codeConfirmed);
|
||||
|
||||
if (codeConfirmed != null)
|
||||
B.putBoolean("codeConfirmed", codeConfirmed);
|
||||
|
||||
if (onlineVerified != null)
|
||||
B.putBoolean("onlineVerified", onlineVerified);
|
||||
|
||||
if (onlineValidated != null)
|
||||
B.putBoolean("onlineValidated", onlineValidated);
|
||||
|
||||
}
|
||||
|
||||
public void LoadFromBundle(Bundle B) {
|
||||
|
|
@ -1388,6 +1429,7 @@ public class TangemCard {
|
|||
if(B.containsKey("FailedBalance")) failedBalanceRequestCounter = new AtomicInteger(B.getInt("FailedBalance"));
|
||||
if (B.containsKey("Issuer")) issuer = Issuer.FindIssuer(B.getString("Issuer"));
|
||||
if (B.containsKey("FirmwareVersion")) firmwareVersion = B.getString("FirmwareVersion");
|
||||
if (B.containsKey("Batch")) batch = B.getString("Batch");
|
||||
|
||||
if(B.containsKey("isBalanceEqual")) setIsBalanceEqual(B.getBoolean("isBalanceEqual"));
|
||||
cardPublicKeyValid = B.getBoolean("CardPublicKeyValid");
|
||||
|
|
@ -1406,7 +1448,7 @@ public class TangemCard {
|
|||
if (B.containsKey("Denomination")) setDenomination(B.getByteArray("Denomination"));
|
||||
else clearDenomination();
|
||||
|
||||
if (B.containsKey("IssuerData"))
|
||||
if (B.containsKey("IssuerData") && B.containsKey("IssuerDataSignature"))
|
||||
setIssuerData(B.getByteArray("IssuerData"), B.getByteArray("IssuerDataSignature"));
|
||||
else setIssuerData(null, null);
|
||||
|
||||
|
|
@ -1461,26 +1503,47 @@ public class TangemCard {
|
|||
if (B.containsKey("confirmTx"))
|
||||
countConfirmTX = new BigInteger(B.getString("confirmTx"), 16);
|
||||
|
||||
if( B.containsKey("codeConfirmed") )
|
||||
codeConfirmed=B.getBoolean("codeConfirmed");
|
||||
if (B.containsKey("codeConfirmed"))
|
||||
codeConfirmed = B.getBoolean("codeConfirmed");
|
||||
|
||||
if( B.containsKey("onlineVerified") )
|
||||
onlineVerified=B.getBoolean("onlineVerified");
|
||||
if (B.containsKey("onlineVerified"))
|
||||
onlineVerified = B.getBoolean("onlineVerified");
|
||||
|
||||
if( B.containsKey("onlineValidated") )
|
||||
onlineValidated=B.getBoolean("onlineValidated");
|
||||
if (B.containsKey("onlineValidated"))
|
||||
onlineValidated = B.getBoolean("onlineValidated");
|
||||
}
|
||||
|
||||
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
|
||||
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
if (bytes == null) return "";
|
||||
char[] hexChars = new char[bytes.length * 2];
|
||||
for (int j = 0; j < bytes.length; j++) {
|
||||
int v = bytes[j] & 0xFF;
|
||||
hexChars[j * 2] = hexArray[v >>> 4];
|
||||
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
|
||||
}
|
||||
return new String(hexChars);
|
||||
}
|
||||
|
||||
public int getCardImageResource() {
|
||||
switch (getBlockchainID()) {
|
||||
case "BTC":
|
||||
return R.drawable.card_btc001;
|
||||
if (bytesToHex(getDenomination()).equals("40420F0000000000"))
|
||||
return R.drawable.card_btc001;
|
||||
else if (bytesToHex(getDenomination()).equals("404B4C0000000000"))
|
||||
return R.drawable.card_btc005;
|
||||
else
|
||||
return R.drawable.card_default;
|
||||
|
||||
case "ETH\\XTZ":
|
||||
return R.drawable.card_seed;
|
||||
case "Token":
|
||||
if (getTokenSymbol().equals("SEED"))
|
||||
return R.drawable.card_seed;
|
||||
else
|
||||
return R.drawable.card_default;
|
||||
|
||||
default:
|
||||
return R.drawable.card_btc001;
|
||||
return R.drawable.card_default;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.presentation.activity;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.AssetManager;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.nfc.Tag;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -24,7 +25,9 @@ import android.widget.TextView;
|
|||
|
||||
import com.scottyab.rootbeer.RootBeer;
|
||||
import com.skyfishjy.library.RippleBackground;
|
||||
import com.tangem.domain.cardReader.FW;
|
||||
import com.tangem.domain.wallet.DeviceNFCAntennaLocation;
|
||||
import com.tangem.domain.wallet.Issuer;
|
||||
import com.tangem.domain.wallet.LastSignStorage;
|
||||
import com.tangem.domain.wallet.Logger;
|
||||
import com.tangem.domain.wallet.PINStorage;
|
||||
|
|
@ -244,6 +247,8 @@ public class MainActivity extends AppCompatActivity implements PopupMenu.OnMenuI
|
|||
if (LastSignStorage.needInit()) {
|
||||
LastSignStorage.Init(context);
|
||||
}
|
||||
if( Issuer.needInit() ) Issuer.Init(context);
|
||||
if( FW.needInit() ) FW.Init(context);
|
||||
}
|
||||
|
||||
public void showCleanButton() {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
|
||||
private int unsuccessReadCount = 0;
|
||||
private Tag lastTag = null;
|
||||
private String lastRead_UID = "";
|
||||
// private String lastRead_UID = "";
|
||||
|
||||
public Main() {
|
||||
}
|
||||
|
|
@ -119,9 +119,9 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
int cardIndex = viewHolder.getAdapterPosition();
|
||||
if (cardIndex < 0 || cardIndex >= mCardListAdapter.getItemCount()) return;
|
||||
slCardUIDs.remove(mCardListAdapter.getCard(cardIndex).getUID());
|
||||
if (mCardListAdapter.getCard(cardIndex).getUID() == lastRead_UID) {
|
||||
lastRead_UID = "";
|
||||
}
|
||||
// if (mCardListAdapter.getCard(cardIndex).getUID() == lastRead_UID) {
|
||||
// lastRead_UID = "";
|
||||
// }
|
||||
mCardListAdapter.removeCard(cardIndex);
|
||||
if (mCardListAdapter.getItemCount() == 0 && getActivity().getClass() == MainActivity.class) {
|
||||
((MainActivity) getActivity()).hideCleanButton();
|
||||
|
|
@ -142,6 +142,7 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
ReadCardInfoTask.resetLastReadInfo();
|
||||
mNfcManager.onResume();
|
||||
}
|
||||
|
||||
|
|
@ -201,8 +202,13 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
}
|
||||
|
||||
}
|
||||
} else if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_ENTER_PIN_ACTIVITY) {
|
||||
if (lastTag != null) onTagDiscovered(lastTag);
|
||||
} else if (requestCode == REQUEST_CODE_ENTER_PIN_ACTIVITY) {
|
||||
if( resultCode == Activity.RESULT_OK && lastTag != null)
|
||||
{
|
||||
onTagDiscovered(lastTag);
|
||||
}else{
|
||||
ReadCardInfoTask.resetLastReadInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -233,13 +239,14 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
}
|
||||
lastTag = tag;
|
||||
|
||||
readCardInfoTask = new ReadCardInfoTask(getActivity(), mNfcManager, lastRead_UID, isoDep, this);
|
||||
readCardInfoTask = new ReadCardInfoTask(getActivity(), mNfcManager, isoDep, this);
|
||||
readCardInfoTask.start();
|
||||
|
||||
Log.i(TAG, "onTagDiscovered " + Arrays.toString(tag.getId()));
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
mNfcManager.notifyReadResult(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -290,6 +297,7 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
readCardInfoTask = null;
|
||||
if (cardProtocol != null) {
|
||||
if (cardProtocol.getError() == null) {
|
||||
mNfcManager.notifyReadResult(true);
|
||||
progressBar.post(() -> {
|
||||
rlProgressBar.setVisibility(View.GONE);
|
||||
progressBar.setProgress(100);
|
||||
|
|
@ -334,7 +342,6 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
for (RequestWalletInfoTask rt : requestTasks) {
|
||||
rt.cancel(true);
|
||||
}
|
||||
lastRead_UID = "";
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -349,12 +356,15 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
slCardUIDs.remove(cardProtocol.getCard().getUID());
|
||||
if (cardProtocol.getError() instanceof CardProtocol.TangemException_InvalidPIN) {
|
||||
doEnterPIN();
|
||||
} else if (cardProtocol.getError() instanceof CardProtocol.TangemException_ExtendedLengthNotSupported) {
|
||||
if (!NoExtendedLengthSupportDialog.allreadyShowed) {
|
||||
new NoExtendedLengthSupportDialog().show(Objects.requireNonNull(getActivity()).getFragmentManager(), NoExtendedLengthSupportDialog.TAG);
|
||||
}
|
||||
} else {
|
||||
if (cardProtocol.getError() instanceof CardProtocol.TangemException_ExtendedLengthNotSupported) {
|
||||
if (!NoExtendedLengthSupportDialog.allreadyShowed) {
|
||||
new NoExtendedLengthSupportDialog().show(Objects.requireNonNull(getActivity()).getFragmentManager(), NoExtendedLengthSupportDialog.TAG);
|
||||
}
|
||||
}
|
||||
lastTag = null;
|
||||
ReadCardInfoTask.resetLastReadInfo();
|
||||
mNfcManager.notifyReadResult(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -376,6 +386,7 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
|
||||
public void OnReadCancel() {
|
||||
readCardInfoTask = null;
|
||||
ReadCardInfoTask.resetLastReadInfo();
|
||||
progressBar.postDelayed(() -> {
|
||||
try {
|
||||
rlProgressBar.setVisibility(View.GONE);
|
||||
|
|
@ -410,7 +421,7 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
for (RequestWalletInfoTask rt : requestTasks) {
|
||||
rt.cancel(true);
|
||||
}
|
||||
lastRead_UID = "";
|
||||
ReadCardInfoTask.resetLastReadInfo();
|
||||
}
|
||||
|
||||
public void refreshCard(TangemCard card) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue