diff --git a/.idea/dictionaries/tangem.xml b/.idea/dictionaries/tangem.xml
new file mode 100644
index 0000000000..e77bbeb7ed
--- /dev/null
+++ b/.idea/dictionaries/tangem.xml
@@ -0,0 +1,16 @@
+
+
+
+ binance
+ blockchain
+ cardano
+ ducatus
+ ethereum
+ litecoin
+ matic
+ tangem
+ testnet
+ tezos
+
+
+
\ No newline at end of file
diff --git a/blockchain-demo/src/main/java/com/tangem/blockchain_demo/BlockchainDemoActivity.kt b/blockchain-demo/src/main/java/com/tangem/blockchain_demo/BlockchainDemoActivity.kt
index 0028ee31c5..76d9ce0ffa 100644
--- a/blockchain-demo/src/main/java/com/tangem/blockchain_demo/BlockchainDemoActivity.kt
+++ b/blockchain-demo/src/main/java/com/tangem/blockchain_demo/BlockchainDemoActivity.kt
@@ -4,24 +4,23 @@ import android.os.Bundle
import android.text.Editable
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import com.tangem.CardManager
+import com.tangem.SessionError
+import com.tangem.TangemSdk
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.Signer
import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain_demo.databinding.ActivityBlockchainDemoBinding
import com.tangem.commands.Card
+import com.tangem.common.CompletionResult
import com.tangem.tangem_sdk_new.extensions.init
-import com.tangem.tasks.ScanEvent
-import com.tangem.tasks.TaskError
-import com.tangem.tasks.TaskEvent
import kotlinx.coroutines.*
import java.math.BigDecimal
import kotlin.coroutines.CoroutineContext
class BlockchainDemoActivity : AppCompatActivity() {
- private lateinit var cardManager: CardManager
+ private lateinit var tangemSdk: TangemSdk
private lateinit var signer: TransactionSigner
private lateinit var card: Card
private lateinit var walletManager: WalletManager
@@ -47,8 +46,8 @@ class BlockchainDemoActivity : AppCompatActivity() {
val view = binding.root
setContentView(view)
- cardManager = CardManager.init(this)
- signer = Signer(cardManager)
+ tangemSdk = TangemSdk.init(this)
+ signer = Signer(tangemSdk)
binding.btnScan.setOnClickListener { scan() }
@@ -59,27 +58,20 @@ class BlockchainDemoActivity : AppCompatActivity() {
private fun scan() {
- cardManager.scanCard { taskEvent ->
- when (taskEvent) {
- is TaskEvent.Event -> {
- when (taskEvent.data) {
- is ScanEvent.OnReadEvent -> {
- card = (taskEvent.data as ScanEvent.OnReadEvent).card
- walletManager = WalletManagerFactory.makeWalletManager(card)!!
+ tangemSdk.scanCard { result ->
+ when (result) {
+ is CompletionResult.Success -> {
+ walletManager = WalletManagerFactory.makeWalletManager(result.data)!!
getInfo()
}
- }
- }
- is TaskEvent.Completion -> {
- if (taskEvent.error != null) {
- if (taskEvent.error !is TaskError.UserCancelled) {
- handleError(taskEvent.error.toString())
+ is CompletionResult.Failure -> {
+ if (result.error !is SessionError.UserCancelled) {
+ handleError(result.error.toString())
}
}
}
}
}
- }
private fun getInfo() {
scope.launch {
diff --git a/blockchain/src/main/java/com/tangem/blockchain/bitcoin/BitcoinWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/bitcoin/BitcoinWalletManager.kt
index 58ae155e27..72a18f08fc 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/bitcoin/BitcoinWalletManager.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/bitcoin/BitcoinWalletManager.kt
@@ -8,8 +8,8 @@ import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.wallets.CurrencyWallet
+import com.tangem.common.CompletionResult
import com.tangem.common.extensions.toHexString
-import com.tangem.tasks.TaskEvent
import java.math.BigDecimal
class BitcoinWalletManager(
@@ -66,11 +66,11 @@ class BitcoinWalletManager(
is Result.Failure -> return SimpleResult.Failure(buildTransactionResult.error)
is Result.Success -> {
when (val signerResponse = signer.sign(buildTransactionResult.data.toTypedArray(), cardId)) {
- is TaskEvent.Event -> {
+ is CompletionResult.Success -> {
val transactionToSend = transactionBuilder.buildToSend(signerResponse.data.signature, walletPublicKey)
return networkManager.sendTransaction(transactionToSend.toHexString())
}
- is TaskEvent.Completion -> return SimpleResult.Failure(signerResponse.error)
+ is CompletionResult.Failure -> return SimpleResult.Failure(signerResponse.error)
}
}
}
diff --git a/blockchain/src/main/java/com/tangem/blockchain/cardano/CardanoWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/cardano/CardanoWalletManager.kt
index edf2acefbb..86b5f25a51 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/cardano/CardanoWalletManager.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/cardano/CardanoWalletManager.kt
@@ -8,7 +8,7 @@ import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.common.extensions.encodeBase64NoWrap
import com.tangem.blockchain.wallets.CurrencyWallet
-import com.tangem.tasks.TaskEvent
+import com.tangem.common.CompletionResult
class CardanoWalletManager(
private val cardId: String,
@@ -47,11 +47,11 @@ class CardanoWalletManager(
val transactionHash = transactionBuilder.buildToSign(transactionData)
when (val signerResponse = signer.sign(arrayOf(transactionHash), cardId)) {
- is TaskEvent.Event -> {
+ is CompletionResult.Success -> {
val transactionToSend = transactionBuilder.buildToSend(signerResponse.data.signature, walletPublicKey)
return networkManager.sendTransaction(transactionToSend.encodeBase64NoWrap())
}
- is TaskEvent.Completion -> return SimpleResult.Failure(signerResponse.error)
+ is CompletionResult.Failure -> return SimpleResult.Failure(signerResponse.error)
}
}
diff --git a/blockchain/src/main/java/com/tangem/blockchain/common/WalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/common/WalletManager.kt
index c39d9b6c0e..6fe5a862ea 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/common/WalletManager.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/common/WalletManager.kt
@@ -4,7 +4,7 @@ import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.wallets.CurrencyWallet
import com.tangem.commands.SignResponse
-import com.tangem.tasks.TaskEvent
+import com.tangem.common.CompletionResult
interface WalletManager {
var wallet: CurrencyWallet
@@ -18,7 +18,7 @@ interface TransactionSender {
}
interface TransactionSigner {
- suspend fun sign(hashes: Array, cardId: String): TaskEvent
+ suspend fun sign(hashes: Array, cardId: String): CompletionResult
}
interface FeeProvider {
diff --git a/blockchain/src/main/java/com/tangem/blockchain/common/extensions/Coroutines.kt b/blockchain/src/main/java/com/tangem/blockchain/common/extensions/Coroutines.kt
index cdf9edd92e..8451a23b67 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/common/extensions/Coroutines.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/common/extensions/Coroutines.kt
@@ -1,9 +1,9 @@
package com.tangem.blockchain.common.extensions
-import com.tangem.CardManager
+import com.tangem.TangemSdk
import com.tangem.blockchain.common.TransactionSigner
import com.tangem.commands.SignResponse
-import com.tangem.tasks.TaskEvent
+import com.tangem.common.CompletionResult
import kotlinx.coroutines.delay
import kotlinx.coroutines.suspendCancellableCoroutine
import java.io.IOException
@@ -54,10 +54,10 @@ sealed class SimpleResult {
data class Failure(val error: Throwable?) : SimpleResult()
}
-class Signer(private val cardManager: CardManager) : TransactionSigner {
- override suspend fun sign(hashes: Array, cardId: String): TaskEvent =
+class Signer(private val tangemSdk: TangemSdk) : TransactionSigner {
+ override suspend fun sign(hashes: Array, cardId: String): CompletionResult =
suspendCancellableCoroutine { continuation ->
- cardManager.sign(hashes, cardId) { result ->
+ tangemSdk.sign(hashes, cardId) { result ->
if (continuation.isActive) continuation.resume(result)
}
}
diff --git a/blockchain/src/main/java/com/tangem/blockchain/ethereum/EthereumWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/ethereum/EthereumWalletManager.kt
index d7c26e526e..3999bdf7a3 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/ethereum/EthereumWalletManager.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/ethereum/EthereumWalletManager.kt
@@ -8,8 +8,8 @@ import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.ethereum.network.EthereumNetworkManager
import com.tangem.blockchain.ethereum.network.EthereumResponse
import com.tangem.blockchain.wallets.CurrencyWallet
+import com.tangem.common.CompletionResult
import com.tangem.common.extensions.toHexString
-import com.tangem.tasks.TaskEvent
import org.kethereum.DEFAULT_GAS_LIMIT
import org.kethereum.crypto.api.ec.ECDSASignature
import org.kethereum.crypto.determineRecId
@@ -81,11 +81,11 @@ class EthereumWalletManager(
val transactionToSign = builder.buildToSign(transactionData, txCount.toBigInteger())
?: return SimpleResult.Failure(Exception("Not enough data"))
when (val signerResponse = signer.sign(transactionToSign.hashes.toTypedArray(), cardId)) {
- is TaskEvent.Event -> {
+ is CompletionResult.Success -> {
val transactionToSend = builder.buildToSend(signerResponse.data.signature, transactionToSign, walletPublicKey)
return networkManager.sendTransaction(String.format("0x%s", transactionToSend.toHexString()))
}
- is TaskEvent.Completion -> return SimpleResult.Failure(signerResponse.error)
+ is CompletionResult.Failure -> return SimpleResult.Failure(signerResponse.error)
}
}
diff --git a/blockchain/src/main/java/com/tangem/blockchain/stellar/StellarWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/stellar/StellarWalletManager.kt
index e65278fa35..754cf7fa60 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/stellar/StellarWalletManager.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/stellar/StellarWalletManager.kt
@@ -5,7 +5,7 @@ import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.wallets.CurrencyWallet
-import com.tangem.tasks.TaskEvent
+import com.tangem.common.CompletionResult
import java.math.BigDecimal
import java.util.*
@@ -58,11 +58,11 @@ class StellarWalletManager(
override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult {
val hashes = builder.buildToSign(transactionData, sequence, baseFee.toStroops())
when (val signerResponse = signer.sign(hashes.toTypedArray(), cardId)) {
- is TaskEvent.Event -> {
+ is CompletionResult.Success -> {
val transactionToSend = builder.buildToSend(signerResponse.data.signature)
return networkManager.sendTransaction(transactionToSend)
}
- is TaskEvent.Completion -> return SimpleResult.Failure(signerResponse.error)
+ is CompletionResult.Failure -> return SimpleResult.Failure(signerResponse.error)
}
}
diff --git a/blockchain/src/main/java/com/tangem/blockchain/xrp/XrpWalletManager.kt b/blockchain/src/main/java/com/tangem/blockchain/xrp/XrpWalletManager.kt
index bba2e26427..cf6c8206a8 100644
--- a/blockchain/src/main/java/com/tangem/blockchain/xrp/XrpWalletManager.kt
+++ b/blockchain/src/main/java/com/tangem/blockchain/xrp/XrpWalletManager.kt
@@ -7,7 +7,7 @@ import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.wallets.CurrencyWallet
import com.tangem.blockchain.xrp.network.XrpInfoResponse
import com.tangem.blockchain.xrp.network.XrpNetworkManager
-import com.tangem.tasks.TaskEvent
+import com.tangem.common.CompletionResult
class XrpWalletManager(
private val cardId: String,
@@ -68,11 +68,11 @@ class XrpWalletManager(
val transactionHash = transactionBuilder.buildToSign(transactionData)
when (val signerResponse = signer.sign(arrayOf(transactionHash), cardId)) {
- is TaskEvent.Event -> {
+ is CompletionResult.Success -> {
val transactionToSend = transactionBuilder.buildToSend(signerResponse.data.signature)
return networkManager.sendTransaction(transactionToSend)
}
- is TaskEvent.Completion -> return SimpleResult.Failure(signerResponse.error)
+ is CompletionResult.Failure -> return SimpleResult.Failure(signerResponse.error)
}
}
diff --git a/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt b/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt
index a476130557..9ce1fd90ac 100644
--- a/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt
+++ b/blockchain/src/test/java/com/tangem/blockchain/common/WalletManagerFactoryTest.kt
@@ -1,7 +1,7 @@
package com.tangem.blockchain.common
import com.google.common.truth.Truth
-import com.tangem.common.CardEnvironment
+import com.tangem.SessionEnvironment
import com.tangem.blockchain.bitcoin.BitcoinWalletManager
import com.tangem.blockchain.cardano.CardanoWalletManager
import com.tangem.blockchain.ethereum.EthereumWalletManager
@@ -18,7 +18,7 @@ internal class WalletManagerFactoryTest {
fun createBitcoinWalletManager() {
val data = "0108bb00000000000304200754414e47454d00020102800a322e3432642053444b000341040876bdec26b89bd2159a668b9af3d9fe86370f318717c92b8d6c1186fb3648c32a5f9321998cc2d042901c91d40601e79a641e1cbcebe7a2358be6054e1b6e5d0a04041e76310c618102ffff8a0101820407e30b0d830b54414e47454d2053444b0084034254438640e17ceec48c5be36240c98019f95ad8b6e56acfebe60d11979c6279f715d607d76a860a137da8d109e805753f3f56b0130709f4bbf4cb9974b4c57b8469bf4b873041045f16bd1d2eafe463e62a335a09e6b2bbcbd04452526885cb679fc4d27af1bd22f553c7deefb54fd3d4f361d14e6dc3f11b7d4ea183250a60720ebdf9e110cd26050a736563703235366b310008040000006407010009020bb8604104752a727e14bba5bd73b6714d72500f61ffd11026ad1196d2e1c54577cbeeac3d11fc68a64700f8d533f4e311964ea8fb3aa26c588295f2133868d69c3e62869362040000005c6304000000090f01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(CardEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card!!)
Truth.assertThat(walletManager)
@@ -29,7 +29,7 @@ internal class WalletManagerFactoryTest {
fun createEthereumWalletManager() {
val data = "0108bb00000000000536200754414e47454d00020102800a322e3432642053444b000341046c8aea0d5a850b0a608acf9a0c453c39ea86131e88bfa78800de3cfb5bf1007aeaa7b9ffc184212255758605c2461be343c0a661d73cabafa4c9c175b3f0e59a0a04041e76310c618102ffff8a0101820407e30b0d830b54414e47454d2053444b0084034554488640431b6244acfeac479becdff201a7f720a7d70a97edc4e019fb678596baf52dfe9d0e8faf08ceb4443b82d4e66815541f2dc8ec6dd3ff83eb42f06e5eab07f25f3041045f16bd1d2eafe463e62a335a09e6b2bbcbd04452526885cb679fc4d27af1bd22f553c7deefb54fd3d4f361d14e6dc3f11b7d4ea183250a60720ebdf9e110cd26050a736563703235366b3100080400000064070100090205dc60410464dddc3f356744aaecfa07427f9eb996ff537d65f20fb5be3abccf0354352a6b5f8a1942e0f8ddeea3a170eda78d060be8162ad60e94e4e91fbbdf0a7054785562040000005b6304000000090f01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(CardEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card!!)
Truth.assertThat(walletManager)
@@ -40,7 +40,7 @@ internal class WalletManagerFactoryTest {
fun createStellarWalletManager() {
val data = "0108bb00000000000379200754414e47454d00020102800a322e3432642053444b0003410487d7bb51b189213e3cedc3fcfa3fc047b3b71b7805b5b215e14639b3a8ebb1952c9dd5ea4354441b6ada4e8b8327674bb102ddae69df55be69643a2c916edf650a04041e76310c618102ffff8a0101820407e30b0d830b54414e47454d2053444b008403584c4d86409a4bc2baf0e5836887da21167cf33458d5249d1a610bced0e31dc053f23729ed24d715912bf89e6804669430dfe396ed83274e0031f6803e2bdb8c041fa993413041045f16bd1d2eafe463e62a335a09e6b2bbcbd04452526885cb679fc4d27af1bd22f553c7deefb54fd3d4f361d14e6dc3f11b7d4ea183250a60720ebdf9e110cd2605086564323535313900080400000064070100090205dc6020e078212d58b2b9d0edc9c936830d10081cd38b90c31778c56dfb1171027e294e62040000003863040000002c0f01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(CardEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card!!)
Truth.assertThat(walletManager)
@@ -51,7 +51,7 @@ internal class WalletManagerFactoryTest {
fun createCardanoWalletManager() {
val data = "0108bb00000000000502200754414e47454d00020102800a322e3432642053444b0003410402c1e39257d60583489da2d67d35d1cc2a1c005cc05c1021f44838edcaf25d5615cad7c9d11c2e23f5efa93e50904d33c88808d0e169060508df840992e31f4d0a04041e76310c658102ffff8a0101820407e30b0d830b54414e47454d2053444b00840743415244414e4f8640f24ef5c8c6eba0ff97560d5b013edb4a452594270db9647bd0a3543df8104dec75731d4db3ebe0fc493f2afee00195e560b51e3c41189b7c61ba7895d6434b9d3041045f16bd1d2eafe463e62a335a09e6b2bbcbd04452526885cb679fc4d27af1bd22f553c7deefb54fd3d4f361d14e6dc3f11b7d4ea183250a60720ebdf9e110cd2605086564323535313900080400000064070100090205dc60208a71161cfdf1e0a85d8e7ff372aa4a01136046292aceb5f9ad7ebdb98d3f60a86204000000646304000000000f01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(CardEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card!!)
Truth.assertThat(walletManager)
@@ -62,7 +62,7 @@ internal class WalletManagerFactoryTest {
fun createXrpWalletManager() {
val data = "0108cb21000000002154200b534d4152542043415348000201028006322e31317200034104bdad63848f97c535da53cf8fd300d24fa33f0516d194aa78ec164a06994d00204bae243a424e316c6ec845e02d9b15eafae8c19018a926b0b7435e6e941cdadb0a0400007e210c5a81020028820407e30502830754414e47454d00840358525086400ed8734b877869722c7d0b37ffb154b9fef21c54bf2c6496feb1fb5c1fc28a2ac28e201dde84f27495fa7f08b3ca2be2fb4954bf0fe78af027d6cdc16c3eee923041048196aa4b410ac44a3b9cce18e7be226aea070acc83a9cf67540fac49af25129f6a538a28ad6341358e3c4f9963064f7e365372a651d374e5c23cdd37fd099bf2050a736563703235366b31000804000f4240070100090205dc604104d2b9fb288540d54e5b32ecaf0381cd571f97f6f1ecd036b66bb11aa52ffe9981110d883080e2e255c6b1640586f7765e6faa325d1340f49b56b83d9de56bc7ed6204000f42406304000000000f01009000"
val responseApdu = ResponseApdu(data.hexToBytes())
- val card = ReadCommand().deserialize(CardEnvironment(), responseApdu)
+ val card = ReadCommand().deserialize(SessionEnvironment(), responseApdu)
val walletManager = WalletManagerFactory.makeWalletManager(card!!)
Truth.assertThat(walletManager)
diff --git a/tangem-core/src/main/java/com/tangem/CardManager.kt b/tangem-core/src/main/java/com/tangem/CardManager.kt
deleted file mode 100644
index c5a1f99e77..0000000000
--- a/tangem-core/src/main/java/com/tangem/CardManager.kt
+++ /dev/null
@@ -1,330 +0,0 @@
-package com.tangem
-
-import com.tangem.commands.*
-import com.tangem.commands.personalization.DepersonalizeCommand
-import com.tangem.commands.personalization.DepersonalizeResponse
-import com.tangem.commands.personalization.PersonalizeCommand
-import com.tangem.commands.personalization.entities.Acquirer
-import com.tangem.commands.personalization.entities.CardConfig
-import com.tangem.commands.personalization.entities.Issuer
-import com.tangem.commands.personalization.entities.Manufacturer
-import com.tangem.common.CardEnvironment
-import com.tangem.common.TerminalKeysService
-import com.tangem.crypto.CryptoUtils
-import com.tangem.tasks.*
-
-/**
- * The main interface of Tangem SDK that allows your app to communicate with Tangem cards.
- *
- * @property reader is an interface that is responsible for NFC connection and
- * transfer of data to and from the Tangem Card.
- * Its default implementation, NfcCardReader, is in our tangem-sdk module.
- * @property cardManagerDelegate An interface that allows interaction with users and shows relevant UI.
- * Its default implementation, DefaultCardManagerDelegate, is in our tangem-sdk module.
- */
-class CardManager(
- private val reader: CardReader,
- private val cardManagerDelegate: CardManagerDelegate? = null,
- private val config: Config = Config()
-) {
-
- private var terminalKeysService: TerminalKeysService? = null
- private var isBusy = false
-
- init {
- CryptoUtils.initCrypto()
- }
-
- /**
- * To start using any card, you first need to read it using the scanCard() method.
- * This method launches an NFC session, and once it’s connected with the card,
- * it obtains the card data. Optionally, if the card contains a wallet (private and public key pair),
- * it proves that the wallet owns a private key that corresponds to a public one.
- *
- * It launches on the new thread a [ScanTask] that will send the following events in a callback:
- * [ScanEvent.OnReadEvent] after completing [com.tangem.commands.ReadCommand]
- * [ScanEvent.OnVerifyEvent] after completing [com.tangem.commands.CheckWalletCommand]
- * [TaskEvent.Completion] with an error field null after successful completion of a task or
- * [TaskEvent.Completion] with a [TaskError] if some error occurs.
- * @param callback is triggered on events during a performance of the task,
- * provides data in form of [ScanEvent] subclasses.
- */
- fun scanCard(callback: (result: TaskEvent) -> Unit) {
- val task = ScanTask()
- runTask(task, callback = callback)
- }
-
- /**
- * This method allows you to sign one or multiple hashes.
- * Simultaneous signing of array of hashes in a single [SignCommand] is required to support
- * Bitcoin-type multi-input blockchains (UTXO).
- * The [SignCommand] will return a corresponding array of signatures.
- *
- * This method launches on the new thread [SignCommand] that will send the following events in a callback:
- * [SignResponse] after completing [SignCommand]
- * [TaskEvent.Completion] with an error field null after successful completion of a task or
- * [TaskEvent.Completion] with a [TaskError] if some error occurs.
- * Please note that Tangem cards usually protect the signing with a security delay
- * that may last up to 90 seconds, depending on a card.
- * It is for [CardManagerDelegate] to notify users of security delay.
- * @param hashes Array of transaction hashes. It can be from one or up to ten hashes of the same length.
- * @param cardId CID, Unique Tangem card ID number
- * @param callback is triggered on the completion of the [SignCommand],
- * provides card response in the form of [SignResponse].
- */
- fun sign(hashes: Array, cardId: String,
- callback: (result: TaskEvent) -> Unit) {
- val signCommand = SignCommand(hashes)
- val task = SingleCommandTask(signCommand)
- runTask(task, cardId, callback)
- }
-
- /**
- * This command returns 512-byte Issuer Data field and its issuer’s signature.
- * Issuer Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
- * format and payload of Issuer Data. For example, this field may contain information about
- * wallet balance signed by the issuer or additional issuer’s attestation data.
- * @param cardId CID, Unique Tangem card ID number.
- * @param callback is triggered on the completion of the [ReadIssuerDataCommand],
- * provides card response in the form of [ReadIssuerDataResponse].
- */
- fun readIssuerData(cardId: String,
- callback: (result: TaskEvent) -> Unit) {
- val task = ReadIssuerDataTask(config.issuerPublicKey)
- runTask(task, cardId, callback)
- }
-
- /**
- * This task retrieves Issuer Extra Data field and its issuer’s signature.
- * Issuer Extra Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
- * format and payload of Issuer Data. . For example, this field may contain photo or
- * biometric information for ID card product. Because of the large size of Issuer_Extra_Data,
- * a series of these commands have to be executed to read the entire Issuer_Extra_Data.
- * @param cardId CID, Unique Tangem card ID number.
- * @param callback is triggered on the completion of the [ReadIssuerExtraDataTask],
- * provides card response in the form of [ReadIssuerExtraDataResponse].
- */
- fun readIssuerExtraData(cardId: String,
- callback: (result: TaskEvent) -> Unit) {
- val task = ReadIssuerExtraDataTask(config.issuerPublicKey)
- runTask(task, cardId, callback)
- }
-
- /**
- * This command writes 512-byte Issuer Data field and its issuer’s signature.
- * Issuer Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
- * format and payload of Issuer Data. For example, this field may contain information about
- * wallet balance signed by the issuer or additional issuer’s attestation data.
- * @param cardId CID, Unique Tangem card ID number.
- * @param issuerData Data provided by issuer.
- * @param issuerDataSignature Issuer’s signature of [issuerData] with Issuer Data Private Key.
- * @param issuerDataCounter An optional counter that protect issuer data against replay attack.
- * @param callback is triggered on the completion of the [WriteIssuerDataCommand],
- * provides card response in the form of [WriteIssuerDataResponse].
- */
- fun writeIssuerData(cardId: String,
- issuerData: ByteArray,
- issuerDataSignature: ByteArray,
- issuerDataCounter: Int? = null,
- callback: (result: TaskEvent) -> Unit) {
- val task = WriteIssuerDataTask(
- issuerData,
- issuerDataSignature,
- issuerDataCounter,
- config.issuerPublicKey
- )
- runTask(task, cardId, callback)
- }
-
- /**
- * This task writes Issuer Extra Data field and its issuer’s signature.
- * Issuer Extra Data is never changed or parsed from within the Tangem COS.
- * The issuer defines purpose of use, format and payload of Issuer Data.
- * For example, this field may contain a photo or biometric information for ID card products.
- * Because of the large size of Issuer_Extra_Data, a series of these commands have to be executed
- * to write entire Issuer_Extra_Data.
- * @param cardId CID, Unique Tangem card ID number.
- * @param issuerData Data provided by issuer.
- * @param startingSignature Issuer’s signature with Issuer Data Private Key of [cardId],
- * [issuerDataCounter] (if flags Protect_Issuer_Data_Against_Replay and
- * Restrict_Overwrite_Issuer_Extra_Data are set in [SettingsMask]) and size of [issuerData].
- * @param finalizingSignature Issuer’s signature with Issuer Data Private Key of [cardId],
- * [issuerData] and [issuerDataCounter] (the latter one only if flags Protect_Issuer_Data_Against_Replay
- * andRestrict_Overwrite_Issuer_Extra_Data are set in [SettingsMask]).
- * @param issuerDataCounter An optional counter that protect issuer data against replay attack.
- * @param callback is triggered on the completion of the [WriteIssuerDataCommand],
- * provides card response in the form of [WriteIssuerDataResponse].
- */
- fun writeIssuerExtraData(cardId: String,
- issuerData: ByteArray,
- startingSignature: ByteArray,
- finalizingSignature: ByteArray,
- issuerDataCounter: Int? = null,
- callback: (result: TaskEvent) -> Unit) {
- val task = WriteIssuerExtraDataTask(
- issuerData,
- startingSignature, finalizingSignature,
- config.issuerPublicKey,
- issuerDataCounter
- )
- runTask(task, cardId, callback)
- }
-
- /**
- * This command write some of User_Data, User_ProtectedData, User_Counter and User_ProtectedCounter fields.
- * User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS.
- * The App defines purpose of use, format and it's payload. For example, this field may contain cashed information
- * from blockchain to accelerate preparing new transaction.
- * User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing
- * of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use.
- * For example, this fields may contain blockchain nonce value.
- *
- * Writing of User_Counter and User_Data protected only by PIN1.
- * User_ProtectedCounter and User_ProtectedData additionaly need PIN2 to confirmation.
- */
- fun writeUserData(
- cardId: String,
- userData: ByteArray? = null,
- userProtectedData: ByteArray? = null,
- userCounter: Int? = null,
- userProtectedCounter: Int? = null,
- callback: (result: TaskEvent) -> Unit
- ) {
- val writeUserDataCommand = WriteUserDataCommand(userData, userProtectedData, userCounter, userProtectedCounter)
- val task = SingleCommandTask(writeUserDataCommand)
- runTask(task, cardId, callback)
- }
-
- /**
- * This command returns two up to 512-byte User_Data, User_Protected_Data and two counters User_Counter and
- * User_Protected_Counter fields.
- * User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS.
- * The App defines purpose of use, format and it's payload. For example, this field may contain cashed information
- * from blockchain to accelerate preparing new transaction.
- * User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing
- * of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use.
- * For example, this fields may contain blockchain nonce value.
- */
- fun readUserData(cardId: String, callback: (result: TaskEvent) -> Unit) {
- val task = SingleCommandTask(ReadUserDataCommand())
- runTask(task, cardId, callback)
- }
-
- /**
- * This command will create a new wallet on the card having ‘Empty’ state.
- * A key pair WalletPublicKey / WalletPrivateKey is generated and securely stored in the card.
- * App will need to obtain Wallet_PublicKey from the response of [CreateWalletCommand] or [ReadCommand]
- * and then transform it into an address of corresponding blockchain wallet
- * according to a specific blockchain algorithm.
- * WalletPrivateKey is never revealed by the card and will be used by [SignCommand] and [CheckWalletCommand].
- * RemainingSignature is set to MaxSignatures.
- * @param cardId CID, Unique Tangem card ID number.
- */
- fun createWallet(cardId: String,
- callback: (result: TaskEvent) -> Unit) {
- val createWalletCommand = CreateWalletCommand()
- val task = SingleCommandTask(createWalletCommand)
- runTask(task, cardId, callback)
- }
-
- /**
- * This command deletes all wallet data. If Is_Reusable flag is enabled during personalization,
-
- * If Is_Reusable flag is disabled, the card switches to ‘Purged’ state.
- * ‘Purged’ state is final, it makes the card useless.
- * @param cardId CID, Unique Tangem card ID number.
- */
- fun purgeWallet(cardId: String,
- callback: (result: TaskEvent) -> Unit) {
- val purgeWalletCommand = PurgeWalletCommand()
- val task = SingleCommandTask(purgeWalletCommand)
- runTask(task, cardId, callback)
- }
-
- /**
- * Command available on SDK cards only
- *
- * This command resets card to initial state,
- * erasing all data written during personalization and usage.
- * @param cardId CID, Unique Tangem card ID number.
- */
- fun depersonalize(cardId: String,
- callback: (result: TaskEvent) -> Unit) {
- val depersonalizeCommand = DepersonalizeCommand()
- val task = SingleCommandTask(depersonalizeCommand)
- runTask(task, cardId, callback)
- }
-
- /**
- * Command available on SDK cards only
- *
- * Personalization is an initialization procedure, required before starting using a card.
- * During this procedure a card setting is set up.
- * During this procedure all data exchange is encrypted.
- * @param config is a configuration file with all the card settings that are written on the card
- * during personalization.
- * @param issuer Issuer is a third-party team or company wishing to use Tangem cards.
- * @param manufacturer Tangem Card Manufacturer.
- * @param acquirer Acquirer is a trusted third-party company that operates proprietary
- * (non-EMV) POS terminal infrastructure and transaction processing back-end.
- */
- fun personalize(config: CardConfig,
- issuer: Issuer, manufacturer: Manufacturer, acquirer: Acquirer? = null,
- callback: (result: TaskEvent) -> Unit) {
- val personalizationCommand = PersonalizeCommand(config, issuer, manufacturer, acquirer)
- val task = SingleCommandTask(personalizationCommand)
- task.performPreflightRead = false
- runTask(task, callback = callback)
- }
-
- /**
-
- */
- fun runTask(task: Task, cardId: String? = null, callback: (result: TaskEvent) -> Unit) {
- if (isBusy) {
- callback(TaskEvent.Completion(TaskError.Busy()))
- return
- }
-
- val environment = prepareCardEnvironment(cardId)
- isBusy = true
-
- task.reader = reader
- task.delegate = cardManagerDelegate
-
- Thread().run {
- task.run(environment) { taskEvent ->
- if (taskEvent is TaskEvent.Completion) isBusy = false
- callback(taskEvent)
- }
- }
- }
-
- /**
-
- */
- fun runCommand(command: CommandSerializer,
- cardId: String? = null,
- callback: (result: TaskEvent) -> Unit) {
- val task = SingleCommandTask(command)
- runTask(task, cardId, callback)
- }
-
- /**
- * Allows to set a particular [TerminalKeysService] to retrieve terminal keys.
- * Default implementation is provided in tangem-sdk module: [TerminalKeysStorage].
- */
- fun setTerminalKeysService(terminalKeysService: TerminalKeysService) {
- this.terminalKeysService = terminalKeysService
- }
-
- private fun prepareCardEnvironment(cardId: String?): CardEnvironment {
- val terminalKeys = if (config.linkedTerminal) terminalKeysService?.getKeys() else null
- return CardEnvironment(
- cardId = cardId,
- terminalKeys = terminalKeys
- )
- }
-
- companion object
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/CardSession.kt b/tangem-core/src/main/java/com/tangem/CardSession.kt
new file mode 100644
index 0000000000..9977e9b17f
--- /dev/null
+++ b/tangem-core/src/main/java/com/tangem/CardSession.kt
@@ -0,0 +1,221 @@
+package com.tangem
+
+import com.tangem.commands.Card
+import com.tangem.commands.CommandResponse
+import com.tangem.commands.OpenSessionCommand
+import com.tangem.commands.ReadCommand
+import com.tangem.common.CompletionResult
+import com.tangem.common.apdu.CommandApdu
+import com.tangem.common.apdu.ResponseApdu
+import com.tangem.common.extensions.calculateSha256
+import com.tangem.crypto.EncryptionHelper
+import com.tangem.crypto.FastEncryptionHelper
+import com.tangem.crypto.StrongEncryptionHelper
+import com.tangem.crypto.pbkdf2Hash
+
+/**
+ * Basic interface for running tasks and [com.tangem.commands.Command] in a [CardSession]
+ */
+interface CardSessionRunnable {
+
+ /**
+ * The starting point for custom business logic.
+ * Implement this interface and use [TangemSdk.startSession] to run.
+ * @param session run commands in this [CardSession].
+ * @param callback trigger the callback to complete the task.
+ */
+ fun run(session: CardSession, callback: (result: CompletionResult) -> Unit)
+}
+
+/**
+ * Allows interaction with Tangem cards. Should be opened before sending commands.
+ *
+ * @property environment
+ * @property reader is an interface that is responsible for NFC connection and
+ * transfer of data to and from the Tangem Card.
+ * @property viewDelegate is an interface that allows interaction with users and shows relevant UI.
+ * @property cardId ID, Unique Tangem card ID number. If not null, the SDK will check that you the card
+ * with which you tapped a phone has this [cardId] and SDK will return
+ * the [SessionError.WrongCard] otherwise.
+ * @property initialMessage A custom description that will be shown at the beginning of the NFC session.
+ * If null, a default header and text body will be used.
+ */
+class CardSession(
+ val environment: SessionEnvironment,
+ private val reader: CardReader,
+ val viewDelegate: SessionViewDelegate,
+ private var cardId: String? = null,
+ private val initialMessage: Message? = null
+) {
+
+ /**
+ * True if some operation is still in progress.
+ */
+ private var isBusy = false
+
+ /**
+ * This metod starts a card session, performs preflight [ReadCommand],
+ * invokes [CardSessionRunnable.run] and closes the session.
+ * @param runnable [CardSessionRunnable] that will be performed in the session.
+ * @param callback will be triggered with a [CompletionResult] of a session.
+ */
+ fun , R : CommandResponse> startWithRunnable(
+ runnable: T, callback: (result: CompletionResult) -> Unit) {
+
+ start { session, error ->
+ if (error != null) {
+ callback(CompletionResult.Failure(error))
+ return@start
+ }
+ if (runnable is ReadCommand) {
+ callback(CompletionResult.Success(environment.card as R))
+ return@start
+ }
+
+ runnable.run(this) { result ->
+ stop()
+ callback(result)
+ }
+ }
+ }
+
+ /**
+ * Starts a card session and performs preflight [ReadCommand].
+ * @param callback: callback with the card session. Can contain [SessionError] if something goes wrong.
+ */
+ fun start(callback: (session: CardSession, error: SessionError?) -> Unit) {
+ try {
+ startSession()
+ } catch (error: SessionError) {
+ callback(this, error)
+ }
+
+ preflightRead() { result ->
+ when (result) {
+ is CompletionResult.Failure -> {
+ callback(this, result.error)
+ stopWithError(result.error)
+ }
+ is CompletionResult.Success -> {
+ callback(this, null)
+
+ }
+ }
+ }
+ }
+
+ private fun startSession() {
+ if (isBusy) throw SessionError.Busy()
+ isBusy = true
+ viewDelegate.onNfcSessionStarted(cardId, initialMessage)
+ reader.openSession()
+ }
+
+ private fun preflightRead(callback: (result: CompletionResult) -> Unit) {
+ val readCommand = ReadCommand()
+ readCommand.run(this) { result ->
+ when (result) {
+ is CompletionResult.Failure -> {
+ tryHandleError(result.error) { handleErrorResult ->
+ when (handleErrorResult) {
+ is CompletionResult.Success -> preflightRead(callback)
+ is CompletionResult.Failure -> {
+ stopWithError(result.error)
+ callback(CompletionResult.Failure(result.error))
+ }
+ }
+ }
+ }
+ is CompletionResult.Success -> {
+ val receivedCardId = result.data.cardId
+ if (cardId != null && receivedCardId != cardId) {
+ stopWithError(SessionError.WrongCard())
+ callback(CompletionResult.Failure(SessionError.WrongCard()))
+ return@run
+ }
+ environment.card = result.data
+ cardId = receivedCardId
+ callback(CompletionResult.Success(result.data))
+ }
+ }
+ }
+ }
+
+ /**
+ * Stops the current session with the text message.
+ * @param message If null, the default message will be shown.
+ */
+ private fun stop(message: Message? = null) {
+ reader.closeSession()
+ viewDelegate.onNfcSessionCompleted(message)
+ isBusy = false
+ }
+
+ /**
+ * Stops the current session on error.
+ * @param error An error that will be shown.
+ */
+ private fun stopWithError(error: Exception) {
+ reader.closeSession()
+ isBusy = false
+
+ val errorMessage = if (error is SessionError) {
+ "${error::class.simpleName}: ${error.code}"
+ } else {
+ error.localizedMessage
+ }
+ if (error !is SessionError.UserCancelled) viewDelegate.onError(errorMessage)
+ }
+
+ fun send(apdu: CommandApdu, callback: (result: CompletionResult) -> Unit) {
+ reader.transceiveApdu(apdu, callback)
+ }
+
+ private fun tryHandleError(
+ error: SessionError, callback: (result: CompletionResult) -> Unit) {
+
+ when (error) {
+ is SessionError.NeedEncryption -> {
+ when (environment.encryptionMode) {
+ EncryptionMode.NONE -> {
+ environment.encryptionKey = null
+ environment.encryptionMode = EncryptionMode.FAST
+ }
+ EncryptionMode.FAST -> {
+ environment.encryptionKey = null
+ environment.encryptionMode = EncryptionMode.STRONG
+ }
+ EncryptionMode.STRONG -> {
+ Log.e(this::class.simpleName!!, "Encryption doesn't work")
+ callback(CompletionResult.Failure(SessionError.NeedEncryption()))
+ }
+ }
+ return establishEncryption(callback)
+ }
+ else -> callback(CompletionResult.Failure(SessionError.UnknownError()))
+ }
+ }
+
+ private fun establishEncryption(callback: (result: CompletionResult) -> Unit) {
+ val encryptionHelper: EncryptionHelper =
+ if (environment.encryptionMode == EncryptionMode.STRONG) {
+ StrongEncryptionHelper()
+ } else {
+ FastEncryptionHelper()
+ }
+ val openSesssionCommand = OpenSessionCommand(encryptionHelper.keyA)
+ openSesssionCommand.run(this) { result ->
+ when (result) {
+ is CompletionResult.Success -> {
+ val uid = result.data.uid
+ val protocolKey = environment.pin1.calculateSha256().pbkdf2Hash(uid, 50)
+ val secret = encryptionHelper.generateSecret(result.data.sessionKeyB)
+ val sessionKey = (secret + protocolKey).calculateSha256()
+ environment.encryptionKey = sessionKey
+ callback(CompletionResult.Success(true))
+ }
+ is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/Config.kt b/tangem-core/src/main/java/com/tangem/Config.kt
index 2d1193e176..d99c57fcf9 100644
--- a/tangem-core/src/main/java/com/tangem/Config.kt
+++ b/tangem-core/src/main/java/com/tangem/Config.kt
@@ -1,6 +1,33 @@
package com.tangem
class Config(
+ /**
+ * Enables or disables Linked Terminal feature.
+
+ App can optionally generate ECDSA key pair Terminal_PrivateKey / Terminal_PublicKey.
+ And then submit Terminal_PublicKey to the card in any SIGN command.
+ Once SIGN is successfully executed by COS (Card Operation System),
+ including PIN2 verification and/or completion of security delay, the submitted
+ Terminal_PublicKey key is stored by COS. After that, the App instance is deemed trusted
+ by COS and COS will allow skipping security delay for subsequent SIGN operations
+ thus improving convenience without sacrificing security.
+
+ In order to skip security delay, App should use Terminal_PrivateKey to compute the signature
+ of the data being submitted to SIGN command for signing and transmit this signature in
+ Terminal_Transaction_Signature parameter in the same SIGN command. COS will verify
+ the correctness of Terminal_Transaction_Signature using previously stored Terminal_PublicKey
+ and, if correct, will skip security delay for the current SIGN operation.
+ */
val linkedTerminal: Boolean = true,
- val issuerPublicKey: ByteArray? = null
+
+ /**
+ * If not null, it will be used to validate Issuer data and issuer extra data.
+ * If null, issuerPublicKey from current card will be used.
+ */
+ val issuerPublicKey: ByteArray? = null,
+
+ /**
+ * Level of encryption used in communication with a Tangem Card.
+ */
+ val encryptionMode: EncryptionMode = EncryptionMode.NONE
)
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/CardEnvironment.kt b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt
similarity index 67%
rename from tangem-core/src/main/java/com/tangem/common/CardEnvironment.kt
rename to tangem-core/src/main/java/com/tangem/SessionEnvironment.kt
index 09cfd736b4..81a541184c 100644
--- a/tangem-core/src/main/java/com/tangem/common/CardEnvironment.kt
+++ b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt
@@ -1,17 +1,22 @@
-package com.tangem.common
+package com.tangem
+import com.tangem.commands.Card
import com.tangem.commands.EllipticCurve
+import com.tangem.common.extensions.calculateSha256
import com.tangem.crypto.CryptoUtils.generatePublicKey
/**
* Contains data relating to a Tangem card. It is used in constructing all the commands,
- * and commands can return modified [CardEnvironment].
+ * and commands can return modified [SessionEnvironment].
+ *
+ * @property card Current card, read by preflight [com.tangem.commands.ReadCommand].
+ * @property terminalKeys generated terminal keys used in Linked Terminal feature.
*/
-data class CardEnvironment(
+data class SessionEnvironment(
val pin1: String = DEFAULT_PIN,
val pin2: String = DEFAULT_PIN2,
- val cardId: String? = null,
+ var card: Card? = null,
val terminalKeys: KeyPair? = null,
var encryptionMode: EncryptionMode = EncryptionMode.NONE,
var encryptionKey: ByteArray? = null,
@@ -24,6 +29,9 @@ data class CardEnvironment(
}
}
+/**
+ * All possible encryption modes.
+ */
enum class EncryptionMode(val code: Byte) {
NONE(0x0),
FAST(0x1),
diff --git a/tangem-core/src/main/java/com/tangem/SessionError.kt b/tangem-core/src/main/java/com/tangem/SessionError.kt
new file mode 100644
index 0000000000..07209b6a3f
--- /dev/null
+++ b/tangem-core/src/main/java/com/tangem/SessionError.kt
@@ -0,0 +1,139 @@
+package com.tangem
+
+import com.tangem.commands.Card
+import com.tangem.commands.ReadCommand
+import com.tangem.common.apdu.StatusWord
+import com.tangem.tasks.ScanTask
+
+/**
+ * An error class that represent typical errors that may occur when performing Tangem SDK tasks.
+ * Errors are propagated back to the caller in callbacks.
+ */
+sealed class SessionError(val code: Int) : Exception() {
+
+ //Errors in serializing APDU
+ /**
+ * This error is returned when there [CommandSerializer] cannot deserialize [com.tangem.common.tlv.Tlv]
+ * (this error is a wrapper around internal [com.tangem.common.tlv.TlvDecoder] errors).
+ */
+ class SerializeCommandError : SessionError(1000)
+
+ class DeserializeApduFailed : SessionError(1001)
+ class EncodingFailedTypeMismatch : SessionError(1002)
+ class EncodingFailed : SessionError(1003)
+
+ class DecodingFailedMissingTag : SessionError(1004)
+ class DecodingFailedTypeMismatch : SessionError(1005)
+ class DecodingFailed : SessionError(1005)
+
+ /**
+ * This error is returned when unknown [StatusWord] is received from a card.
+ */
+ class UnknownStatus : SessionError(2001)
+
+ /**
+ * This error is returned when a card's reply is [StatusWord.ErrorProcessingCommand].
+ * The card sends this status in case of internal card error.
+ */
+ class ErrorProcessingCommand : SessionError(2002)
+
+ /**
+ * This error is returned when a task (such as [ScanTask]) requires that [ReadCommand]
+ * is executed before performing other commands.
+ */
+ class MissingPreflightRead : SessionError(2003)
+
+ /**
+ * This error is returned when a card's reply is [StatusWord.InvalidState].
+ * The card sends this status when command can not be executed in the current state of a card.
+ */
+ class InvalidState : SessionError(2004)
+
+ /**
+ * This error is returned when a card's reply is [StatusWord.InsNotSupported].
+ * The card sends this status when the card cannot process the [com.tangem.common.apdu.Instruction].
+ */
+ class InsNotSupported : SessionError(2005)
+
+ /**
+ * This error is returned when a card's reply is [StatusWord.InvalidParams].
+ * The card sends this status when there are wrong or not sufficient parameters in TLV request,
+ * or wrong PIN1/PIN2.
+ * The error may be caused, for example, by wrong parameters of the [Task], [CommandSerializer],
+ * mapping or serialization errors.
+ */
+ class InvalidParams : SessionError(2006)
+
+ /**
+ * This error is returned when a card's reply is [StatusWord.NeedEncryption]
+ * and the encryption was not established by TangemSdk.
+ */
+ class NeedEncryption : SessionError(2007)
+
+ //Scan errors
+ /**
+ * This error is returned when a [Task] checks unsuccessfully either
+ * a card's ability to sign with its private key, or the validity of issuer data.
+ */
+ class VerificationFailed : SessionError(3000)
+
+ /**
+ * This error is returned when a [ScanTask] returns a [Card] without some of the essential fields.
+ */
+ class CardError : SessionError(3001)
+
+ /**
+ * This error is returned when a [Task] expects a user to use a particular card,
+ * and a user tries to use a different card.
+ */
+ class WrongCard : SessionError(3002)
+
+ /**
+ * Tangem cards can sign currently up to 10 hashes during one [com.tangem.commands.SignCommand].
+ * This error is returned when a [com.tangem.commands.SignCommand] receives more than 10 hashes to sign.
+ */
+ class TooMuchHashesInOneTransaction : SessionError(3003)
+
+ /**
+ * This error is returned when a [com.tangem.commands.SignCommand]
+ * receives only empty hashes for signature.
+ */
+ class EmptyHashes : SessionError(3004)
+
+ /**
+ * This error is returned when a [com.tangem.commands.SignCommand]
+ * receives hashes of different lengths for signature.
+ */
+ class HashSizeMustBeEqual : SessionError(3005)
+
+ /**
+ * This error is returned when [com.tangem.TangemSdk] was called with a new [Task],
+ * while a previous [Task] is still in progress.
+ */
+ class Busy : SessionError(4000)
+
+ /**
+ * This error is returned when a user manually closes NFC Reading Bottom Sheet Dialog.
+ */
+ class UserCancelled : SessionError(4001)
+
+ //NFC errors
+ class NfcReaderError : SessionError(5002)
+
+ /**
+ * This error is returned when Android NFC reader loses a tag
+ * (e.g. a user detaches card from the phone's NFC module) while the NFC session is in progress.
+ */
+ class TagLost : SessionError(5003)
+
+ class UnknownError : SessionError(6000)
+
+ //Specific Command Errors
+ /**
+ * This error is returned when [ReadIssuerDataTask] or [ReadIssuerExtraDataTask] expects a counter
+ * (when the card's requires it), but the counter is missing.
+ */
+ class MissingCounter : SessionError(7001)
+
+ class MissingIssuerPubicKey : SessionError(7002)
+}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/CardManagerDelegate.kt b/tangem-core/src/main/java/com/tangem/SessionViewDelegate.kt
similarity index 78%
rename from tangem-core/src/main/java/com/tangem/CardManagerDelegate.kt
rename to tangem-core/src/main/java/com/tangem/SessionViewDelegate.kt
index 5fce77186d..c372b1730c 100644
--- a/tangem-core/src/main/java/com/tangem/CardManagerDelegate.kt
+++ b/tangem-core/src/main/java/com/tangem/SessionViewDelegate.kt
@@ -1,19 +1,18 @@
package com.tangem
import com.tangem.common.CompletionResult
-import com.tangem.tasks.TaskError
/**
* Allows interaction with users and shows visual elements.
*
* Its default implementation, DefaultCardManagerDelegate, is in our tangem-sdk module.
*/
-interface CardManagerDelegate {
+interface SessionViewDelegate {
/**
* It is called when user is expected to scan a Tangem Card with an Android device.
*/
- fun onNfcSessionStarted(cardId: String?)
+ fun onNfcSessionStarted(cardId: String?, message: Message? = null)
/**
* It is called when security delay is triggered by the card.
@@ -36,16 +35,21 @@ interface CardManagerDelegate {
/**
* It is called when NFC session was completed and a user can take the card away from the Android device.
*/
- fun onNfcSessionCompleted()
+ fun onNfcSessionCompleted(message: Message? = null)
/**
* It is called when some error occur during NFC session.
*/
- fun onError(error: TaskError)
+ fun onError(errorMessage: String)
/**
* It is called when a user is expected to enter pin code.
*/
fun onPinRequested(callback: (result: CompletionResult) -> Unit)
-}
\ No newline at end of file
+}
+
+/**
+ * Wrapper for a message that can be shown to user after a start of NFC session.
+ */
+data class Message(val header: String? = null, val body: String? = null)
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/TangemSdk.kt b/tangem-core/src/main/java/com/tangem/TangemSdk.kt
new file mode 100644
index 0000000000..145efc088e
--- /dev/null
+++ b/tangem-core/src/main/java/com/tangem/TangemSdk.kt
@@ -0,0 +1,375 @@
+package com.tangem
+
+import com.tangem.commands.*
+import com.tangem.commands.personalization.DepersonalizeCommand
+import com.tangem.commands.personalization.DepersonalizeResponse
+import com.tangem.commands.personalization.PersonalizeCommand
+import com.tangem.commands.personalization.entities.Acquirer
+import com.tangem.commands.personalization.entities.CardConfig
+import com.tangem.commands.personalization.entities.Issuer
+import com.tangem.commands.personalization.entities.Manufacturer
+import com.tangem.common.CompletionResult
+import com.tangem.common.TerminalKeysService
+import com.tangem.crypto.CryptoUtils
+import com.tangem.tasks.CreateWalletTask
+import com.tangem.tasks.ScanTask
+
+/**
+ * The main interface of Tangem SDK that allows your app to communicate with Tangem cards.
+ *
+ * @property reader is an interface that is responsible for NFC connection and
+ * transfer of data to and from the Tangem Card.
+ * Its default implementation, NfcCardReader, is in our tangem-sdk module.
+ * @property viewDelegate An interface that allows interaction with users and shows relevant UI.
+ * Its default implementation, DefaultCardSessionViewDelegate, is in our tangem-sdk module.
+ * @property config allows to change a number of parameters for communication with Tangem cards.
+ * Do not change the default values unless you know what you are doing.
+ */
+class TangemSdk(
+ private val reader: CardReader,
+ private val viewDelegate: SessionViewDelegate,
+ var config: Config = Config()
+) {
+
+ private var terminalKeysService: TerminalKeysService? = null
+
+ init {
+ CryptoUtils.initCrypto()
+ }
+
+ /**
+ * This method launches a [ScanTask] on a new thread.
+ *
+ * To start using any card, you first need to read it using the scanCard() method.
+ * This method launches an NFC session, and once it’s connected with the card,
+ * it obtains the card data. Optionally, if the card contains a wallet (private and public key pair),
+ * it proves that the wallet owns a private key that corresponds to a public one.
+ *
+ * @param callback is triggered on the completion of the [ScanTask] and provides card response
+ * in the form of [Card] if the task was performed successfully or [SessionError] in case of an error.
+ */
+ fun scanCard(initialMessage: Message? = null, callback: (result: CompletionResult) -> Unit) {
+ startSession(ScanTask(), null, initialMessage, callback)
+ }
+
+ /**
+ * This method launches a [SignCommand] on a new thread.
+ *
+ * It allows you to sign one or multiple hashes.
+ * Simultaneous signing of array of hashes in a single [SignCommand] is required to support
+ * Bitcoin-type multi-input blockchains (UTXO).
+ * The [SignCommand] will return a corresponding array of signatures.
+ *
+ * Please note that Tangem cards usually protect the signing with a security delay
+ * that may last up to 90 seconds, depending on a card.
+ * It is for [SessionViewDelegate] to notify users of security delay.
+ *
+ * @param hashes Array of transaction hashes. It can be from one or up to ten hashes of the same length.
+ * @param cardId CID, Unique Tangem card ID number
+ * @param callback is triggered on the completion of the [SignCommand] and provides card response
+ * in the form of [SignResponse] if the task was performed successfully
+ * or [SessionError] in case of an error.
+ */
+ fun sign(hashes: Array, cardId: String, initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit) {
+ startSession(SignCommand(hashes), cardId, initialMessage, callback)
+ }
+
+ /**
+ * This method launches a [ReadIssuerDataCommand] on a new thread.
+
+ * This command returns 512-byte Issuer Data field and its issuer’s signature.
+ * Issuer Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
+ * format and payload of Issuer Data. For example, this field may contain information about
+ * wallet balance signed by the issuer or additional issuer’s attestation data.
+ *
+ * @param cardId CID, Unique Tangem card ID number.
+ * @param callback is triggered on the completion of the [ReadIssuerDataCommand] and provides
+ * card response in the form of [ReadIssuerDataResponse] if the task was performed successfully
+ * or [SessionError] in case of an error.
+ */
+ fun readIssuerData(cardId: String, initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit) {
+ startSession(ReadIssuerDataCommand(config.issuerPublicKey), cardId, initialMessage, callback)
+ }
+
+ /**
+ * This method launches a [ReadIssuerExtraDataCommand] on a new thread.
+ *
+ * This command retrieves Issuer Extra Data field and its issuer’s signature.
+ * Issuer Extra Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
+ * format and payload of Issuer Data. . For example, this field may contain photo or
+ * biometric information for ID card product. Because of the large size of Issuer_Extra_Data,
+ * a series of these commands have to be executed to read the entire Issuer_Extra_Data.
+ *
+ * @param cardId CID, Unique Tangem card ID number.
+ * @param callback is triggered on the completion of the [ReadIssuerExtraDataCommand] and provides
+ * card response in the form of [ReadIssuerExtraDataResponse] if the task was performed successfully
+ * or [SessionError] in case of an error.
+ */
+ fun readIssuerExtraData(cardId: String,
+ callback: (result: CompletionResult) -> Unit) {
+ startSession(ReadIssuerExtraDataCommand(config.issuerPublicKey), cardId, null, callback)
+ }
+
+ /**
+ * This method launches a [WriteIssuerDataCommand] on a new thread.
+ *
+ * This command writes 512-byte Issuer Data field and its issuer’s signature.
+ * Issuer Data is never changed or parsed from within the Tangem COS. The issuer defines purpose of use,
+ * format and payload of Issuer Data. For example, this field may contain information about
+ * wallet balance signed by the issuer or additional issuer’s attestation data.
+ *
+ * @param cardId CID, Unique Tangem card ID number.
+ * @param issuerData Data provided by issuer.
+ * @param issuerDataSignature Issuer’s signature of [issuerData] with Issuer Data Private Key.
+ * @param issuerDataCounter An optional counter that protect issuer data against replay attack.
+ * @param callback is triggered on the completion of the [WriteIssuerDataCommand] and provides
+ * card response in the form of [WriteIssuerDataResponse] if the task was performed successfully
+ * or [SessionError] in case of an error.
+ */
+ fun writeIssuerData(cardId: String,
+ issuerData: ByteArray,
+ issuerDataSignature: ByteArray,
+ issuerDataCounter: Int? = null,
+ initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit) {
+ val command = WriteIssuerDataCommand(
+ issuerData,
+ issuerDataSignature,
+ issuerDataCounter,
+ config.issuerPublicKey
+ )
+ startSession(command, cardId, initialMessage, callback)
+ }
+
+ /**
+ * This method launches a [WriteIssuerExtraDataCommand] on a new thread.
+ *
+ * This command writes Issuer Extra Data field and its issuer’s signature.
+ * Issuer Extra Data is never changed or parsed from within the Tangem COS.
+ * The issuer defines purpose of use, format and payload of Issuer Data.
+ * For example, this field may contain a photo or biometric information for ID card products.
+ * Because of the large size of IssuerExtraData, a series of these commands have to be executed
+ * to write entire IssuerExtraData.
+ *
+ * @param cardId CID, Unique Tangem card ID number.
+ * @param issuerData Data provided by issuer.
+ * @param startingSignature Issuer’s signature with Issuer Data Private Key of [cardId],
+ * [issuerDataCounter] (if flags Protect_Issuer_Data_Against_Replay and
+ * Restrict_Overwrite_Issuer_Extra_Data are set in [SettingsMask]) and size of [issuerData].
+ * @param finalizingSignature Issuer’s signature with Issuer Data Private Key of [cardId],
+ * [issuerData] and [issuerDataCounter] (the latter one only if flags Protect_Issuer_Data_Against_Replay
+ * andRestrict_Overwrite_Issuer_Extra_Data are set in [SettingsMask]).
+ * @param issuerDataCounter An optional counter that protect issuer data against replay attack.
+ * @param callback is triggered on the completion of the [WriteIssuerExtraDataCommand] and provides
+ * card response in the form of [WriteIssuerDataResponse] if the task was performed successfully
+ * or [SessionError] in case of an error.
+ */
+ fun writeIssuerExtraData(cardId: String,
+ issuerData: ByteArray,
+ startingSignature: ByteArray,
+ finalizingSignature: ByteArray,
+ issuerDataCounter: Int? = null,
+ initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit) {
+ val command = WriteIssuerExtraDataCommand(
+ issuerData,
+ startingSignature, finalizingSignature,
+ issuerDataCounter,
+ config.issuerPublicKey
+ )
+ startSession(command, cardId, initialMessage, callback)
+ }
+
+ /**
+ * This method launches a [WriteUserDataCommand] on a new thread.
+ *
+ * This command writes some of UserData, UserProtectedData, UserCounter and UserProtectedCounter fields.
+ * User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS.
+ * The App defines purpose of use, format and it's payload. For example, this field may contain cashed information
+ * from blockchain to accelerate preparing new transaction.
+ * User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing
+ * of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use.
+ * For example, this fields may contain blockchain nonce value.
+ *
+ * Writing of UserCounter and UserData is protected only by PIN1.
+ * UserProtectedCounter and UserProtectedData need additionally PIN2 to confirmation.
+ */
+ fun writeUserData(
+ cardId: String,
+ userData: ByteArray? = null,
+ userProtectedData: ByteArray? = null,
+ userCounter: Int? = null,
+ userProtectedCounter: Int? = null,
+ initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit
+ ) {
+ val command = WriteUserDataCommand(userData, userProtectedData, userCounter, userProtectedCounter)
+ startSession(command, cardId, initialMessage, callback)
+ }
+
+ /**
+ * This method launches a [ReadUserDataCommand] on a new thread.
+ *
+ * This command returns two up to 512-byte User_Data, User_Protected_Data and two counters User_Counter and
+ * User_Protected_Counter fields.
+ * User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS.
+ * The App defines purpose of use, format and it's payload. For example, this field may contain cashed information
+ * from blockchain to accelerate preparing new transaction.
+ * User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing
+ * of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use.
+ * For example, this fields may contain blockchain nonce value.
+ *
+ * @param cardId CID, Unique Tangem card ID number.
+ * @param callback is triggered on the completion of the [ReadUserDataCommand] and provides
+ * card response in the form of [ReadUserDataResponse] if the task was performed successfully
+ * or [SessionError] in case of an error.
+ */
+ fun readUserData(cardId: String, initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit) {
+ startSession(ReadUserDataCommand(), cardId, initialMessage, callback)
+ }
+
+ /**
+ * This method launches a [CreateWalletTask] on a new thread.
+ *
+ * This this will create a new wallet on the card having ‘Empty’ state with [CreateWalletCommand]
+ * and will check the success of the operation by performing [CheckWalletCommand].
+ * A key pair WalletPublicKey / WalletPrivateKey is generated and securely stored in the card.
+ * App will need to obtain Wallet_PublicKey from the [CreateWalletResponse] or from the
+ * response of [ReadCommand] and then transform it into an address of corresponding
+ * blockchain wallet according to a specific blockchain algorithm.
+ * WalletPrivateKey is never revealed by the card and will be used by [SignCommand] and [CheckWalletCommand].
+ * RemainingSignature is set to MaxSignatures.
+ *
+ * @param cardId CID, Unique Tangem card ID number.
+ * @param callback is triggered on the completion of the [CreateWalletTask] and provides
+ * card response in the form of [CreateWalletResponse] if the task was performed successfully
+ * or [SessionError] in case of an error.
+ */
+ fun createWallet(cardId: String, initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit) {
+ startSession(CreateWalletTask(), cardId, initialMessage, callback)
+ }
+
+ /**
+ * This method launches a [PurgeWalletCommand] on a new thread.
+ *
+ * This command deletes all wallet data. If IsReusable flag is enabled during personalization,
+
+ * or [CreateWalletCommand].
+ * If IsReusable flag is disabled, the card switches to ‘Purged’ state.
+ * ‘Purged’ state is final, it makes the card useless.
+ *
+ * @param cardId CID, Unique Tangem card ID number.
+ * @param callback is triggered on the completion of the [PurgeWalletCommand] and provides
+ * card response in the form of [PurgeWalletResponse] if the task was performed successfully
+ * or [SessionError] in case of an error.
+ */
+ fun purgeWallet(cardId: String, initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit) {
+ startSession(PurgeWalletCommand(), cardId, initialMessage, callback)
+ }
+
+ /**
+ * Command available on SDK cards only
+ *
+ * This method launches a [DepersonalizeCommand] on a new thread.
+ *
+ * This command resets card to initial state,
+ * erasing all data written during personalization and usage.
+ *
+ * @param cardId CID, Unique Tangem card ID number.
+ * @param callback is triggered on the completion of the [DepersonalizeCommand] and provides
+ * card response in the form of [DepersonalizeResponse] if the task was performed successfully
+ * or [SessionError] in case of an error.
+ * */
+ fun depersonalize(cardId: String, initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit) {
+ startSession(DepersonalizeCommand(), cardId, initialMessage, callback)
+ }
+
+ /**
+ * Command available on SDK cards only
+ *
+ * This method launches a [PersonalizeCommand] on a new thread.
+ *
+ * Personalization is an initialization procedure, required before starting using a card.
+ * During this procedure a card setting is set up.
+ * During this procedure all data exchange is encrypted.
+ * @param config is a configuration file with all the card settings that are written on the card
+ * during personalization.
+ * @param issuer Issuer is a third-party team or company wishing to use Tangem cards.
+ * @param manufacturer Tangem Card Manufacturer.
+ * @param acquirer Acquirer is a trusted third-party company that operates proprietary
+ * (non-EMV) POS terminal infrastructure and transaction processing back-end.
+ * @param callback is triggered on the completion of the [PersonalizeCommand] and provides
+ * card response in the form of [Card] if the command was performed successfully
+ * or [SessionError] in case of an error.
+ */
+ fun personalize(config: CardConfig,
+ issuer: Issuer, manufacturer: Manufacturer, acquirer: Acquirer? = null,
+ initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit) {
+ val command = PersonalizeCommand(config, issuer, manufacturer, acquirer)
+ startSession(command, null, initialMessage, callback)
+ }
+
+ /**
+ * Allows running a custom bunch of commands in one [CardSession] by creating a custom task.
+ * [TangemSdk] will start a card session, perform preflight [ReadCommand],
+ * invoke [CardSessionRunnable.run] and close the session.
+ * You can find the current card in the [CardSession.environment].
+
+ * @runnable: A custom task, adopting [CardSessionRunnable] protocol
+ * @cardId: CID, Unique Tangem card ID number. If not null, the SDK will check that you the card
+ * with which you tapped a phone has this [cardId] and SDK will return
+ * the [SessionError.WrongCard] otherwise.
+ * @initialMessage: A custom description that shows at the beginning of the NFC session.
+ * If null, default message will be used.
+ * @callback: Standard [TangemSdk] callback.
+ */
+ fun startSession(
+ runnable: CardSessionRunnable, cardId: String? = null, initialMessage: Message? = null,
+ callback: (result: CompletionResult) -> Unit) {
+ val cardSession = CardSession(buildEnvironment(), reader, viewDelegate, cardId, initialMessage)
+ Thread().run { cardSession.startWithRunnable(runnable, callback) }
+ }
+
+ /**
+ * Allows running a custom bunch of commands in one [CardSession] with lightweight closure syntax.
+ * Tangem SDK will start a card sesion and perform preflight [ReadCommand].
+
+ * @cardId: CID, Unique Tangem card ID number. If not null, the SDK will check that you the card
+ * with which you tapped a phone has this [cardId] and SDK will return
+ * the [SessionError.WrongCard] otherwise.
+ * @initialMessage: A custom description that shows at the beginning of the NFC session.
+ * If null, default message will be used.
+ * @callback: At first, you should check that the [SessionError] is not null,
+ * then you can use the [CardSession] to interact with a card.
+ */
+ fun startSession(
+ cardId: String? = null, initialMessage: Message? = null,
+ callback: (session: CardSession, error: SessionError?) -> Unit) {
+ val cardSession = CardSession(buildEnvironment(), reader, viewDelegate, cardId, initialMessage)
+ Thread().run { cardSession.start(callback) }
+ }
+
+ /**
+ * Allows to set a particular [TerminalKeysService] to retrieve terminal keys.
+ * Default implementation is provided in tangem-sdk module: [TerminalKeysStorage].
+ */
+ fun setTerminalKeysService(terminalKeysService: TerminalKeysService) {
+ this.terminalKeysService = terminalKeysService
+ }
+
+ private fun buildEnvironment(): SessionEnvironment {
+ val terminalKeys = if (config.linkedTerminal) terminalKeysService?.getKeys() else null
+ return SessionEnvironment(
+ terminalKeys = terminalKeys
+ )
+ }
+
+ companion object
+}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt
index 28f0cd2d43..4d9c3a53ff 100644
--- a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt
@@ -1,14 +1,16 @@
package com.tangem.commands
-import com.tangem.common.CardEnvironment
+import com.tangem.CardSession
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
+import com.tangem.common.CompletionResult
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
import com.tangem.crypto.CryptoUtils
-import com.tangem.tasks.TaskError
/**
* Deserialized response from the Tangem card after [CheckWalletCommand].
@@ -40,33 +42,54 @@ class CheckWalletResponse(
* @property cardId Unique Tangem card ID number
* @property challenge Random challenge generated by application
*/
-class CheckWalletCommand : CommandSerializer() {
+class CheckWalletCommand(
+ private val curve: EllipticCurve, private val publicKey: ByteArray
+) : Command() {
- val challenge = CryptoUtils.generateRandomBytes(16)
+ private val challenge = CryptoUtils.generateRandomBytes(16)
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
+ transceive(session) { result ->
+ when (result) {
+ is CompletionResult.Failure -> {
+ callback(CompletionResult.Failure(result.error))
+ }
+ is CompletionResult.Success -> {
+ val verified = result.data.verify(
+ curve,
+ publicKey,
+ challenge
+ )
+ if (verified) {
+ callback(CompletionResult.Success(result.data))
+ } else {
+ callback(CompletionResult.Failure(SessionError.VerificationFailed()))
+ }
+ }
+ }
+ }
+ }
+
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1)
- tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId)
+ tlvBuilder.append(TlvTag.Pin, environment.pin1)
+ tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
tlvBuilder.append(TlvTag.Challenge, challenge)
return CommandApdu(
Instruction.CheckWallet, tlvBuilder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
+ environment.encryptionMode, environment.encryptionKey
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): CheckWalletResponse? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): CheckWalletResponse {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val mapper = TlvMapper(tlvData)
- CheckWalletResponse(
- cardId = mapper.map(TlvTag.CardId),
- salt = mapper.map(TlvTag.Salt),
- walletSignature = mapper.map(TlvTag.Signature)
- )
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
+ val decoder = TlvDecoder(tlvData)
+ return CheckWalletResponse(
+ cardId = decoder.decode(TlvTag.CardId),
+ salt = decoder.decode(TlvTag.Salt),
+ walletSignature = decoder.decode(TlvTag.Signature)
+ )
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/Command.kt b/tangem-core/src/main/java/com/tangem/commands/Command.kt
new file mode 100644
index 0000000000..a44332d04f
--- /dev/null
+++ b/tangem-core/src/main/java/com/tangem/commands/Command.kt
@@ -0,0 +1,116 @@
+package com.tangem.commands
+
+import com.tangem.*
+import com.tangem.common.CompletionResult
+import com.tangem.common.apdu.CommandApdu
+import com.tangem.common.apdu.ResponseApdu
+import com.tangem.common.apdu.StatusWord
+import com.tangem.common.apdu.toSessionError
+import com.tangem.common.extensions.toInt
+import com.tangem.common.tlv.TlvTag
+
+/**
+ * Basic interface for a parsed response from [Command].
+ */
+interface CommandResponse
+
+/**
+ * Basic class for Tangem card commands
+ */
+abstract class Command : CardSessionRunnable {
+
+ /**
+ * Serializes data into an array of [com.tangem.common.tlv.Tlv],
+ * then creates [CommandApdu] with this data.
+ * @param environment [SessionEnvironment] of the current card
+ * @return command data converted to [CommandApdu] that allows to convert it to [ByteArray]
+ * that can be sent to a Tangem card
+ */
+ abstract fun serialize(environment: SessionEnvironment): CommandApdu
+
+ /**
+ * Deserializes data received from a card and stored in [ResponseApdu]
+ * into an array of [com.tangem.common.tlv.Tlv]. Then maps it into a [CommandResponse].
+ * @param environment [SessionEnvironment] of the current card.
+ * @param apdu received data.
+ * @return Card response converted to a [CommandResponse] of a type [T]
+ */
+ abstract fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): T
+
+ override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
+ transceive(session, callback)
+ }
+
+ fun transceive(session: CardSession, callback: (result: CompletionResult) -> Unit) {
+ try {
+ val apdu = serialize(session.environment)
+ transceiveApdu(apdu, session) { result ->
+ when (result) {
+ is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
+ is CompletionResult.Success -> {
+ val response = deserialize(session.environment, result.data)
+ callback(CompletionResult.Success(response))
+ }
+ }
+ }
+ } catch (error: SessionError) {
+ callback(CompletionResult.Failure(error))
+ }
+ }
+
+ private fun transceiveApdu(apdu: CommandApdu, session: CardSession, callback: (result: CompletionResult) -> Unit) {
+ session.send(apdu) { result ->
+
+ when (result) {
+ is CompletionResult.Success -> {
+ val responseApdu = result.data
+ when (responseApdu.statusWord) {
+ StatusWord.ProcessCompleted, StatusWord.Pin1Changed, StatusWord.Pin2Changed, StatusWord.PinsChanged
+ -> callback(CompletionResult.Success(responseApdu))
+ StatusWord.NeedPause -> {
+ // NeedPause is returned from the card whenever security delay is triggered.
+ val remainingTime = deserializeSecurityDelay(responseApdu, session.environment)
+ if (remainingTime != null) {
+ session.viewDelegate.onSecurityDelay(
+ remainingTime,
+ session.environment.card?.pauseBeforePin2 ?: 0)
+ }
+ Log.i(this::class.simpleName!!, "Nfc command ${this::class.simpleName!!} " +
+ "triggered security delay of $remainingTime milliseconds")
+ transceiveApdu(apdu, session, callback)
+ }
+ else -> {
+ val error = responseApdu.statusWord.toSessionError()
+ if (error != null && !tryHandleError(error)) {
+ callback(CompletionResult.Failure(error))
+ } else {
+ callback(CompletionResult.Failure(SessionError.UnknownError()))
+ }
+ }
+ }
+ }
+ is CompletionResult.Failure ->
+ if (result.error == SessionError.TagLost()) {
+ session.viewDelegate.onTagLost()
+ } else {
+ callback(CompletionResult.Failure(result.error))
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper method to parse security delay information received from a card.
+ *
+ * @return Remaining security delay in milliseconds.
+ */
+ private fun deserializeSecurityDelay(responseApdu: ResponseApdu, environment: SessionEnvironment): Int? {
+ val tlv = responseApdu.getTlvData()
+ return tlv?.find { it.tag == TlvTag.Pause }?.value?.toInt()
+ }
+
+ private fun tryHandleError(error: SessionError): Boolean {
+ return false
+ }
+
+}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt b/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt
deleted file mode 100644
index 134474fb23..0000000000
--- a/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.tangem.commands
-
-import com.tangem.common.CardEnvironment
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.ResponseApdu
-import com.tangem.common.extensions.toInt
-import com.tangem.common.tlv.TlvTag
-
-/**
- * Simple interface for responses received after sending commands to Tangem cards.
- */
-interface CommandResponse
-
-/**
- * Abstract class for all Tangem card commands.
- */
-abstract class CommandSerializer {
-
- /**
- * Serializes data into a [List] of [com.tangem.common.tlv.Tlv],
- * then creates [CommandApdu] with this data.
- *
- * @return Command data that can be converted to raw bytes with a method [CommandApdu.toBytes].
- */
- abstract fun serialize(cardEnvironment: CardEnvironment): CommandApdu
-
- /**
- * Deserializes data, received from a card and stored in [ResponseApdu],
- * into a [List] of [com.tangem.common.tlv.Tlv]. Then this method maps it into a [CommandResponse].
- *
- * @return Card response, converted to a [CommandResponse] of a type [T].
- */
- abstract fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): T?
-
- /**
- * Helper method to parse security delay information received from a card.
- *
- * @return Remaining security delay in milliseconds.
- */
- fun deserializeSecurityDelay(responseApdu: ResponseApdu, cardEnvironment: CardEnvironment): Int? {
- val tlv = responseApdu.getTlvData()
- return tlv?.find { it.tag == TlvTag.Pause }?.value?.toInt()
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt
index 18b20f1394..089a134702 100644
--- a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt
@@ -1,13 +1,13 @@
package com.tangem.commands
-import com.tangem.common.CardEnvironment
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
-import com.tangem.tasks.TaskError
class CreateWalletResponse(
/**
@@ -35,32 +35,29 @@ class CreateWalletResponse(
*
* @property cardId CID, Unique Tangem card ID number.
*/
-class CreateWalletCommand : CommandSerializer() {
+class CreateWalletCommand : Command() {
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1)
- tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId)
- tlvBuilder.append(TlvTag.Pin2, cardEnvironment.pin2)
- tlvBuilder.append(TlvTag.Cvc, cardEnvironment.cvc)
+ tlvBuilder.append(TlvTag.Pin, environment.pin1)
+ tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
+ tlvBuilder.append(TlvTag.Pin2, environment.pin2)
+ tlvBuilder.append(TlvTag.Cvc, environment.cvc)
return CommandApdu(
Instruction.CreateWallet, tlvBuilder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
+ environment.encryptionMode, environment.encryptionKey
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): CreateWalletResponse? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): CreateWalletResponse {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val mapper = TlvMapper(tlvData)
- CreateWalletResponse(
- cardId = mapper.map(TlvTag.CardId),
- status = mapper.map(TlvTag.Status),
- walletPublicKey = mapper.map(TlvTag.WalletPublicKey)
- )
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
+ val decoder = TlvDecoder(tlvData)
+ return CreateWalletResponse(
+ cardId = decoder.decode(TlvTag.CardId),
+ status = decoder.decode(TlvTag.Status),
+ walletPublicKey = decoder.decode(TlvTag.WalletPublicKey)
+ )
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt b/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt
index 85d3ddf866..7484f9d48b 100644
--- a/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/OpenSessionCommand.kt
@@ -1,13 +1,13 @@
package com.tangem.commands
-import com.tangem.common.CardEnvironment
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
-import com.tangem.tasks.TaskError
class OpenSessionResponse(
val sessionKeyB: ByteArray,
@@ -20,27 +20,24 @@ class OpenSessionResponse(
* to encrypt and decrypt commands’ payload.
*/
-class OpenSessionCommand(private val sessionKeyA: ByteArray) : CommandSerializer() {
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+class OpenSessionCommand(private val sessionKeyA: ByteArray) : Command() {
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
val tlvBuilder = TlvBuilder()
tlvBuilder.append(TlvTag.SessionKeyA, sessionKeyA)
return CommandApdu(
Instruction.OpenSession, tlvBuilder.serialize(),
- encryptionMode = cardEnvironment.encryptionMode
+ encryptionMode = environment.encryptionMode
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): OpenSessionResponse? {
- val tlvData = responseApdu.getTlvData() ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): OpenSessionResponse {
+ val tlvData = apdu.getTlvData()
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val mapper = TlvMapper(tlvData)
- OpenSessionResponse(
- sessionKeyB = mapper.map(TlvTag.SessionKeyB),
- uid = mapper.map(TlvTag.Uid)
- )
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
+ val decoder = TlvDecoder(tlvData)
+ return OpenSessionResponse(
+ sessionKeyB = decoder.decode(TlvTag.SessionKeyB),
+ uid = decoder.decode(TlvTag.Uid)
+ )
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt
index 4eb379e521..057ae8d084 100644
--- a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt
@@ -1,13 +1,13 @@
package com.tangem.commands
-import com.tangem.common.CardEnvironment
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
-import com.tangem.tasks.TaskError
class PurgeWalletResponse(
/**
@@ -27,29 +27,26 @@ class PurgeWalletResponse(
* ‘Purged’ state is final, it makes the card useless.
* @property cardId CID, Unique Tangem card ID number.
*/
-class PurgeWalletCommand : CommandSerializer() {
+class PurgeWalletCommand : Command() {
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1)
- tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId)
- tlvBuilder.append(TlvTag.Pin2, cardEnvironment.pin2)
+ tlvBuilder.append(TlvTag.Pin, environment.pin1)
+ tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
+ tlvBuilder.append(TlvTag.Pin2, environment.pin2)
return CommandApdu(
Instruction.PurgeWallet, tlvBuilder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
+ environment.encryptionMode, environment.encryptionKey
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): PurgeWalletResponse? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): PurgeWalletResponse {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val mapper = TlvMapper(tlvData)
- PurgeWalletResponse(
- cardId = mapper.map(TlvTag.CardId),
- status = mapper.map(TlvTag.Status))
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
+ val decoder = TlvDecoder(tlvData)
+ return PurgeWalletResponse(
+ cardId = decoder.decode(TlvTag.CardId),
+ status = decoder.decode(TlvTag.Status))
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt
index c861d73469..09c188072d 100644
--- a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt
@@ -1,14 +1,14 @@
package com.tangem.commands
-import com.tangem.common.CardEnvironment
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.Tlv
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
-import com.tangem.tasks.TaskError
import java.util.*
/**
@@ -73,7 +73,7 @@ data class SigningMethod(val rawValue: Int) {
if (signRawValidatedByIssuerAndWriteIssuerData) signingMethod += 0x01 shl SigningMethod.signRawValidatedByIssuerAndWriteIssuerData
if (signPos) signingMethod += 0x01 shl SigningMethod.signPos
}
- return SigningMethod(signingMethod)
+ return SigningMethod(signingMethod)
}
}
}
@@ -354,6 +354,13 @@ class Card(
*/
val userCounter: Int?,
+ /**
+ * This value can be initialized by App (with PIN2 confirmation) and will be increased by COS
+ * with the execution of each [SignCommand]. For example, this field can store blockchain “nonce”
+ * for a quick one-touch transaction on POS terminals. Returned only if [SigningMethod.SignPos].
+ */
+ val userProtectedCounter: Int?,
+
/**
* When this value is true, it means that the application is linked to the card,
* and COS will not enforce security delay if [SignCommand] will be called
@@ -373,58 +380,56 @@ class Card(
* This command receives from the Tangem Card all the data about the card and the wallet,
* including unique card number (CID or cardId) that has to be submitted while calling all other commands.
*/
-class ReadCommand : CommandSerializer() {
+class ReadCommand : Command() {
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
val tlvBuilder = TlvBuilder()
/**
- * [CardEnvironment] stores the pin1 value. If no pin1 value was set, it will contain
+ * [SessionEnvironment] stores the pin1 value. If no pin1 value was set, it will contain
* default value of ‘000000’.
* In order to obtain card’s data, [ReadCommand] should use the correct pin 1 value.
* The card will not respond if wrong pin 1 has been submitted.
*/
- tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1)
- tlvBuilder.append(TlvTag.TerminalPublicKey, cardEnvironment.terminalKeys?.publicKey)
+ tlvBuilder.append(TlvTag.Pin, environment.pin1)
+ tlvBuilder.append(TlvTag.TerminalPublicKey, environment.terminalKeys?.publicKey)
return CommandApdu(
Instruction.Read, tlvBuilder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
+ environment.encryptionMode, environment.encryptionKey
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): Card? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): Card {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val tlvMapper = TlvMapper(tlvData)
+ val decoder = TlvDecoder(tlvData)
- Card(
- cardId = tlvMapper.mapOptional(TlvTag.CardId) ?: "",
- manufacturerName = tlvMapper.mapOptional(TlvTag.ManufactureId) ?: "",
- status = tlvMapper.mapOptional(TlvTag.Status),
+ return Card(
+ cardId = decoder.decodeOptional(TlvTag.CardId) ?: "",
+ manufacturerName = decoder.decodeOptional(TlvTag.ManufactureId) ?: "",
+ status = decoder.decodeOptional(TlvTag.Status),
- firmwareVersion = tlvMapper.mapOptional(TlvTag.Firmware),
- cardPublicKey = tlvMapper.mapOptional(TlvTag.CardPublicKey),
- settingsMask = tlvMapper.mapOptional(TlvTag.SettingsMask),
- issuerPublicKey = tlvMapper.mapOptional(TlvTag.IssuerDataPublicKey),
- curve = tlvMapper.mapOptional(TlvTag.CurveId),
- maxSignatures = tlvMapper.mapOptional(TlvTag.MaxSignatures),
- signingMethod = tlvMapper.mapOptional(TlvTag.SigningMethod),
- pauseBeforePin2 = tlvMapper.mapOptional(TlvTag.PauseBeforePin2),
- walletPublicKey = tlvMapper.mapOptional(TlvTag.WalletPublicKey),
- walletRemainingSignatures = tlvMapper.mapOptional(TlvTag.RemainingSignatures),
- walletSignedHashes = tlvMapper.mapOptional(TlvTag.SignedHashes),
- health = tlvMapper.mapOptional(TlvTag.Health),
- isActivated = tlvMapper.map(TlvTag.IsActivated),
- activationSeed = tlvMapper.mapOptional(TlvTag.ActivationSeed),
- paymentFlowVersion = tlvMapper.mapOptional(TlvTag.PaymentFlowVersion),
- userCounter = tlvMapper.mapOptional(TlvTag.UserCounter),
- terminalIsLinked = tlvMapper.map(TlvTag.TerminalIsLinked),
+ firmwareVersion = decoder.decodeOptional(TlvTag.Firmware),
+ cardPublicKey = decoder.decodeOptional(TlvTag.CardPublicKey),
+ settingsMask = decoder.decodeOptional(TlvTag.SettingsMask),
+ issuerPublicKey = decoder.decodeOptional(TlvTag.IssuerDataPublicKey),
+ curve = decoder.decodeOptional(TlvTag.CurveId),
+ maxSignatures = decoder.decodeOptional(TlvTag.MaxSignatures),
+ signingMethod = decoder.decodeOptional(TlvTag.SigningMethod),
+ pauseBeforePin2 = decoder.decodeOptional(TlvTag.PauseBeforePin2),
+ walletPublicKey = decoder.decodeOptional(TlvTag.WalletPublicKey),
+ walletRemainingSignatures = decoder.decodeOptional(TlvTag.RemainingSignatures),
+ walletSignedHashes = decoder.decodeOptional(TlvTag.SignedHashes),
+ health = decoder.decodeOptional(TlvTag.Health),
+ isActivated = decoder.decode(TlvTag.IsActivated),
+ activationSeed = decoder.decodeOptional(TlvTag.ActivationSeed),
+ paymentFlowVersion = decoder.decodeOptional(TlvTag.PaymentFlowVersion),
+ userCounter = decoder.decodeOptional(TlvTag.UserCounter),
+ userProtectedCounter = decoder.decodeOptional(TlvTag.UserProtectedCounter),
+ terminalIsLinked = decoder.decode(TlvTag.TerminalIsLinked),
- cardData = deserializeCardData(tlvData)
- )
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
+ cardData = deserializeCardData(tlvData)
+ )
}
private fun deserializeCardData(tlvData: List): CardData? {
@@ -433,18 +438,18 @@ class ReadCommand : CommandSerializer() {
}
if (cardDataTlvs.isNullOrEmpty()) return null
- val tlvMapper = TlvMapper(cardDataTlvs)
+ val decoder = TlvDecoder(cardDataTlvs)
return CardData(
- batchId = tlvMapper.mapOptional(TlvTag.Batch),
- manufactureDateTime = tlvMapper.mapOptional(TlvTag.ManufactureDateTime),
- issuerName = tlvMapper.mapOptional(TlvTag.IssuerId),
- blockchainName = tlvMapper.mapOptional(TlvTag.BlockchainId),
- manufacturerSignature = tlvMapper.mapOptional(TlvTag.ManufacturerSignature),
- productMask = tlvMapper.mapOptional(TlvTag.ProductMask),
+ batchId = decoder.decodeOptional(TlvTag.Batch),
+ manufactureDateTime = decoder.decodeOptional(TlvTag.ManufactureDateTime),
+ issuerName = decoder.decodeOptional(TlvTag.IssuerId),
+ blockchainName = decoder.decodeOptional(TlvTag.BlockchainId),
+ manufacturerSignature = decoder.decodeOptional(TlvTag.ManufacturerSignature),
+ productMask = decoder.decodeOptional(TlvTag.ProductMask),
- tokenSymbol = tlvMapper.mapOptional(TlvTag.TokenSymbol),
- tokenContractAddress = tlvMapper.mapOptional(TlvTag.TokenContractAddress),
- tokenDecimal = tlvMapper.mapOptional(TlvTag.TokenDecimal)
+ tokenSymbol = decoder.decodeOptional(TlvTag.TokenSymbol),
+ tokenContractAddress = decoder.decodeOptional(TlvTag.TokenContractAddress),
+ tokenDecimal = decoder.decodeOptional(TlvTag.TokenDecimal)
)
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt
index cb95fd0899..7055bc403f 100644
--- a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt
@@ -1,16 +1,19 @@
package com.tangem.commands
+import com.tangem.CardSession
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.commands.common.DefaultIssuerDataVerifier
import com.tangem.commands.common.IssuerDataMode
+import com.tangem.commands.common.IssuerDataToVerify
import com.tangem.commands.common.IssuerDataVerifier
-import com.tangem.common.CardEnvironment
+import com.tangem.common.CompletionResult
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
-import com.tangem.tasks.TaskError
class ReadIssuerDataResponse(
@@ -51,34 +54,63 @@ class ReadIssuerDataResponse(
* @property cardId CID, Unique Tangem card ID number.
*/
class ReadIssuerDataCommand(
+ val issuerPublicKey: ByteArray? = null,
verifier: IssuerDataVerifier = DefaultIssuerDataVerifier()
-) : CommandSerializer(),
- IssuerDataVerifier by verifier {
+) : Command(), IssuerDataVerifier by verifier {
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
+ val card = session.environment.card
+ if (card == null) {
+ callback(CompletionResult.Failure(SessionError.MissingPreflightRead()))
+ return
+ }
+ val publicKey = issuerPublicKey ?: card.issuerPublicKey
+ if (publicKey == null) {
+ callback(CompletionResult.Failure(SessionError.MissingIssuerPubicKey()))
+ return
+ }
+ super.run(session) { result ->
+ when (result) {
+ is CompletionResult.Failure -> callback(result)
+ is CompletionResult.Success -> {
+ if (result.data.issuerData.isEmpty()) {
+ callback(result)
+ return@run
+ }
+ val issuerDataToVerify = IssuerDataToVerify(
+ card.cardId, result.data.issuerData, result.data.issuerDataCounter
+ )
+ if (verify(publicKey, result.data.issuerDataSignature, issuerDataToVerify)) {
+ callback(result)
+ } else {
+ callback(CompletionResult.Failure(SessionError.VerificationFailed()))
+ }
+ }
+ }
+ }
+ }
+
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1)
- tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId)
+ tlvBuilder.append(TlvTag.Pin, environment.pin1)
+ tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
tlvBuilder.append(TlvTag.Mode, IssuerDataMode.ReadData)
return CommandApdu(
Instruction.ReadIssuerData, tlvBuilder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
+ environment.encryptionMode, environment.encryptionKey
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): ReadIssuerDataResponse? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): ReadIssuerDataResponse {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val mapper = TlvMapper(tlvData)
- ReadIssuerDataResponse(
- cardId = mapper.map(TlvTag.CardId),
- issuerData = mapper.map(TlvTag.IssuerData),
- issuerDataSignature = mapper.map(TlvTag.IssuerDataSignature),
- issuerDataCounter = mapper.mapOptional(TlvTag.IssuerDataCounter)
- )
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
+ val decoder = TlvDecoder(tlvData)
+ return ReadIssuerDataResponse(
+ cardId = decoder.decode(TlvTag.CardId),
+ issuerData = decoder.decode(TlvTag.IssuerData),
+ issuerDataSignature = decoder.decode(TlvTag.IssuerDataSignature),
+ issuerDataCounter = decoder.decodeOptional(TlvTag.IssuerDataCounter)
+ )
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt
index 5672003477..4140000621 100644
--- a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt
@@ -1,16 +1,20 @@
package com.tangem.commands
+import com.tangem.CardSession
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.commands.common.DefaultIssuerDataVerifier
import com.tangem.commands.common.IssuerDataMode
+import com.tangem.commands.common.IssuerDataToVerify
import com.tangem.commands.common.IssuerDataVerifier
-import com.tangem.common.CardEnvironment
+import com.tangem.common.CompletionResult
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
-import com.tangem.tasks.TaskError
+import java.io.ByteArrayOutputStream
class ReadIssuerExtraDataResponse(
@@ -56,38 +60,113 @@ class ReadIssuerExtraDataResponse(
* a series of these commands have to be executed to read the entire Issuer_Extra_Data.
*/
class ReadIssuerExtraDataCommand(
+ private val issuerPublicKey: ByteArray? = null,
verifier: IssuerDataVerifier = DefaultIssuerDataVerifier()
-) : CommandSerializer(), IssuerDataVerifier by verifier {
+) : Command(), IssuerDataVerifier by verifier {
- var offset: Int = 0
+ private val issuerData = ByteArrayOutputStream()
+ private var offset: Int = 0
+ private var issuerDataSize: Int = 0
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
+ val card = session.environment.card
+ if (card == null) {
+ callback(CompletionResult.Failure(SessionError.MissingPreflightRead()))
+ return
+ }
+ val publicKey = issuerPublicKey ?: card.issuerPublicKey
+ if (publicKey == null) {
+ callback(CompletionResult.Failure(SessionError.MissingIssuerPubicKey()))
+ return
+ }
+
+ readIssuerData(session, card.cardId, publicKey, callback)
+ }
+
+
+ private fun readIssuerData(
+ session: CardSession,
+ cardId: String, publicKey: ByteArray,
+ callback: (result: CompletionResult) -> Unit) {
+
+ if (issuerDataSize != 0) {
+ session.viewDelegate.onDelay(
+ issuerDataSize, offset, WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE
+ )
+ }
+
+ transceive(session) { result ->
+ when (result) {
+ is CompletionResult.Success -> {
+ if (result.data.size != null) {
+ if (result.data.size == 0) {
+ callback(CompletionResult.Success(result.data))
+ return@transceive
+ }
+ issuerDataSize = result.data.size
+ }
+ issuerData.write(result.data.issuerData)
+ if (result.data.issuerDataSignature == null) {
+ offset = issuerData.size()
+ readIssuerData(session, cardId, publicKey, callback)
+ } else {
+ completeTask(result.data, cardId, publicKey, callback)
+ }
+ }
+ is CompletionResult.Failure -> {
+ callback(CompletionResult.Failure(result.error))
+ }
+ }
+ }
+ }
+
+ private fun completeTask(data: ReadIssuerExtraDataResponse,
+ cardId: String, publicKey: ByteArray,
+ callback: (result: CompletionResult) -> Unit) {
+ val dataToVerify = IssuerDataToVerify(
+ cardId,
+ issuerData.toByteArray(),
+ data.issuerDataCounter
+ )
+ if (verify(publicKey, data.issuerDataSignature!!, dataToVerify)) {
+ val finalResult = ReadIssuerExtraDataResponse(
+ data.cardId,
+ issuerDataSize,
+ issuerData.toByteArray(),
+ data.issuerDataSignature,
+ data.issuerDataCounter
+ )
+ callback(CompletionResult.Success(finalResult))
+ } else {
+ callback(CompletionResult.Failure(SessionError.VerificationFailed()))
+ }
+ }
+
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1)
- tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId)
+ tlvBuilder.append(TlvTag.Pin, environment.pin1)
+ tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
tlvBuilder.append(TlvTag.Mode, IssuerDataMode.ReadExtraData)
tlvBuilder.append(TlvTag.Offset, offset)
return CommandApdu(
Instruction.ReadIssuerData, tlvBuilder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
+ environment.encryptionMode, environment.encryptionKey
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): ReadIssuerExtraDataResponse? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): ReadIssuerExtraDataResponse {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val mapper = TlvMapper(tlvData)
- ReadIssuerExtraDataResponse(
- cardId = mapper.map(TlvTag.CardId),
- size = mapper.mapOptional(TlvTag.Size),
- issuerData = mapper.mapOptional(TlvTag.IssuerData) ?: byteArrayOf(),
- issuerDataSignature = mapper.mapOptional(TlvTag.IssuerDataSignature),
- issuerDataCounter = mapper.mapOptional(TlvTag.IssuerDataCounter)
- )
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
+
+ val decoder = TlvDecoder(tlvData)
+ return ReadIssuerExtraDataResponse(
+ cardId = decoder.decode(TlvTag.CardId),
+ size = decoder.decodeOptional(TlvTag.Size),
+ issuerData = decoder.decodeOptional(TlvTag.IssuerData) ?: byteArrayOf(),
+ issuerDataSignature = decoder.decodeOptional(TlvTag.IssuerDataSignature),
+ issuerDataCounter = decoder.decodeOptional(TlvTag.IssuerDataCounter)
+ )
}
companion object {
diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt
index 656c1750f0..528ba98fb0 100644
--- a/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt
@@ -1,13 +1,13 @@
package com.tangem.commands
-import com.tangem.common.CardEnvironment
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
-import com.tangem.tasks.TaskError
class ReadUserDataResponse(
/**
@@ -47,33 +47,30 @@ class ReadUserDataResponse(
* of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use.
* For example, this fields may contain blockchain nonce value.
*/
-class ReadUserDataCommand: CommandSerializer() {
+class ReadUserDataCommand: Command() {
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
val builder = TlvBuilder()
- builder.append(TlvTag.CardId, cardEnvironment.cardId)
- builder.append(TlvTag.Pin, cardEnvironment.pin1)
+ builder.append(TlvTag.CardId, environment.card?.cardId)
+ builder.append(TlvTag.Pin, environment.pin1)
return CommandApdu(
Instruction.ReadUserData, builder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
+ environment.encryptionMode, environment.encryptionKey
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): ReadUserDataResponse? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): ReadUserDataResponse {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val mapper = TlvMapper(tlvData)
- ReadUserDataResponse(
- cardId = mapper.map(TlvTag.CardId),
- userData = mapper.map(TlvTag.UserData),
- userProtectedData = mapper.map(TlvTag.UserProtectedData),
- userCounter = mapper.map(TlvTag.UserCounter),
- userProtectedCounter = mapper.map(TlvTag.UserProtectedCounter)
+ val decoder = TlvDecoder(tlvData)
+ return ReadUserDataResponse(
+ cardId = decoder.decode(TlvTag.CardId),
+ userData = decoder.decode(TlvTag.UserData),
+ userProtectedData = decoder.decode(TlvTag.UserProtectedData),
+ userCounter = decoder.decode(TlvTag.UserCounter),
+ userProtectedCounter = decoder.decode(TlvTag.UserProtectedCounter)
)
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt
index 6f0b7bfacc..7707f82197 100644
--- a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt
@@ -1,14 +1,14 @@
package com.tangem.commands
-import com.tangem.common.CardEnvironment
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
import com.tangem.crypto.sign
-import com.tangem.tasks.TaskError
/**
* @param cardId CID, Unique Tangem card ID number
@@ -31,10 +31,26 @@ class SignResponse(
* @property cardId CID, Unique Tangem card ID number
*/
class SignCommand(private val hashes: Array)
- : CommandSerializer() {
+ : Command() {
private val hashSizes = if (hashes.isNotEmpty()) hashes.first().size else 0
- private val dataToSign = flattenHashes()
+
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
+ val dataToSign = flattenHashes()
+ val tlvBuilder = TlvBuilder()
+ tlvBuilder.append(TlvTag.Pin, environment.pin1)
+ tlvBuilder.append(TlvTag.Pin2, environment.pin2)
+ tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
+ tlvBuilder.append(TlvTag.TransactionOutHashSize, byteArrayOf(hashSizes.toByte()))
+ tlvBuilder.append(TlvTag.TransactionOutHash, dataToSign)
+ tlvBuilder.append(TlvTag.Cvc, environment.cvc)
+
+ addTerminalSignature(environment, dataToSign, tlvBuilder)
+ return CommandApdu(
+ Instruction.Sign, tlvBuilder.serialize(),
+ environment.encryptionMode, environment.encryptionKey
+ )
+ }
private fun flattenHashes(): ByteArray {
checkForErrors()
@@ -42,25 +58,9 @@ class SignCommand(private val hashes: Array)
}
private fun checkForErrors() {
- if (hashes.isEmpty()) throw TaskError.EmptyHashes()
- if (hashes.size > 10) throw TaskError.TooMuchHashesInOneTransaction()
- if (hashes.any { it.size != hashSizes }) throw TaskError.HashSizeMustBeEqual()
- }
-
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
- val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1)
- tlvBuilder.append(TlvTag.Pin2, cardEnvironment.pin2)
- tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId)
- tlvBuilder.append(TlvTag.TransactionOutHashSize, byteArrayOf(hashSizes.toByte()))
- tlvBuilder.append(TlvTag.TransactionOutHash, dataToSign)
- tlvBuilder.append(TlvTag.Cvc, cardEnvironment.cvc)
-
- addTerminalSignature(cardEnvironment, tlvBuilder)
- return CommandApdu(
- Instruction.Sign, tlvBuilder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
- )
+ if (hashes.isEmpty()) throw SessionError.EmptyHashes()
+ if (hashes.size > 10) throw SessionError.TooMuchHashesInOneTransaction()
+ if (hashes.any { it.size != hashSizes }) throw SessionError.HashSizeMustBeEqual()
}
/**
@@ -70,23 +70,25 @@ class SignCommand(private val hashes: Array)
* TerminalTransactionSignature parameter containing a correct signature of raw data to be signed made with TerminalPrivateKey
* (this key should be generated and securily stored by the application).
*/
- private fun addTerminalSignature(cardEnvironment: CardEnvironment, tlvBuilder: TlvBuilder) {
- cardEnvironment.terminalKeys?.let { terminalKeyPair ->
+ private fun addTerminalSignature(
+ environment: SessionEnvironment, dataToSign: ByteArray, tlvBuilder: TlvBuilder) {
+ environment.terminalKeys?.let { terminalKeyPair ->
val signedData = dataToSign.sign(terminalKeyPair.privateKey)
tlvBuilder.append(TlvTag.TerminalTransactionSignature, signedData)
tlvBuilder.append(TlvTag.TerminalPublicKey, terminalKeyPair.publicKey)
}
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): SignResponse? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): SignResponse {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
- val tlvMapper = TlvMapper(tlvData)
+ val decoder = TlvDecoder(tlvData)
return SignResponse(
- cardId = tlvMapper.map(TlvTag.CardId),
- signature = tlvMapper.map(TlvTag.Signature),
- walletRemainingSignatures = tlvMapper.map(TlvTag.RemainingSignatures),
- walletSignedHashes = tlvMapper.map(TlvTag.SignedHashes)
+ cardId = decoder.decode(TlvTag.CardId),
+ signature = decoder.decode(TlvTag.Signature),
+ walletRemainingSignatures = decoder.decode(TlvTag.RemainingSignatures),
+ walletSignedHashes = decoder.decode(TlvTag.SignedHashes)
)
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt
index dbc7f15640..a425f5a740 100644
--- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt
@@ -1,16 +1,19 @@
package com.tangem.commands
+import com.tangem.CardSession
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.commands.common.DefaultIssuerDataVerifier
import com.tangem.commands.common.IssuerDataMode
+import com.tangem.commands.common.IssuerDataToVerify
import com.tangem.commands.common.IssuerDataVerifier
-import com.tangem.common.CardEnvironment
+import com.tangem.common.CompletionResult
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
-import com.tangem.tasks.TaskError
class WriteIssuerDataResponse(
/**
@@ -33,13 +36,50 @@ class WriteIssuerDataCommand(
private val issuerData: ByteArray,
private val issuerDataSignature: ByteArray,
private val issuerDataCounter: Int? = null,
+ private val issuerPublicKey: ByteArray? = null,
verifier: IssuerDataVerifier = DefaultIssuerDataVerifier()
-) : CommandSerializer(), IssuerDataVerifier by verifier {
+) : Command(), IssuerDataVerifier by verifier {
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
+
+ val card = session.environment.card
+ if (card == null) {
+ callback(CompletionResult.Failure(SessionError.MissingPreflightRead()))
+ return
+ }
+ val publicKey = issuerPublicKey ?: card.issuerPublicKey
+ if (publicKey == null) {
+ callback(CompletionResult.Failure(SessionError.MissingIssuerPubicKey()))
+ return
+ }
+
+ if (!isCounterValid(issuerDataCounter, card)) {
+ callback(CompletionResult.Failure(SessionError.MissingCounter()))
+ } else if (!verifySignature(publicKey, card.cardId)) {
+ callback(CompletionResult.Failure(SessionError.VerificationFailed()))
+ } else {
+ super.run(session, callback)
+ }
+ }
+
+ private fun isCounterValid(issuerDataCounter: Int?, card: Card): Boolean =
+ if (isCounterRequired(card)) issuerDataCounter != null else true
+
+ private fun isCounterRequired(card: Card): Boolean =
+ card.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) != false
+
+ private fun verifySignature(publicKey: ByteArray, cardId: String): Boolean {
+ return verify(
+ publicKey,
+ issuerDataSignature,
+ IssuerDataToVerify(cardId, issuerData, issuerDataCounter)
+ )
+ }
+
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1)
- tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId)
+ tlvBuilder.append(TlvTag.Pin, environment.pin1)
+ tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
tlvBuilder.append(TlvTag.Mode, IssuerDataMode.WriteData)
tlvBuilder.append(TlvTag.IssuerData, issuerData)
tlvBuilder.append(TlvTag.IssuerDataSignature, issuerDataSignature)
@@ -47,20 +87,17 @@ class WriteIssuerDataCommand(
return CommandApdu(
Instruction.WriteIssuerData, tlvBuilder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
+ environment.encryptionMode, environment.encryptionKey
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): WriteIssuerDataResponse? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): WriteIssuerDataResponse {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val mapper = TlvMapper(tlvData)
- WriteIssuerDataResponse(
- cardId = mapper.map(TlvTag.CardId)
- )
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
+ val decoder = TlvDecoder(tlvData)
+ return WriteIssuerDataResponse(
+ cardId = decoder.decode(TlvTag.CardId)
+ )
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt
index 753607f0a9..4a93ebd734 100644
--- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt
@@ -1,16 +1,19 @@
package com.tangem.commands
+import com.tangem.CardSession
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.commands.common.DefaultIssuerDataVerifier
import com.tangem.commands.common.IssuerDataMode
+import com.tangem.commands.common.IssuerDataToVerify
import com.tangem.commands.common.IssuerDataVerifier
-import com.tangem.common.CardEnvironment
+import com.tangem.common.CompletionResult
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
-import com.tangem.tasks.TaskError
/**
* This command writes Issuer Extra Data field and its issuer’s signature.
@@ -33,17 +36,94 @@ class WriteIssuerExtraDataCommand(
private val startingSignature: ByteArray,
private val finalizingSignature: ByteArray,
private val issuerDataCounter: Int? = null,
+ private val issuerPublicKey: ByteArray? = null,
verifier: IssuerDataVerifier = DefaultIssuerDataVerifier()
-) : CommandSerializer(), IssuerDataVerifier by verifier {
+) : Command(), IssuerDataVerifier by verifier {
var mode: IssuerDataMode = IssuerDataMode.InitializeWritingExtraData
var offset: Int = 0
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
+ val card = session.environment.card
+ if (card == null) {
+ callback(CompletionResult.Failure(SessionError.MissingPreflightRead()))
+ return
+ }
+ val publicKey = issuerPublicKey ?: card.issuerPublicKey
+ if (publicKey == null) {
+ callback(CompletionResult.Failure(SessionError.MissingIssuerPubicKey()))
+ return
+ }
+
+ if (!isCounterValid(issuerDataCounter, card)) {
+ callback(CompletionResult.Failure(SessionError.MissingCounter()))
+ } else if (!verifySignatures(card.cardId, publicKey)) {
+ callback(CompletionResult.Failure(SessionError.VerificationFailed()))
+ } else {
+ writeIssuerData(session, card.cardId, publicKey, callback)
+ }
+ }
+
+ private fun isCounterValid(issuerDataCounter: Int?, card: Card): Boolean =
+ if (isCounterRequired(card)) issuerDataCounter != null else true
+
+ private fun isCounterRequired(card: Card): Boolean =
+ card.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) != false
+
+ private fun verifySignatures(cardId: String, publicKey: ByteArray): Boolean {
+
+ val firstData = IssuerDataToVerify(cardId, null, issuerDataCounter, issuerData.size)
+ val secondData = IssuerDataToVerify(cardId, issuerData, issuerDataCounter)
+
+ return verify(publicKey, startingSignature, firstData) &&
+ verify(publicKey, finalizingSignature, secondData)
+ }
+
+ private fun writeIssuerData(
+ session: CardSession,
+ cardId: String, publicKey: ByteArray,
+ callback: (result: CompletionResult) -> Unit
+ ) {
+
+ if (mode == IssuerDataMode.WriteExtraData) {
+ session.viewDelegate.onDelay(issuerData.size, offset, WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE)
+ }
+ transceive(session) { result ->
+ when (result) {
+ is CompletionResult.Success -> {
+ when (mode) {
+ IssuerDataMode.InitializeWritingExtraData -> {
+ mode = IssuerDataMode.WriteExtraData
+ writeIssuerData(session, cardId, publicKey, callback)
+ return@transceive
+ }
+ IssuerDataMode.WriteExtraData -> {
+ offset += WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE
+ if (offset >= issuerData.size) {
+ mode = IssuerDataMode.FinalizeExtraData
+ }
+ writeIssuerData(session, cardId, publicKey, callback)
+ return@transceive
+ }
+ IssuerDataMode.FinalizeExtraData -> {
+ callback(CompletionResult.Success(result.data))
+ }
+ }
+ }
+ is CompletionResult.Failure -> {
+ callback(CompletionResult.Failure(result.error))
+ }
+ }
+ }
+
+
+ }
+
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
val tlvBuilder = TlvBuilder()
- tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1)
- tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId)
+ tlvBuilder.append(TlvTag.Pin, environment.pin1)
+ tlvBuilder.append(TlvTag.CardId, environment.card?.cardId)
tlvBuilder.append(TlvTag.Mode, mode)
when (mode) {
@@ -62,7 +142,7 @@ class WriteIssuerExtraDataCommand(
}
return CommandApdu(
Instruction.WriteIssuerData, tlvBuilder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
+ environment.encryptionMode, environment.encryptionKey
)
}
@@ -74,17 +154,12 @@ class WriteIssuerExtraDataCommand(
return if (bytesLeft < SINGLE_WRITE_SIZE) bytesLeft else SINGLE_WRITE_SIZE
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): WriteIssuerDataResponse? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): WriteIssuerDataResponse {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val mapper = TlvMapper(tlvData)
- WriteIssuerDataResponse(
- cardId = mapper.map(TlvTag.CardId)
- )
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
+ return WriteIssuerDataResponse(cardId = TlvDecoder(tlvData).decode(TlvTag.CardId)
+ )
}
companion object {
diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt
index ac79cba45c..e9771d0b87 100644
--- a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt
@@ -1,20 +1,20 @@
package com.tangem.commands
-import com.tangem.common.CardEnvironment
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
-import com.tangem.tasks.TaskError
class WriteUserDataResponse(
- /**
- * CID, Unique Tangem card ID number.
- */
- val cardId: String
-): CommandResponse
+ /**
+ * CID, Unique Tangem card ID number.
+ */
+ val cardId: String
+) : CommandResponse
/**
* This command write some of User_Data, User_ProtectedData, User_Counter and User_ProtectedCounter fields.
@@ -29,33 +29,29 @@ class WriteUserDataResponse(
* User_ProtectedCounter and User_ProtectedData additionaly need PIN2 to confirmation.
*/
class WriteUserDataCommand(private val userData: ByteArray? = null, private val userProtectedData: ByteArray? = null,
- private val userCounter: Int? = null,
- private val userProtectedCounter: Int? = null): CommandSerializer() {
+ private val userCounter: Int? = null,
+ private val userProtectedCounter: Int? = null) : Command() {
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
- val builder = TlvBuilder()
- builder.append(TlvTag.CardId, cardEnvironment.cardId)
- builder.append(TlvTag.Pin, cardEnvironment.pin1)
- builder.append(TlvTag.UserData, userData)
- builder.append(TlvTag.UserCounter, userCounter)
- builder.append(TlvTag.UserProtectedData, userProtectedData)
- builder.append(TlvTag.UserProtectedCounter, userProtectedCounter)
- if (userProtectedCounter != null || userProtectedData != null)
- builder.append(TlvTag.Pin2, cardEnvironment.pin2)
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
+ val builder = TlvBuilder()
+ builder.append(TlvTag.CardId, environment.card?.cardId)
+ builder.append(TlvTag.Pin, environment.pin1)
+ builder.append(TlvTag.UserData, userData)
+ builder.append(TlvTag.UserCounter, userCounter)
+ builder.append(TlvTag.UserProtectedData, userProtectedData)
+ builder.append(TlvTag.UserProtectedCounter, userProtectedCounter)
+ if (userProtectedCounter != null || userProtectedData != null)
+ builder.append(TlvTag.Pin2, environment.pin2)
- return CommandApdu(
- Instruction.WriteUserData, builder.serialize(),
- cardEnvironment.encryptionMode, cardEnvironment.encryptionKey
- )
- }
-
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): WriteUserDataResponse? {
- val tlvData = responseApdu.getTlvData(cardEnvironment.encryptionKey) ?: return null
-
- return try {
- WriteUserDataResponse(TlvMapper(tlvData).map(TlvTag.CardId))
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
+ return CommandApdu(
+ Instruction.WriteUserData, builder.serialize(),
+ environment.encryptionMode, environment.encryptionKey
+ )
+ }
+
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): WriteUserDataResponse {
+ val tlvData = apdu.getTlvData(environment.encryptionKey)
+ ?: throw SessionError.DeserializeApduFailed()
+ return WriteUserDataResponse(TlvDecoder(tlvData).decode(TlvTag.CardId))
}
- }
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt
index 034b28dce5..2ed9366331 100644
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/personalization/DepersonalizeCommand.kt
@@ -1,8 +1,8 @@
package com.tangem.commands.personalization
+import com.tangem.SessionEnvironment
+import com.tangem.commands.Command
import com.tangem.commands.CommandResponse
-import com.tangem.commands.CommandSerializer
-import com.tangem.common.CardEnvironment
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
@@ -14,17 +14,16 @@ data class DepersonalizeResponse(val success: Boolean) : CommandResponse
*
* This command resets card to initial state,
* erasing all data written during personalization and usage.
- * @param cardId CID, Unique Tangem card ID number.
*/
-class DepersonalizeCommand : CommandSerializer() {
+class DepersonalizeCommand : Command() {
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
return CommandApdu(
Instruction.Depersonalize, byteArrayOf()
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): DepersonalizeResponse? {
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): DepersonalizeResponse {
return DepersonalizeResponse(true)
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt
index 035963c21a..24a118322a 100644
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt
@@ -1,10 +1,11 @@
package com.tangem.commands.personalization
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
import com.tangem.commands.Card
import com.tangem.commands.CardData
-import com.tangem.commands.CommandSerializer
+import com.tangem.commands.Command
import com.tangem.commands.personalization.entities.*
-import com.tangem.common.CardEnvironment
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
@@ -12,10 +13,9 @@ import com.tangem.common.extensions.calculateSha256
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.tlv.Tlv
import com.tangem.common.tlv.TlvBuilder
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
import com.tangem.crypto.sign
-import com.tangem.tasks.TaskError
/**
* Command available on SDK cards only
@@ -34,9 +34,9 @@ class PersonalizeCommand(
private val config: CardConfig,
private val issuer: Issuer, private val manufacturer: Manufacturer,
private val acquirer: Acquirer? = null
-) : CommandSerializer() {
+) : Command() {
- override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
+ override fun serialize(environment: SessionEnvironment): CommandApdu {
return CommandApdu(
Instruction.Personalize,
serializePersonalizationData(config),
@@ -44,39 +44,37 @@ class PersonalizeCommand(
)
}
- override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): Card? {
- val tlvData = responseApdu.getTlvData(devPersonalizationKey) ?: return null
+ override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): Card {
+ val tlvData = apdu.getTlvData(devPersonalizationKey)
+ ?: throw SessionError.DeserializeApduFailed()
- return try {
- val tlvMapper = TlvMapper(tlvData)
- Card(
- cardId = tlvMapper.mapOptional(TlvTag.CardId) ?: "",
- manufacturerName = tlvMapper.mapOptional(TlvTag.ManufactureId) ?: "",
- status = tlvMapper.mapOptional(TlvTag.Status),
+ val decoder = TlvDecoder(tlvData)
+ return Card(
+ cardId = decoder.decodeOptional(TlvTag.CardId) ?: "",
+ manufacturerName = decoder.decodeOptional(TlvTag.ManufactureId) ?: "",
+ status = decoder.decodeOptional(TlvTag.Status),
- firmwareVersion = tlvMapper.mapOptional(TlvTag.Firmware),
- cardPublicKey = tlvMapper.mapOptional(TlvTag.CardPublicKey),
- settingsMask = tlvMapper.mapOptional(TlvTag.SettingsMask),
- issuerPublicKey = tlvMapper.mapOptional(TlvTag.IssuerDataPublicKey),
- curve = tlvMapper.mapOptional(TlvTag.CurveId),
- maxSignatures = tlvMapper.mapOptional(TlvTag.MaxSignatures),
- signingMethod = tlvMapper.mapOptional(TlvTag.SigningMethod),
- pauseBeforePin2 = tlvMapper.mapOptional(TlvTag.PauseBeforePin2),
- walletPublicKey = tlvMapper.mapOptional(TlvTag.WalletPublicKey),
- walletRemainingSignatures = tlvMapper.mapOptional(TlvTag.RemainingSignatures),
- walletSignedHashes = tlvMapper.mapOptional(TlvTag.SignedHashes),
- health = tlvMapper.mapOptional(TlvTag.Health),
- isActivated = tlvMapper.map(TlvTag.IsActivated),
- activationSeed = tlvMapper.mapOptional(TlvTag.ActivationSeed),
- paymentFlowVersion = tlvMapper.mapOptional(TlvTag.PaymentFlowVersion),
- userCounter = tlvMapper.mapOptional(TlvTag.UserCounter),
- terminalIsLinked = tlvMapper.map(TlvTag.TerminalIsLinked),
+ firmwareVersion = decoder.decodeOptional(TlvTag.Firmware),
+ cardPublicKey = decoder.decodeOptional(TlvTag.CardPublicKey),
+ settingsMask = decoder.decodeOptional(TlvTag.SettingsMask),
+ issuerPublicKey = decoder.decodeOptional(TlvTag.IssuerDataPublicKey),
+ curve = decoder.decodeOptional(TlvTag.CurveId),
+ maxSignatures = decoder.decodeOptional(TlvTag.MaxSignatures),
+ signingMethod = decoder.decodeOptional(TlvTag.SigningMethod),
+ pauseBeforePin2 = decoder.decodeOptional(TlvTag.PauseBeforePin2),
+ walletPublicKey = decoder.decodeOptional(TlvTag.WalletPublicKey),
+ walletRemainingSignatures = decoder.decodeOptional(TlvTag.RemainingSignatures),
+ walletSignedHashes = decoder.decodeOptional(TlvTag.SignedHashes),
+ health = decoder.decodeOptional(TlvTag.Health),
+ isActivated = decoder.decode(TlvTag.IsActivated),
+ activationSeed = decoder.decodeOptional(TlvTag.ActivationSeed),
+ paymentFlowVersion = decoder.decodeOptional(TlvTag.PaymentFlowVersion),
+ userCounter = decoder.decodeOptional(TlvTag.UserCounter),
+ userProtectedCounter = decoder.decodeOptional(TlvTag.UserProtectedCounter),
+ terminalIsLinked = decoder.decode(TlvTag.TerminalIsLinked),
- cardData = deserializeCardData(tlvData)
- )
- } catch (exception: Exception) {
- throw TaskError.SerializeCommandError()
- }
+ cardData = deserializeCardData(tlvData)
+ )
}
private fun deserializeCardData(tlvData: List): CardData? {
@@ -85,23 +83,23 @@ class PersonalizeCommand(
}
if (cardDataTlvs.isNullOrEmpty()) return null
- val tlvMapper = TlvMapper(cardDataTlvs)
+ val decoder = TlvDecoder(cardDataTlvs)
return CardData(
- batchId = tlvMapper.mapOptional(TlvTag.Batch),
- manufactureDateTime = tlvMapper.mapOptional(TlvTag.ManufactureDateTime),
- issuerName = tlvMapper.mapOptional(TlvTag.IssuerId),
- blockchainName = tlvMapper.mapOptional(TlvTag.BlockchainId),
- manufacturerSignature = tlvMapper.mapOptional(TlvTag.ManufacturerSignature),
- productMask = tlvMapper.mapOptional(TlvTag.ProductMask),
+ batchId = decoder.decodeOptional(TlvTag.Batch),
+ manufactureDateTime = decoder.decodeOptional(TlvTag.ManufactureDateTime),
+ issuerName = decoder.decodeOptional(TlvTag.IssuerId),
+ blockchainName = decoder.decodeOptional(TlvTag.BlockchainId),
+ manufacturerSignature = decoder.decodeOptional(TlvTag.ManufacturerSignature),
+ productMask = decoder.decodeOptional(TlvTag.ProductMask),
- tokenSymbol = tlvMapper.mapOptional(TlvTag.TokenSymbol),
- tokenContractAddress = tlvMapper.mapOptional(TlvTag.TokenContractAddress),
- tokenDecimal = tlvMapper.mapOptional(TlvTag.TokenDecimal)
+ tokenSymbol = decoder.decodeOptional(TlvTag.TokenSymbol),
+ tokenContractAddress = decoder.decodeOptional(TlvTag.TokenContractAddress),
+ tokenDecimal = decoder.decodeOptional(TlvTag.TokenDecimal)
)
}
private fun serializePersonalizationData(config: CardConfig): ByteArray {
- val cardId = config.createCardId() ?: throw TaskError.SerializeCommandError()
+ val cardId = config.createCardId() ?: throw SessionError.SerializeCommandError()
val tlvBuilder = TlvBuilder()
tlvBuilder.append(TlvTag.CardId, cardId)
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Acquirer.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Acquirer.kt
index cda239b145..ec4cff04b0 100644
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Acquirer.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Acquirer.kt
@@ -1,6 +1,6 @@
package com.tangem.commands.personalization.entities
-import com.tangem.common.KeyPair
+import com.tangem.KeyPair
data class Acquirer(
val keyPair: KeyPair,
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt
index f82889be6a..ee7ab58fa7 100644
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt
@@ -1,6 +1,6 @@
package com.tangem.commands.personalization.entities
-import com.tangem.common.KeyPair
+import com.tangem.KeyPair
data class Issuer(
val name: String,
diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Manufacturer.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Manufacturer.kt
index bffdde9384..9e30287bb0 100644
--- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Manufacturer.kt
+++ b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Manufacturer.kt
@@ -1,6 +1,6 @@
package com.tangem.commands.personalization.entities
-import com.tangem.common.KeyPair
+import com.tangem.KeyPair
data class Manufacturer(
val keyPair: KeyPair,
diff --git a/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt b/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt
index afd76a39e8..71f460c7d7 100644
--- a/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt
+++ b/tangem-core/src/main/java/com/tangem/common/CompletionResult.kt
@@ -1,7 +1,7 @@
package com.tangem.common
+import com.tangem.SessionError
import com.tangem.common.CompletionResult.Success
-import com.tangem.tasks.TaskError
/**
* Response class encapsulating successful and failed results.
@@ -9,5 +9,5 @@ import com.tangem.tasks.TaskError
*/
sealed class CompletionResult {
class Success(val data: T) : CompletionResult()
- class Failure(val error: TaskError) : CompletionResult()
+ class Failure(val error: SessionError) : CompletionResult()
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/common/TerminalKeysService.kt b/tangem-core/src/main/java/com/tangem/common/TerminalKeysService.kt
index d389c172b3..3ba365247d 100644
--- a/tangem-core/src/main/java/com/tangem/common/TerminalKeysService.kt
+++ b/tangem-core/src/main/java/com/tangem/common/TerminalKeysService.kt
@@ -1,9 +1,11 @@
package com.tangem.common
+import com.tangem.KeyPair
+
/**
* Interface for a service for managing Terminal keypair, used for Linked Terminal feature.
- * Its implementation Needs to be provided to [com.tangem.CardManager]
- * by calling [com.tangem.CardManager.setTerminalKeysService].
+ * Its implementation Needs to be provided to [com.tangem.TangemSdk]
+ * by calling [com.tangem.TangemSdk.setTerminalKeysService].
* Default implementation is provided in tangem-sdk module: [TerminalKeysStorage].
* Linked Terminal feature can be disabled manually by editing [com.tangem.Config].
*/
diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt b/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt
index 1a2c2be076..e2d37df4bb 100644
--- a/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt
+++ b/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt
@@ -1,6 +1,6 @@
package com.tangem.common.apdu
-import com.tangem.common.EncryptionMode
+import com.tangem.EncryptionMode
import com.tangem.common.extensions.calculateCrc16
import com.tangem.common.extensions.toByteArray
import com.tangem.crypto.encrypt
diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt b/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt
index a43cfbe969..3938cee65f 100644
--- a/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt
+++ b/tangem-core/src/main/java/com/tangem/common/apdu/StatusWord.kt
@@ -1,5 +1,7 @@
package com.tangem.common.apdu
+import com.tangem.SessionError
+
/**
* Part of a response from the card, shows the status of the operation
*/
@@ -21,5 +23,18 @@ enum class StatusWord(val code: Int, val description: String) {
private val values = values()
fun byCode(code: Int): StatusWord = values.find { it.code == code } ?: Unknown
}
-
+}
+
+fun StatusWord.toSessionError(): SessionError? {
+ return when (this) {
+ StatusWord.ProcessCompleted, StatusWord.Pin1Changed,
+ StatusWord.Pin2Changed, StatusWord.PinsChanged -> null
+ StatusWord.NeedPause -> null
+ StatusWord.InvalidParams -> SessionError.InvalidParams()
+ StatusWord.ErrorProcessingCommand -> SessionError.ErrorProcessingCommand()
+ StatusWord.InvalidState -> SessionError.InvalidState()
+ StatusWord.InsNotSupported -> SessionError.InsNotSupported()
+ StatusWord.NeedEncryption -> SessionError.NeedEncryption()
+ StatusWord.Unknown -> SessionError.UnknownStatus()
+ }
}
diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt
similarity index 86%
rename from tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt
rename to tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt
index 1713fd2e2d..3d63f0e27e 100644
--- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt
+++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt
@@ -1,13 +1,13 @@
package com.tangem.common.tlv
import com.tangem.Log
+import com.tangem.SessionError
import com.tangem.commands.*
import com.tangem.commands.common.IssuerDataMode
import com.tangem.common.extensions.toDate
import com.tangem.common.extensions.toHexString
import com.tangem.common.extensions.toInt
import com.tangem.common.extensions.toUtf8
-import com.tangem.tasks.TaskError
import java.util.*
/**
@@ -16,7 +16,7 @@ import java.util.*
*
* @property tlvList List of TLVs, which values are to be converted to particular classes.
*/
-class TlvMapper(val tlvList: List) {
+class TlvDecoder(val tlvList: List) {
/**
* Finds [Tlv] by its [TlvTag].
@@ -26,10 +26,10 @@ class TlvMapper(val tlvList: List) {
*
* @return Value converted to a nullable type [T].
*/
- inline fun mapOptional(tag: TlvTag): T? =
+ inline fun decodeOptional(tag: TlvTag): T? =
try {
- map(tag)
- } catch (exception: TaskError.MissingTag) {
+ decode(tag)
+ } catch (exception: SessionError.DecodingFailedMissingTag) {
null
}
@@ -44,13 +44,13 @@ class TlvMapper(val tlvList: List) {
*
* @throws [TaskError.MissingTag] exception if no [Tlv] is found by the Tag.
*/
- inline fun map(tag: TlvTag): T {
+ inline fun decode(tag: TlvTag): T {
val tlvValue: ByteArray = tlvList.find { it.tag == tag }?.value
?: if (tag.valueType() == TlvValueType.BoolValue && T::class == Boolean::class) {
return false as T
} else {
Log.e(this::class.simpleName!!, "Tag $tag not found")
- throw TaskError.MissingTag()
+ throw SessionError.DecodingFailedMissingTag()
}
return when (tag.valueType()) {
@@ -68,7 +68,7 @@ class TlvMapper(val tlvList: List) {
tlvValue.toInt() as T
} catch (exception: IllegalArgumentException) {
Log.e(this::class.simpleName!!, exception.message ?: "")
- throw TaskError.ConvertError()
+ throw SessionError.DecodingFailed()
}
}
TlvValueType.BoolValue -> {
@@ -85,7 +85,7 @@ class TlvMapper(val tlvList: List) {
EllipticCurve.byName(tlvValue.toUtf8()) as T
} catch (exception: Exception) {
logException(tag, tlvValue.toUtf8(), exception)
- throw TaskError.ConvertError()
+ throw SessionError.DecodingFailed()
}
@@ -96,7 +96,7 @@ class TlvMapper(val tlvList: List) {
tlvValue.toDate() as T
} catch (exception: Exception) {
logException(tag, tlvValue.toHexString(), exception)
- throw TaskError.ConvertError()
+ throw SessionError.DecodingFailed()
}
}
TlvValueType.ProductMask -> {
@@ -113,7 +113,7 @@ class TlvMapper(val tlvList: List) {
CardStatus.byCode(tlvValue.toInt()) as T
} catch (exception: Exception) {
logException(tag, tlvValue.toInt().toString(), exception)
- throw TaskError.ConvertError()
+ throw SessionError.DecodingFailed()
}
}
TlvValueType.SigningMethod -> {
@@ -122,7 +122,7 @@ class TlvMapper(val tlvList: List) {
SigningMethod(tlvValue.toInt()) as T
} catch (exception: Exception) {
logException(tag, tlvValue.toInt().toString(), exception)
- throw TaskError.ConvertError()
+ throw SessionError.DecodingFailed()
}
}
TlvValueType.IssuerDataMode -> {
@@ -131,7 +131,7 @@ class TlvMapper(val tlvList: List) {
IssuerDataMode.byCode(tlvValue.toInt().toByte()) as T
} catch (exception: Exception) {
logException(tag, tlvValue.toInt().toString(), exception)
- throw TaskError.ConvertError()
+ throw SessionError.DecodingFailed()
}
}
}
@@ -146,7 +146,7 @@ class TlvMapper(val tlvList: List) {
if (T::class != ExpectedT::class) {
Log.e(this::class.simpleName!!,
"Mapping error. Type for tag: $tag must be ${tag.valueType()}. It is ${T::class}")
- throw TaskError.WrongType()
+ throw SessionError.DecodingFailedTypeMismatch()
}
}
diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt
index 58e4043450..1855badcab 100644
--- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt
+++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt
@@ -1,13 +1,12 @@
package com.tangem.common.tlv
import com.tangem.Log
+import com.tangem.SessionError
import com.tangem.commands.*
import com.tangem.commands.common.IssuerDataMode
import com.tangem.common.extensions.calculateSha256
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toByteArray
-import com.tangem.common.extensions.toHexString
-import com.tangem.tasks.TaskError
import java.util.*
/**
@@ -25,7 +24,7 @@ class TlvEncoder {
return Tlv(tag, encodeValue(tag, value))
} else {
Log.e(this::class.simpleName!!, "Encoding error. Value for tag $tag is null")
- throw TaskError.SerializeCommandError()
+ throw SessionError.EncodingFailed()
}
}
@@ -107,7 +106,7 @@ class TlvEncoder {
if (T::class != ExpectedT::class) {
Log.e(this::class.simpleName!!,
"Mapping error. Type for tag: $tag must be ${tag.valueType()}. It is ${T::class}")
- throw TaskError.WrongType()
+ throw SessionError.EncodingFailedTypeMismatch()
}
}
}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/tasks/CreateWalletTask.kt b/tangem-core/src/main/java/com/tangem/tasks/CreateWalletTask.kt
new file mode 100644
index 0000000000..6b21be102c
--- /dev/null
+++ b/tangem-core/src/main/java/com/tangem/tasks/CreateWalletTask.kt
@@ -0,0 +1,43 @@
+package com.tangem.tasks
+
+import com.tangem.CardSession
+import com.tangem.CardSessionRunnable
+import com.tangem.SessionError
+import com.tangem.commands.CardStatus
+import com.tangem.commands.CheckWalletCommand
+import com.tangem.commands.CreateWalletCommand
+import com.tangem.commands.CreateWalletResponse
+import com.tangem.common.CompletionResult
+
+class CreateWalletTask : CardSessionRunnable {
+
+ override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
+ val curve = session.environment.card?.curve
+ if (curve == null) {
+ callback(CompletionResult.Failure(SessionError.CardError()))
+ return
+ }
+
+ val command = CreateWalletCommand()
+ command.run(session) { createWalletResult ->
+ when (createWalletResult) {
+ is CompletionResult.Failure -> callback(createWalletResult)
+ is CompletionResult.Success -> {
+ if (createWalletResult.data.status != CardStatus.Loaded) {
+ callback(CompletionResult.Failure(SessionError.UnknownError()))
+ } else {
+ val checkWalletCommand = CheckWalletCommand(
+ curve, createWalletResult.data.walletPublicKey
+ )
+ checkWalletCommand.run(session) { result ->
+ when (result) {
+ is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
+ is CompletionResult.Success -> callback(createWalletResult)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerDataTask.kt b/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerDataTask.kt
deleted file mode 100644
index d7c50dde31..0000000000
--- a/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerDataTask.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.tangem.tasks
-
-import com.tangem.commands.Card
-import com.tangem.commands.ReadIssuerDataCommand
-import com.tangem.commands.ReadIssuerDataResponse
-import com.tangem.commands.common.IssuerDataToVerify
-import com.tangem.common.CardEnvironment
-import com.tangem.common.CompletionResult
-
-class ReadIssuerDataTask(private val issuerPublicKey: ByteArray? = null) : Task() {
-
- override fun onRun(
- cardEnvironment: CardEnvironment,
- currentCard: Card?,
- callback: (result: TaskEvent) -> Unit) {
-
- val command = ReadIssuerDataCommand()
-
- sendCommand(command, cardEnvironment) { result ->
- when (result) {
- is CompletionResult.Success -> {
- val data = result.data
- if (data.issuerData.isEmpty()) {
- completeNfcSession()
- callback(TaskEvent.Event(result.data))
- callback(TaskEvent.Completion())
- return@sendCommand
- }
- val publicKey = issuerPublicKey ?: currentCard!!.issuerPublicKey!!
- val issuerDataToVerify = IssuerDataToVerify(
- cardEnvironment.cardId!!,
- data.issuerData,
- data.issuerDataCounter
- )
- if (command.verify(publicKey, data.issuerDataSignature, issuerDataToVerify)) {
- completeNfcSession()
- callback(TaskEvent.Event(result.data))
- callback(TaskEvent.Completion())
- } else {
- completeNfcSession(TaskError.VerificationFailed())
- callback(TaskEvent.Completion(TaskError.VerificationFailed()))
- }
- }
- is CompletionResult.Failure -> {
- if (result.error !is TaskError.UserCancelled) {
- completeNfcSession(result.error)
- }
- callback(TaskEvent.Completion(result.error))
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerExtraDataTask.kt b/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerExtraDataTask.kt
deleted file mode 100644
index 4f1397b8db..0000000000
--- a/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerExtraDataTask.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.tangem.tasks
-
-import com.tangem.commands.Card
-import com.tangem.commands.ReadIssuerExtraDataCommand
-import com.tangem.commands.ReadIssuerExtraDataResponse
-import com.tangem.commands.WriteIssuerExtraDataCommand
-import com.tangem.commands.common.IssuerDataToVerify
-import com.tangem.common.CardEnvironment
-import com.tangem.common.CompletionResult
-import java.io.ByteArrayOutputStream
-
-/**
- * This task performs [ReadIssuerExtraDataCommand] repeatedly until
- * the issuer extra data is fully retrieved.
- */
-internal class ReadIssuerExtraDataTask(
- private val issuerPublicKey: ByteArray?) : Task() {
-
- private val issuerData = ByteArrayOutputStream()
- private var issuerDataSize = 0
- private lateinit var card: Card
- private lateinit var cardEnvironment: CardEnvironment
-
- override fun onRun(
- cardEnvironment: CardEnvironment,
- currentCard: Card?,
- callback: (result: TaskEvent) -> Unit
- ) {
- card = currentCard!!
- this.cardEnvironment = cardEnvironment
- val command = ReadIssuerExtraDataCommand()
- readIssuerData(command, callback)
- }
-
- private fun readIssuerData(
- command: ReadIssuerExtraDataCommand,
- callback: (result: TaskEvent) -> Unit) {
-
- if (issuerDataSize != 0) {
- delegate?.onDelay(
- issuerDataSize, command.offset, WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE
- )
- }
-
- sendCommand(command, cardEnvironment) { result ->
- when (result) {
-
- is CompletionResult.Success -> {
- if (result.data.size != null) {
- if (result.data.size == 0) {
- completeNfcSession()
- callback(TaskEvent.Event(result.data))
- callback(TaskEvent.Completion())
- return@sendCommand
- }
- issuerDataSize = result.data.size
- }
- issuerData.write(result.data.issuerData)
- if (result.data.issuerDataSignature == null) {
- command.offset = issuerData.size()
- readIssuerData(command, callback)
- } else {
- completeTask(result.data, command, callback)
- }
- }
- is CompletionResult.Failure -> {
- if (result.error !is TaskError.UserCancelled) {
- completeNfcSession(result.error)
- }
- callback(TaskEvent.Completion(result.error))
- }
- }
- }
- }
-
- private fun completeTask(data: ReadIssuerExtraDataResponse, command: ReadIssuerExtraDataCommand,
- callback: (result: TaskEvent) -> Unit) {
- val publicKey = issuerPublicKey ?: card.issuerPublicKey!!
- val dataToVerify = IssuerDataToVerify(
- cardEnvironment.cardId!!,
- issuerData.toByteArray(),
- data.issuerDataCounter
- )
- if (command.verify(publicKey, data.issuerDataSignature!!, dataToVerify)) {
- completeNfcSession()
- val finalResult = ReadIssuerExtraDataResponse(
- data.cardId,
- issuerDataSize,
- issuerData.toByteArray(),
- data.issuerDataSignature,
- data.issuerDataCounter
- )
- callback(TaskEvent.Event(finalResult))
- callback(TaskEvent.Completion())
- } else {
- completeNfcSession(TaskError.VerificationFailed())
- callback(TaskEvent.Completion(TaskError.VerificationFailed()))
- }
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt b/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt
index f0160c48b3..207cb6f705 100644
--- a/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt
+++ b/tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt
@@ -1,78 +1,42 @@
package com.tangem.tasks
+import com.tangem.CardSession
+import com.tangem.CardSessionRunnable
+import com.tangem.SessionError
import com.tangem.commands.*
-import com.tangem.common.CardEnvironment
import com.tangem.common.CompletionResult
-/**
- * Events that [ScanTask] returns on completion of its commands.
- */
-sealed class ScanEvent {
-
- /**
- * Contains data from a Tangem card after successful completion of [ReadCommand].
- */
- data class OnReadEvent(val card: Card) : ScanEvent()
-
- /**
- * Shows whether the Tangem card was verified on completion of [CheckWalletCommand].
- */
- data class OnVerifyEvent(val isGenuine: Boolean) : ScanEvent()
-}
-
/**
* Task that allows to read Tangem card and verify its private key.
*
* It performs two commands, [ReadCommand] and [CheckWalletCommand], subsequently.
*/
-internal class ScanTask : Task() {
+internal class ScanTask : CardSessionRunnable {
- override fun onRun(cardEnvironment: CardEnvironment,
- currentCard: Card?,
- callback: (result: TaskEvent) -> Unit) {
+ override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
- if (currentCard != null) callback(TaskEvent.Event(ScanEvent.OnReadEvent(currentCard)))
+ val card = session.environment.card
- if (currentCard == null) {
- completeNfcSession(TaskError.MissingPreflightRead())
- callback(TaskEvent.Completion(TaskError.MissingPreflightRead()))
+ if (card == null) {
+ callback(CompletionResult.Failure(SessionError.MissingPreflightRead()))
- } else if (currentCard.cardData?.productMask?.contains(ProductMask.tag) != false) {
- completeNfcSession()
- callback(TaskEvent.Completion())
+ } else if (card.cardData?.productMask?.contains(ProductMask.tag) != false) {
+ callback(CompletionResult.Success(card))
- } else if (currentCard.status != CardStatus.Loaded) {
- completeNfcSession()
- callback(TaskEvent.Completion())
+ } else if (card.status != CardStatus.Loaded) {
+ callback(CompletionResult.Success(card))
- } else if (currentCard.curve == null || currentCard.walletPublicKey == null) {
- completeNfcSession(TaskError.CardError())
- callback(TaskEvent.Completion(TaskError.CardError()))
+ } else if (card.curve == null || card.walletPublicKey == null) {
+ callback(CompletionResult.Failure(SessionError.CardError()))
} else {
+ val checkWalletCommand = CheckWalletCommand(card.curve, card.walletPublicKey)
- val checkWalletCommand = CheckWalletCommand()
-
- sendCommand(checkWalletCommand, cardEnvironment) { result ->
+ checkWalletCommand.run(session) { result ->
when (result) {
- is CompletionResult.Failure -> {
- if (result.error !is TaskError.UserCancelled) {
- completeNfcSession(result.error)
- }
- callback(TaskEvent.Completion(result.error))
- }
- is CompletionResult.Success -> {
- completeNfcSession()
- val verified = result.data.verify(
- currentCard.curve,
- currentCard.walletPublicKey,
- checkWalletCommand.challenge
- )
- callback(TaskEvent.Event(ScanEvent.OnVerifyEvent(verified)))
- callback(TaskEvent.Completion())
- }
+ is CompletionResult.Success -> callback(CompletionResult.Success(card))
+ is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
-
}
}
}
diff --git a/tangem-core/src/main/java/com/tangem/tasks/SingleCommandTask.kt b/tangem-core/src/main/java/com/tangem/tasks/SingleCommandTask.kt
deleted file mode 100644
index 03efa615f8..0000000000
--- a/tangem-core/src/main/java/com/tangem/tasks/SingleCommandTask.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.tangem.tasks
-
-import com.tangem.commands.Card
-import com.tangem.common.CardEnvironment
-import com.tangem.commands.CommandResponse
-import com.tangem.commands.CommandSerializer
-import com.tangem.common.CompletionResult
-
-/**
- * Allows to perform a single command.
- *
- * @property command A command that will be performed.
- */
-class SingleCommandTask(
- private val command: CommandSerializer
-) : Task() {
-
- override fun onRun(
- cardEnvironment: CardEnvironment,
- currentCard: Card?,
- callback: (result: TaskEvent) -> Unit
- ) {
- sendCommand(command, cardEnvironment) { result ->
- when (result) {
- is CompletionResult.Success -> {
- completeNfcSession()
- callback(TaskEvent.Event(result.data))
- callback(TaskEvent.Completion())
- }
- is CompletionResult.Failure -> {
- if (result.error !is TaskError.UserCancelled) {
- completeNfcSession(result.error)
- }
- callback(TaskEvent.Completion(result.error))
- }
- }
- }
- }
-}
diff --git a/tangem-core/src/main/java/com/tangem/tasks/Task.kt b/tangem-core/src/main/java/com/tangem/tasks/Task.kt
deleted file mode 100644
index 224b163a9a..0000000000
--- a/tangem-core/src/main/java/com/tangem/tasks/Task.kt
+++ /dev/null
@@ -1,358 +0,0 @@
-package com.tangem.tasks
-
-import com.tangem.CardManagerDelegate
-import com.tangem.CardReader
-import com.tangem.Log
-import com.tangem.commands.*
-import com.tangem.common.CardEnvironment
-import com.tangem.common.CompletionResult
-import com.tangem.common.EncryptionMode
-import com.tangem.common.apdu.CommandApdu
-import com.tangem.common.apdu.StatusWord
-import com.tangem.common.extensions.calculateSha256
-import com.tangem.crypto.EncryptionHelper
-import com.tangem.crypto.FastEncryptionHelper
-import com.tangem.crypto.StrongEncryptionHelper
-import com.tangem.crypto.pbkdf2Hash
-
-/**
- * An error class that represent typical errors that may occur when performing Tangem SDK tasks.
- * Errors are propagated back to the caller in callbacks.
- */
-sealed class TaskError(val code: Int) : Exception() {
-
- //Errors in serializing APDU
- /**
- * This error is returned when there [CommandSerializer] cannot deserialize [com.tangem.common.tlv.Tlv]
- * (this error is a wrapper around internal [com.tangem.common.tlv.TlvMapper] errors).
- */
- class SerializeCommandError : TaskError(1001)
-
- class EncodingError : TaskError(1002)
- class MissingTag : TaskError(1003)
- class WrongType : TaskError(1004)
- class ConvertError : TaskError(1005)
-
- /**
- * This error is returned when unknown [StatusWord] is received from a card.
- */
- class UnknownStatus : TaskError(2001)
-
- /**
- * This error is returned when a card's reply is [StatusWord.ErrorProcessingCommand].
- * The card sends this status in case of internal card error.
- */
- class ErrorProcessingCommand : TaskError(2002)
-
- /**
- * This error is returned when a task (such as [ScanTask]) requires that [ReadCommand]
- * is executed before performing other commands.
- */
- class MissingPreflightRead : TaskError(2003)
-
- /**
- * This error is returned when a card's reply is [StatusWord.InvalidState].
- * The card sends this status when command can not be executed in the current state of a card.
- */
- class InvalidState : TaskError(2004)
-
- /**
- * This error is returned when a card's reply is [StatusWord.InsNotSupported].
- * The card sends this status when the card cannot process the [com.tangem.common.apdu.Instruction].
- */
- class InsNotSupported : TaskError(2005)
-
- /**
- * This error is returned when a card's reply is [StatusWord.InvalidParams].
- * The card sends this status when there are wrong or not sufficient parameters in TLV request,
- * or wrong PIN1/PIN2.
- * The error may be caused, for example, by wrong parameters of the [Task], [CommandSerializer],
- * mapping or serialization errors.
- */
- class InvalidParams : TaskError(2006)
-
- /**
- * This error is returned when a card's reply is [StatusWord.NeedEncryption]
- * and the encryption was not established by TangemSdk.
- */
- class NeedEncryption : TaskError(2007)
-
- //Scan errors
- /**
- * This error is returned when a [Task] checks unsuccessfully either
- * a card's ability to sign with its private key, or the validity of issuer data.
- */
- class VerificationFailed : TaskError(3000)
-
- /**
- * This error is returned when a [ScanTask] returns a [Card] without some of the essential fields.
- */
- class CardError : TaskError(3001)
-
- /**
- * This error is returned when a [Task] expects a user to use a particular card,
- * and a user tries to use a different card.
- */
- class WrongCard : TaskError(3002)
-
- /**
- * Tangem cards can sign currently up to 10 hashes during one [com.tangem.commands.SignCommand].
- * This error is returned when a [com.tangem.commands.SignCommand] receives more than 10 hashes to sign.
- */
- class TooMuchHashesInOneTransaction : TaskError(3003)
-
- /**
- * This error is returned when a [com.tangem.commands.SignCommand]
- * receives only empty hashes for signature.
- */
- class EmptyHashes : TaskError(3004)
-
- /**
- * This error is returned when a [com.tangem.commands.SignCommand]
- * receives hashes of different lengths for signature.
- */
- class HashSizeMustBeEqual : TaskError(3005)
-
- /**
- * This error is returned when [com.tangem.CardManager] was called with a new [Task],
- * while a previous [Task] is still in progress.
- */
- class Busy : TaskError(4000)
-
- /**
- * This error is returned when a user manually closes NFC Reading Bottom Sheet Dialog.
- */
- class UserCancelled : TaskError(4001)
-
- //NFC errors
- class NfcReaderError : TaskError(5002)
-
- /**
- * This error is returned when Android NFC reader loses a tag
- * (e.g. a user detaches card from the phone's NFC module) while the NFC session is in progress.
- */
- class TagLost : TaskError(5003)
-
- class UnknownError : TaskError(6000)
-
- //Specific Command Errors
- /**
- * This error is returned when [ReadIssuerDataTask] or [ReadIssuerExtraDataTask] expects a counter
- * (when the card's requires it), but the counter is missing.
- */
- class MissingCounter : TaskError(7001)
-}
-
-/**
- * Events that are are sent in callbacks from [Task].
- */
-sealed class TaskEvent {
-
- /**
- * A callback that is triggered by a Task.
- */
- class Event(val data: T) : TaskEvent()
-
- /**
- * A callback that is triggered when a [Task] is completed.
- *
- * @param error is null if it's a successful completion of a [Task]
- */
- class Completion(val error: TaskError? = null) : TaskEvent()
-}
-
-/**
- * Allows to perform a group of commands interacting between the card and the application.
- * A task opens an NFC session, sends commands to the card and receives its responses,
- * repeats the commands if needed, and closes session after receiving the last answer.
- */
-abstract class Task {
-
- var delegate: CardManagerDelegate? = null
- var reader: CardReader? = null
- var performPreflightRead: Boolean = true
- var securityDelayDuration: Int = 0
-
- /**
- * This method should be called to run the [Task] and perform all its operations.
- *
- * @param cardEnvironment Relevant current version of a card environment
- * @param callback It will be triggered during the performance of the [Task]
- */
- fun run(cardEnvironment: CardEnvironment,
- callback: (result: TaskEvent) -> Unit) {
- delegate?.onNfcSessionStarted(cardEnvironment.cardId)
- reader?.openSession()
- Log.i(this::class.simpleName!!, "Nfc task is started")
-
- if (performPreflightRead) {
- runWithPreflightRead(cardEnvironment, callback)
- } else {
- onRun(cardEnvironment, null, callback)
- }
- }
-
- /**
- * Should be called on [Task] completion, whether it was successful or with failure.
- *
- * @param taskError The error to be shown by [CardManagerDelegate]
- */
- protected fun completeNfcSession(taskError: TaskError? = null) {
- reader?.closeSession()
- if (taskError != null) {
- delegate?.onError(taskError)
- } else {
- delegate?.onNfcSessionCompleted()
- }
- }
-
- /**
- * In this method the individual Tasks' logic should be implemented.
- */
- protected abstract fun onRun(cardEnvironment: CardEnvironment,
- currentCard: Card?,
- callback: (result: TaskEvent) -> Unit)
-
- /**
- * This method should be called by Tasks in their [onRun] method wherever
- * they need to communicate with the Tangem Card by launching commands.
- */
- protected fun sendCommand(
- command: CommandSerializer,
- cardEnvironment: CardEnvironment,
- callback: (result: CompletionResult) -> Unit) {
-
- Log.i(this::class.simpleName!!, "Nfc command ${command::class.simpleName!!} is initiated")
-
- when (cardEnvironment.encryptionMode) {
- EncryptionMode.NONE -> {
- val commandApdu = command.serialize(cardEnvironment)
- sendRequest(command, commandApdu, cardEnvironment, callback)
- }
- EncryptionMode.FAST, EncryptionMode.STRONG -> {
- if (cardEnvironment.encryptionKey != null ) {
- val commandApdu = command.serialize(cardEnvironment)
- sendRequest(command, commandApdu, cardEnvironment, callback)
- return
- }
- val encryptionHelper: EncryptionHelper =
- if (cardEnvironment.encryptionMode == EncryptionMode.STRONG) {
- StrongEncryptionHelper()
- } else {
- FastEncryptionHelper()
- }
- val openSessionCommand = OpenSessionCommand(encryptionHelper.keyA)
- val openSessionApdu = openSessionCommand.serialize(cardEnvironment)
- sendRequest(openSessionCommand, openSessionApdu, cardEnvironment) { result ->
- when (result) {
- is CompletionResult.Success -> {
- val uid = result.data.uid
- val protocolKey = cardEnvironment.pin1.calculateSha256().pbkdf2Hash(uid, 50)
- val secret = encryptionHelper.generateSecret(result.data.sessionKeyB)
- val sessionKey = (secret + protocolKey).calculateSha256()
- cardEnvironment.encryptionKey = sessionKey
-
- sendCommand(command, cardEnvironment, callback)
- }
- is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
- }
- }
- }
- }
- }
-
- private fun sendRequest(command: CommandSerializer,
- commandApdu: CommandApdu,
- cardEnvironment: CardEnvironment,
- callback: (result: CompletionResult) -> Unit) {
-
- reader?.transceiveApdu(commandApdu) { result ->
-
- when (result) {
- is CompletionResult.Success -> {
- val responseApdu = result.data
- when (responseApdu.statusWord) {
- StatusWord.ProcessCompleted, StatusWord.Pin1Changed, StatusWord.Pin2Changed, StatusWord.PinsChanged
- -> {
- try {
- val responseData = command.deserialize(cardEnvironment, responseApdu)
- Log.i(this::class.simpleName!!, "Nfc command ${command::class.simpleName!!} is completed")
- callback(CompletionResult.Success(responseData as T))
- } catch (error: TaskError) {
- callback(CompletionResult.Failure(error))
- }
- }
- StatusWord.InvalidParams -> callback(CompletionResult.Failure(TaskError.InvalidParams()))
- StatusWord.Unknown -> {
- Log.e(this::class.simpleName!!, "Unknown status error: ${result.data.sw}")
- callback(CompletionResult.Failure(TaskError.UnknownStatus()))
- }
- StatusWord.ErrorProcessingCommand -> callback(CompletionResult.Failure(TaskError.ErrorProcessingCommand()))
- StatusWord.InvalidState -> callback(CompletionResult.Failure(TaskError.InvalidState()))
-
- StatusWord.InsNotSupported -> callback(CompletionResult.Failure(TaskError.InsNotSupported()))
- StatusWord.NeedEncryption -> {
- when (cardEnvironment.encryptionMode) {
- EncryptionMode.NONE -> {
- cardEnvironment.encryptionKey = null
- cardEnvironment.encryptionMode = EncryptionMode.FAST
- }
- EncryptionMode.FAST -> {
- cardEnvironment.encryptionKey = null
- cardEnvironment.encryptionMode = EncryptionMode.STRONG
- }
- EncryptionMode.STRONG -> {
- Log.e(this::class.simpleName!!, "Encryption doesn't work")
- callback(CompletionResult.Failure(TaskError.NeedEncryption()))
- return@transceiveApdu
- }
- }
- sendCommand(command, cardEnvironment, callback)
- }
- StatusWord.NeedPause -> {
- // NeedPause is returned from the card whenever security delay is triggered.
- val remainingTime = command.deserializeSecurityDelay(responseApdu, cardEnvironment)
- if (remainingTime != null) delegate?.onSecurityDelay(remainingTime, securityDelayDuration)
- Log.i(this::class.simpleName!!, "Nfc command ${command::class.simpleName!!} triggered security delay of $remainingTime milliseconds")
- sendRequest(command, commandApdu, cardEnvironment, callback)
- }
- }
- }
- is CompletionResult.Failure ->
- if (result.error == TaskError.TagLost()) {
- delegate?.onTagLost()
- } else if (result.error is TaskError.UserCancelled) {
- callback(CompletionResult.Failure(TaskError.UserCancelled()))
- reader?.closeSession()
- }
- }
- }
- }
-
- private fun runWithPreflightRead(
- environment: CardEnvironment, callback: (result: TaskEvent) -> Unit) {
- sendCommand(ReadCommand(), environment) { readResult ->
- when (readResult) {
- is CompletionResult.Failure -> {
- completeNfcSession(readResult.error)
- callback(TaskEvent.Completion(readResult.error))
- }
- is CompletionResult.Success -> {
- val receivedCardId = readResult.data.cardId
- securityDelayDuration = readResult.data.pauseBeforePin2 ?: 0
-
- if (environment.cardId != null && environment.cardId != receivedCardId) {
- completeNfcSession(TaskError.WrongCard())
- callback(TaskEvent.Completion(TaskError.WrongCard()))
- return@sendCommand
- }
-
- val newEnvironment = environment.copy(cardId = receivedCardId)
- onRun(newEnvironment, readResult.data, callback)
- }
- }
- }
- }
-}
-
-
diff --git a/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerDataTask.kt b/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerDataTask.kt
deleted file mode 100644
index b22ed95049..0000000000
--- a/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerDataTask.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.tangem.tasks
-
-import com.tangem.commands.Card
-import com.tangem.commands.Settings
-import com.tangem.commands.WriteIssuerDataCommand
-import com.tangem.commands.WriteIssuerDataResponse
-import com.tangem.commands.common.IssuerDataToVerify
-import com.tangem.common.CardEnvironment
-import com.tangem.common.CompletionResult
-
-class WriteIssuerDataTask(
- private val issuerData: ByteArray,
- private val issuerDataSignature: ByteArray,
- private val issuerDataCounter: Int? = null,
- private val issuerPublicKey: ByteArray? = null
-) : Task() {
-
- private lateinit var card: Card
-
- override fun onRun(
- cardEnvironment: CardEnvironment,
- currentCard: Card?,
- callback: (result: TaskEvent) -> Unit) {
-
- card = currentCard!!
- val command = WriteIssuerDataCommand(
- issuerData, issuerDataSignature, issuerDataCounter
- )
- if (!isCounterValid(issuerDataCounter)) {
- completeNfcSession(TaskError.MissingCounter())
- callback(TaskEvent.Completion(TaskError.MissingCounter()))
- } else if (!verifySignature(command, cardEnvironment.cardId!!)) {
- completeNfcSession(TaskError.VerificationFailed())
- callback(TaskEvent.Completion(TaskError.VerificationFailed()))
- }
-
- sendCommand(command, cardEnvironment) { result ->
- when (result) {
- is CompletionResult.Success -> {
- completeNfcSession()
- callback(TaskEvent.Event(result.data))
- callback(TaskEvent.Completion())
- }
- is CompletionResult.Failure -> {
- if (result.error !is TaskError.UserCancelled) {
- completeNfcSession(result.error)
- }
- callback(TaskEvent.Completion(result.error))
- }
- }
- }
- }
-
- private fun isCounterValid(issuerDataCounter: Int?): Boolean =
- if (isCounterRequired()) issuerDataCounter != null else true
-
- private fun isCounterRequired(): Boolean =
- card.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) != false
-
- private fun verifySignature(command: WriteIssuerDataCommand, cardId: String): Boolean {
- return command.verify(
- issuerPublicKey ?: card.issuerPublicKey!!,
- issuerDataSignature,
- IssuerDataToVerify(cardId, issuerData, issuerDataCounter)
- )
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerExtraDataTask.kt b/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerExtraDataTask.kt
deleted file mode 100644
index 887e832548..0000000000
--- a/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerExtraDataTask.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.tangem.tasks
-
-import com.tangem.commands.*
-import com.tangem.commands.common.IssuerDataMode
-import com.tangem.commands.common.IssuerDataToVerify
-import com.tangem.common.CardEnvironment
-import com.tangem.common.CompletionResult
-
-/**
- * This task performs [WriteIssuerExtraDataCommand] repeatedly until the issuer extra data is fully
- * written on the card.
- * @param issuerData Data provided by issuer.
- * @param startingSignature Issuer’s signature with Issuer Data Private Key of [cardId],
- * [issuerDataCounter] (if flags Protect_Issuer_Data_Against_Replay and
- * Restrict_Overwrite_Issuer_Extra_Data are set in [SettingsMask]) and size of [issuerData].
- * @param finalizingSignature Issuer’s signature with Issuer Data Private Key of [cardId],
- * [issuerData] and [issuerDataCounter] (the latter one only if flags Protect_Issuer_Data_Against_Replay
- * andRestrict_Overwrite_Issuer_Extra_Data are set in [SettingsMask]).
- * @param issuerDataCounter An optional counter that protect issuer data against replay attack.
- */
-internal class WriteIssuerExtraDataTask(
- private val issuerData: ByteArray,
- private val startingSignature: ByteArray,
- private val finalizingSignature: ByteArray,
- private val issuerPublicKey: ByteArray? = null,
- private val issuerDataCounter: Int? = null
-) : Task() {
-
- private lateinit var card: Card
- private lateinit var cardEnvironment: CardEnvironment
-
- override fun onRun(cardEnvironment: CardEnvironment,
- currentCard: Card?,
- callback: (result: TaskEvent) -> Unit) {
-
- card = currentCard!!
- this.cardEnvironment = cardEnvironment
- val command = WriteIssuerExtraDataCommand(
- issuerData, startingSignature, finalizingSignature, issuerDataCounter
- )
- if (!isCounterValid(issuerDataCounter)) {
- completeNfcSession(TaskError.MissingCounter())
- callback(TaskEvent.Completion(TaskError.MissingCounter()))
- } else if (!verifySignatures(command)) {
- completeNfcSession(TaskError.VerificationFailed())
- callback(TaskEvent.Completion(TaskError.VerificationFailed()))
- }
-
- writeIssuerData(command, callback)
- }
-
- private fun writeIssuerData(
- command: WriteIssuerExtraDataCommand,
- callback: (result: TaskEvent) -> Unit) {
-
- if (command.mode == IssuerDataMode.WriteExtraData) {
- delegate?.onDelay(issuerData.size, command.offset, WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE)
- }
- sendCommand(command, cardEnvironment) { result ->
- when (result) {
-
- is CompletionResult.Success -> {
- when (command.mode) {
- IssuerDataMode.InitializeWritingExtraData -> {
- command.mode = IssuerDataMode.WriteExtraData
- writeIssuerData(command, callback)
- return@sendCommand
- }
- IssuerDataMode.WriteExtraData -> {
- command.offset += WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE
- if (command.offset >= issuerData.size) {
- command.mode = IssuerDataMode.FinalizeExtraData
- }
- writeIssuerData(command, callback)
- return@sendCommand
- }
- IssuerDataMode.FinalizeExtraData -> {
- completeNfcSession()
- callback(TaskEvent.Event(result.data))
- callback(TaskEvent.Completion())
- }
- }
- }
- is CompletionResult.Failure -> {
- if (result.error !is TaskError.UserCancelled) {
- completeNfcSession(result.error)
- }
- callback(TaskEvent.Completion(result.error))
- }
- }
- }
- }
-
- private fun isCounterValid(issuerDataCounter: Int?): Boolean =
- if (isCounterRequired()) issuerDataCounter != null else true
-
- private fun isCounterRequired(): Boolean =
- card.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) != false
-
- private fun verifySignatures(command: WriteIssuerExtraDataCommand): Boolean {
- val publicKey = issuerPublicKey ?: card.issuerPublicKey!!
- val cardId = cardEnvironment.cardId!!
-
- val firstData = IssuerDataToVerify(cardId, null, issuerDataCounter, issuerData.size)
- val secondData = IssuerDataToVerify(cardId, issuerData, issuerDataCounter)
-
- return command.verify(publicKey, startingSignature, firstData) &&
- command.verify(publicKey, finalizingSignature, secondData)
- }
-}
\ No newline at end of file
diff --git a/tangem-core/src/test/java/com/tangem/common/tlv/TlvMapperTest.kt b/tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt
similarity index 71%
rename from tangem-core/src/test/java/com/tangem/common/tlv/TlvMapperTest.kt
rename to tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt
index 64cb5ce15d..f9915fc7b8 100644
--- a/tangem-core/src/test/java/com/tangem/common/tlv/TlvMapperTest.kt
+++ b/tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt
@@ -1,69 +1,69 @@
package com.tangem.common.tlv
import com.google.common.truth.Truth.assertThat
+import com.tangem.SessionError
import com.tangem.commands.*
import com.tangem.common.extensions.hexToBytes
-import com.tangem.tasks.TaskError
import org.junit.Test
import org.junit.jupiter.api.assertThrows
import java.util.*
-class TlvMapperTest {
+class TlvDecoderTest {
private val rawData = byteArrayOf(1, 8, -53, 34, 0, 0, 0, 2, 115, 116, 32, 11, 83, 77, 65, 82, 84, 32, 67, 65, 83, 72, 0, 2, 1, 2, -128, 6, 50, 46, 49, 49, 114, 0, 3, 65, 4, -49, 11, -50, -66, -121, -25, -2, 65, 65, -13, 14, 49, 27, -82, -33, -85, -113, 65, 20, 8, -39, -75, 57, 45, 65, -31, 35, 44, 38, 40, 63, -44, 113, -45, -75, -95, -118, 118, 29, 65, 117, -24, -53, 82, -72, 91, -20, -96, -77, -103, -14, -63, 52, -127, -123, -27, -16, -128, -67, -3, -104, -26, -22, 65, 10, 4, 0, 0, 126, 33, 12, 90, -127, 2, 0, 41, -126, 4, 7, -29, 5, 2, -125, 7, 84, 65, 78, 71, 69, 77, 0, -124, 3, 69, 84, 72, -122, 64, 111, -103, 48, -114, -40, 18, -103, 26, -102, -12, -38, -78, -90, -9, -98, 88, -47, -100, -24, 24, -105, -70, -72, 6, 94, -96, -77, 11, -123, -28, -118, 37, 63, 107, -55, -11, 23, -12, 13, -23, -121, -63, 36, -59, 70, 116, 91, -125, -34, -69, 23, -112, 6, 17, 4, -49, 68, -56, 29, -45, 81, 10, 97, 83, 48, 65, 4, -127, -106, -86, 75, 65, 10, -60, 74, 59, -100, -50, 24, -25, -66, 34, 106, -22, 7, 10, -52, -125, -87, -49, 103, 84, 15, -84, 73, -81, 37, 18, -97, 106, 83, -118, 40, -83, 99, 65, 53, -114, 60, 79, -103, 99, 6, 79, 126, 54, 83, 114, -90, 81, -45, 116, -27, -62, 60, -35, 55, -3, 9, -101, -14, 5, 10, 115, 101, 99, 112, 50, 53, 54, 107, 49, 0, 8, 4, 0, 15, 66, 64, 7, 1, 0, 9, 2, 11, -72, 96, 65, 4, -42, -5, -41, -84, -23, 88, 2, 86, -63, -118, -123, -10, -66, -82, -107, -68, -93, 111, 47, 93, -20, -86, 74, 28, 21, 81, 93, -21, -124, -57, -102, 55, 17, 84, -66, -68, -22, -128, 126, -99, -65, -54, -42, 59, -25, -21, -124, 5, 59, -16, -72, 73, 48, 16, -27, 103, -112, -73, 2, 96, -51, 41, -42, 116, 98, 4, 0, 15, 66, 52, 99, 4, 0, 0, 0, 13, 15, 1, 0)
private val tlvData = Tlv.deserialize(rawData)
- private val tlvMapper = TlvMapper(tlvData!!)
+ private val tlvMapper = TlvDecoder(tlvData!!)
- private val cardDataRaw: ByteArray = tlvMapper.map(TlvTag.CardData)
- private val cardDataMapper = TlvMapper(Tlv.deserialize(cardDataRaw)!!)
+ private val cardDataRaw: ByteArray = tlvMapper.decode(TlvTag.CardData)
+ private val cardDataMapper = TlvDecoder(Tlv.deserialize(cardDataRaw)!!)
@Test
fun `map optional when value is present`() {
- val settingsMask: SettingsMask? = tlvMapper.mapOptional(TlvTag.SettingsMask)
+ val settingsMask: SettingsMask? = tlvMapper.decodeOptional(TlvTag.SettingsMask)
assertThat(settingsMask)
.isNotNull()
}
@Test
fun `map optional when no tag returns null`() {
- val tokenSymbol: String? = tlvMapper.mapOptional(TlvTag.TokenSymbol)
+ val tokenSymbol: String? = tlvMapper.decodeOptional(TlvTag.TokenSymbol)
assertThat(tokenSymbol)
.isNull()
}
@Test
fun `map when value is null throws MissingTagException`() {
- assertThrows {
- tlvMapper.map(TlvTag.TokenSymbol)
+ assertThrows {
+ tlvMapper.decode(TlvTag.TokenSymbol)
}
}
@Test
fun `map optional to wrong type throws WrongTypeException`() {
- assertThrows {
- tlvMapper.mapOptional(TlvTag.CardData)
+ assertThrows {
+ tlvMapper.decodeOptional(TlvTag.CardData)
}
}
@Test
fun `map to wrong type throws WrongTypeException`() {
- assertThrows {
- tlvMapper.map(TlvTag.CardData)
+ assertThrows {
+ tlvMapper.decode(TlvTag.CardData)
}
}
@Test
fun `map boolean missing flag returns false`() {
- val terminalIsLinked: Boolean = tlvMapper.map(TlvTag.TerminalIsLinked)
+ val terminalIsLinked: Boolean = tlvMapper.decode(TlvTag.TerminalIsLinked)
assertThat(terminalIsLinked)
.isFalse()
}
@Test
fun `map SettingsMask returns correct value`() {
- val settingsMask: SettingsMask = tlvMapper.map(TlvTag.SettingsMask)
+ val settingsMask: SettingsMask = tlvMapper.decode(TlvTag.SettingsMask)
assertThat(settingsMask)
.isNotNull()
assertThat(settingsMask.rawValue)
@@ -82,16 +82,16 @@ class TlvMapperTest {
@Test
fun `map SigningMethods single value returns correct value`() {
- val signingMethods: SigningMethod = tlvMapper.map(TlvTag.SigningMethod)
+ val signingMethods: SigningMethod = tlvMapper.decode(TlvTag.SigningMethod)
assertThat(signingMethods.contains(SigningMethod.signHash))
.isTrue()
}
@Test
fun `map SigningMethods set of methods returns correct value`() {
- val localMapper = TlvMapper(Tlv.deserialize("070195".hexToBytes())!!)
+ val localMapper = TlvDecoder(Tlv.deserialize("070195".hexToBytes())!!)
- val signingMethod: SigningMethod = localMapper.map(TlvTag.SigningMethod)
+ val signingMethod: SigningMethod = localMapper.decode(TlvTag.SigningMethod)
assertThat(signingMethod.contains(SigningMethod.signHash))
.isTrue()
assertThat(signingMethod.contains(SigningMethod.signHashValidatedByIssuer))
@@ -110,38 +110,38 @@ class TlvMapperTest {
@Test
fun `map CardStatus returns correct value`() {
- val cardStatus: CardStatus = tlvMapper.map(TlvTag.Status)
+ val cardStatus: CardStatus = tlvMapper.decode(TlvTag.Status)
assertThat(cardStatus)
.isEqualTo(CardStatus.Loaded)
}
@Test
fun `map ProductMask with raw value 5 returns correct value`() {
- val localMapper = TlvMapper(listOf(Tlv(TlvTag.ProductMask, byteArrayOf(5))))
- val productMask: ProductMask = localMapper.map(TlvTag.ProductMask)
+ val localMapper = TlvDecoder(listOf(Tlv(TlvTag.ProductMask, byteArrayOf(5))))
+ val productMask: ProductMask = localMapper.decode(TlvTag.ProductMask)
assertThat(productMask.contains(ProductMask.note) && productMask.contains(ProductMask.idCard))
.isTrue()
}
@Test
fun `map ProductMask with raw value 1 returns correct value`() {
- val localMapper = TlvMapper(listOf(Tlv(TlvTag.ProductMask, byteArrayOf(1))))
- val productMask: ProductMask = localMapper.map(TlvTag.ProductMask)
+ val localMapper = TlvDecoder(listOf(Tlv(TlvTag.ProductMask, byteArrayOf(1))))
+ val productMask: ProductMask = localMapper.decode(TlvTag.ProductMask)
assertThat(productMask.contains(ProductMask.note))
.isTrue()
}
@Test
fun `map Enum with unknown code throws ConversionException error`() {
- val localMapper = TlvMapper(listOf(Tlv(TlvTag.CurveId, "test".toByteArray())))
- assertThrows {
- localMapper.map(TlvTag.CurveId)
+ val localMapper = TlvDecoder(listOf(Tlv(TlvTag.CurveId, "test".toByteArray())))
+ assertThrows {
+ localMapper.decode(TlvTag.CurveId)
}
}
@Test
fun `map DateTime returns correct value`() {
- val date: Date = cardDataMapper.map(TlvTag.ManufactureDateTime)
+ val date: Date = cardDataMapper.decode(TlvTag.ManufactureDateTime)
val expected = Calendar.getInstance().apply { this.set(2019, 4, 2, 0, 0, 0) }.time
assertThat(date.toString())
.isEqualTo(expected.toString())
@@ -149,43 +149,43 @@ class TlvMapperTest {
@Test
fun `map EllipticCurve returns correct value`() {
- val ellipticCurve: EllipticCurve = tlvMapper.map(TlvTag.CurveId)
+ val ellipticCurve: EllipticCurve = tlvMapper.decode(TlvTag.CurveId)
assertThat(ellipticCurve)
.isEqualTo(EllipticCurve.Secp256k1)
}
@Test
fun `map ByteArray returns correctly`() {
- val cardPublicKey: ByteArray = tlvMapper.map(TlvTag.CardPublicKey)
+ val cardPublicKey: ByteArray = tlvMapper.decode(TlvTag.CardPublicKey)
assertThat(cardPublicKey)
.isInstanceOf(ByteArray::class.java)
}
@Test
fun `map Int returns correct value`() {
- val signedHashes: Int = tlvMapper.map(TlvTag.SignedHashes)
+ val signedHashes: Int = tlvMapper.decode(TlvTag.SignedHashes)
assertThat(signedHashes)
.isEqualTo(13)
}
@Test
fun `map Int with wrong value throws ConversionException`() {
- val localMapper = TlvMapper(listOf(Tlv(TlvTag.SignedHashes, byteArrayOf(1, 2, 3, 4, 5))))
- assertThrows {
- localMapper.map(TlvTag.SignedHashes)
+ val localMapper = TlvDecoder(listOf(Tlv(TlvTag.SignedHashes, byteArrayOf(1, 2, 3, 4, 5))))
+ assertThrows {
+ localMapper.decode(TlvTag.SignedHashes)
}
}
@Test
fun `map UTF8 returns correct value`() {
- val blockchainId: String = cardDataMapper.map(TlvTag.BlockchainId)
+ val blockchainId: String = cardDataMapper.decode(TlvTag.BlockchainId)
assertThat(blockchainId)
.isEqualTo("ETH")
}
@Test
fun `map Hex returns correct value`() {
- val cardId: String = tlvMapper.map(TlvTag.CardId)
+ val cardId: String = tlvMapper.decode(TlvTag.CardId)
assertThat(cardId)
.isEqualTo("cb22000000027374")
}
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/Old_MainActivity.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/Old_MainActivity.kt
index f2c89bc9b4..40998ca19b 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/Old_MainActivity.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/Old_MainActivity.kt
@@ -3,16 +3,14 @@ package com.tangem.tangemtest
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
-import com.tangem.CardManager
+import com.tangem.TangemSdk
+import com.tangem.common.CompletionResult
import com.tangem.tangem_sdk_new.extensions.init
-import com.tangem.tasks.ScanEvent
-import com.tangem.tasks.TaskError
-import com.tangem.tasks.TaskEvent
import kotlinx.android.synthetic.main.old_activity_main.*
class Old_MainActivity : AppCompatActivity() {
- private lateinit var cardManager: CardManager
+ private lateinit var tangemSdk: TangemSdk
private lateinit var cardId: String
private lateinit var issuerData: ByteArray
private lateinit var issuerDataSignature: ByteArray
@@ -22,66 +20,50 @@ class Old_MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.old_activity_main)
- cardManager = CardManager.init(this)
+ tangemSdk = TangemSdk.init(this)
btn_scan?.setOnClickListener { _ ->
- cardManager.scanCard { taskEvent ->
+ tangemSdk.scanCard { taskEvent ->
when (taskEvent) {
- is TaskEvent.Event -> {
- when (taskEvent.data) {
- is ScanEvent.OnReadEvent -> {
- // Handle returned card data
- cardId = (taskEvent.data as ScanEvent.OnReadEvent).card.cardId
- runOnUiThread {
- tv_card_cid?.text = cardId
- btn_create_wallet.isEnabled = true
- }
- }
- is ScanEvent.OnVerifyEvent -> {
- //Handle card verification
- runOnUiThread {
- tv_card_cid?.text = cardId
- btn_sign.isEnabled = true
- btn_read_issuer_data.isEnabled = true
- btn_read_issuer_extra_data.isEnabled = true
- btn_write_issuer_data.isEnabled = true
- btn_purge_wallet.isEnabled = true
- btn_create_wallet.isEnabled = true
- }
- }
+ is CompletionResult.Success -> {
+ // Handle returned card data
+ val card = taskEvent.data
+ cardId = card.cardId
+ runOnUiThread {
+ tv_card_cid?.text = cardId
+ btn_create_wallet.isEnabled = true
+ tv_card_cid?.text = cardId
+ btn_sign.isEnabled = true
+ btn_read_issuer_data.isEnabled = true
+ btn_read_issuer_extra_data.isEnabled = true
+ btn_write_issuer_data.isEnabled = true
+ btn_purge_wallet.isEnabled = true
+ btn_create_wallet.isEnabled = true
+
}
}
- is TaskEvent.Completion -> {
- if (taskEvent.error != null) {
- if (taskEvent.error is TaskError.UserCancelled) {
- // Handle case when user cancelled manually
- }
- // Handle other errors
- }
- // Handle completion
- }
}
}
}
btn_sign?.setOnClickListener { _ ->
- cardManager.sign(
+ tangemSdk.sign(
createSampleHashes(),
cardId) {
when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
+ is CompletionResult.Failure -> {
+ runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
}
- is TaskEvent.Event -> runOnUiThread { tv_card_cid?.text = cardId + "was used to sign sample hashes." }
+ is CompletionResult.Success -> runOnUiThread { tv_card_cid?.text = cardId + "was used to sign sample hashes." }
}
}
}
btn_read_issuer_data?.setOnClickListener { _ ->
- cardManager.readIssuerData(cardId) {
+ tangemSdk.readIssuerData(cardId) {
when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
+ is CompletionResult.Failure -> {
+ runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
}
- is TaskEvent.Event -> runOnUiThread {
+ is CompletionResult.Success -> runOnUiThread {
btn_write_issuer_data.isEnabled = true
tv_card_cid?.text = it.data.issuerData.contentToString()
issuerData = it.data.issuerData
@@ -91,27 +73,27 @@ class Old_MainActivity : AppCompatActivity() {
}
}
btn_write_issuer_data?.setOnClickListener { _ ->
- cardManager.writeIssuerData(
+ tangemSdk.writeIssuerData(
cardId,
issuerData,
issuerDataSignature) {
when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
+ is CompletionResult.Failure -> {
+ runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
}
- is TaskEvent.Event -> runOnUiThread {
+ is CompletionResult.Success -> runOnUiThread {
tv_card_cid?.text = it.data.cardId
}
}
}
}
btn_read_issuer_extra_data?.setOnClickListener { _ ->
- cardManager.readIssuerExtraData(cardId) {
+ tangemSdk.readIssuerExtraData(cardId) {
when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
+ is CompletionResult.Failure -> {
+ runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
}
- is TaskEvent.Event -> runOnUiThread {
+ is CompletionResult.Success -> runOnUiThread {
issuerDataCounter = (it.data.issuerDataCounter ?: 0) + 1
btn_write_issuer_data.isEnabled = true
tv_card_cid?.text = "Read ${it.data.issuerData.size} bytes of data."
@@ -120,26 +102,26 @@ class Old_MainActivity : AppCompatActivity() {
}
}
btn_purge_wallet?.setOnClickListener { _ ->
- cardManager.purgeWallet(
+ tangemSdk.purgeWallet(
cardId) {
when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
+ is CompletionResult.Failure -> {
+ runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
}
- is TaskEvent.Event -> runOnUiThread {
+ is CompletionResult.Success -> runOnUiThread {
tv_card_cid?.text = it.data.status.name
}
}
}
}
btn_create_wallet?.setOnClickListener { _ ->
- cardManager.createWallet(
+ tangemSdk.createWallet(
cardId) {
when (it) {
- is TaskEvent.Completion -> {
- if (it.error != null) runOnUiThread { tv_card_cid?.text = it.error!!::class.simpleName }
+ is CompletionResult.Failure -> {
+ runOnUiThread { tv_card_cid?.text = it.error::class.simpleName }
}
- is TaskEvent.Event -> runOnUiThread {
+ is CompletionResult.Success -> runOnUiThread {
tv_card_cid?.text = it.data.status.name
btn_sign.isEnabled = true
btn_read_issuer_data.isEnabled = true
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt
index 9ffcba3103..7f3ba0639d 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt
@@ -5,14 +5,11 @@ import android.view.View
import android.widget.CompoundButton
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
-import com.tangem.CardManager
-import com.tangem.commands.ReadUserDataResponse
-import com.tangem.commands.WriteUserDataResponse
-import com.tangem.common.CardEnvironment
+import com.tangem.SessionEnvironment
+import com.tangem.SessionError
+import com.tangem.TangemSdk
+import com.tangem.common.CompletionResult
import com.tangem.tangem_sdk_new.extensions.init
-import com.tangem.tasks.ScanEvent
-import com.tangem.tasks.TaskError
-import com.tangem.tasks.TaskEvent
import kotlinx.android.synthetic.main.activity_test_user_data.*
import java.nio.charset.StandardCharsets
@@ -21,7 +18,7 @@ import java.nio.charset.StandardCharsets
*/
class TestUserDataActivity : AppCompatActivity() {
- private lateinit var cardManager: CardManager
+ private lateinit var tangemSdk: TangemSdk
private lateinit var writeOptions: WriteOptions
override fun onCreate(savedInstanceState: Bundle?) {
@@ -33,31 +30,15 @@ class TestUserDataActivity : AppCompatActivity() {
}
private fun init() {
- cardManager = CardManager.init(this)
+ tangemSdk = TangemSdk.init(this)
btn_scan?.setOnClickListener { _ ->
- cardManager.scanCard { taskEvent ->
+ tangemSdk.scanCard { taskEvent ->
when (taskEvent) {
- is TaskEvent.Event -> {
- when (taskEvent.data) {
- is ScanEvent.OnReadEvent -> {
- // Handle returned card data
- writeOptions.cardId = (taskEvent.data as ScanEvent.OnReadEvent).card.cardId
- runOnUiThread { showReadWriteSection(true) }
- }
- is ScanEvent.OnVerifyEvent -> {
- //Handle card verification
- }
- }
- }
- is TaskEvent.Completion -> {
- if (taskEvent.error != null) {
- if (taskEvent.error is TaskError.UserCancelled) {
- // Handle case when user cancelled manually
- }
- // Handle other errors
- }
- // Handle completion
+ is CompletionResult.Success -> {
+ // Handle returned card data
+ writeOptions.cardId = taskEvent.data.cardId
+ runOnUiThread { showReadWriteSection(true) }
}
}
}
@@ -66,7 +47,7 @@ class TestUserDataActivity : AppCompatActivity() {
btn_write.setOnClickListener {
if (writeOptions.cardId == null) return@setOnClickListener
- cardManager.writeUserData(
+ tangemSdk.writeUserData(
writeOptions.cardId!!,
writeOptions.userData,
writeOptions.userProtectedData,
@@ -74,16 +55,9 @@ class TestUserDataActivity : AppCompatActivity() {
writeOptions.userProtectedCounter
) {
when (it) {
- is TaskEvent.Completion -> handleError(tv_write_result, it.error)
- is TaskEvent.Event -> {
- runOnUiThread {
- val data = it.data as? WriteUserDataResponse
- if (data == null) {
- tv_write_result.text = "Response doesn't match"
- return@runOnUiThread
- }
- tv_write_result?.text = "Success"
- }
+ is CompletionResult.Failure -> handleError(tv_write_result, it.error)
+ is CompletionResult.Success -> {
+ runOnUiThread { tv_write_result?.text = "Success" }
}
}
}
@@ -92,28 +66,24 @@ class TestUserDataActivity : AppCompatActivity() {
btn_read.setOnClickListener {
if (writeOptions.cardId == null) return@setOnClickListener
- cardManager.readUserData(writeOptions.cardId!!) {
+ tangemSdk.readUserData(writeOptions.cardId!!) {
when (it) {
- is TaskEvent.Completion -> handleError(tv_read_result, it.error)
- is TaskEvent.Event -> {
+ is CompletionResult.Failure -> handleError(tv_write_result, it.error)
+ is CompletionResult.Success -> {
runOnUiThread {
- val data = it.data as? ReadUserDataResponse
- if (data == null) {
- tv_read_result.text = "Response doesn't match"
- return@runOnUiThread
- }
+
tv_read_result?.text = "Success"
- writeOptions.userData = data.userData
- writeOptions.userProtectedData = data.userProtectedData
- writeOptions.userCounter = data.userCounter
- writeOptions.userProtectedCounter = data.userProtectedCounter
+ writeOptions.userData = it.data.userData
+ writeOptions.userProtectedData = it.data.userProtectedData
+ writeOptions.userCounter = it.data.userCounter
+ writeOptions.userProtectedCounter = it.data.userProtectedCounter
- tv_card_cid.text = data.cardId
- tv_data.text = String(data.userData, StandardCharsets.US_ASCII)
- tv_protected_data.text = String(data.userProtectedData, StandardCharsets.US_ASCII)
- tv_counter.text = data.userCounter.toString()
- tv_protected_counter.text = data.userProtectedCounter.toString()
+ tv_card_cid.text = it.data.cardId
+ tv_data.text = String(it.data.userData, StandardCharsets.US_ASCII)
+ tv_protected_data.text = String(it.data.userProtectedData, StandardCharsets.US_ASCII)
+ tv_counter.text = it.data.userCounter.toString()
+ tv_protected_counter.text = it.data.userProtectedCounter.toString()
}
}
@@ -122,11 +92,10 @@ class TestUserDataActivity : AppCompatActivity() {
}
}
- private fun handleError(tv: TextView, error: TaskError?) {
- val er = error ?: return
- if (er is TaskError.UserCancelled) return
+ private fun handleError(tv: TextView, error: SessionError) {
+ if (error is SessionError.UserCancelled) return
- runOnUiThread { tv.text = er::class.simpleName }
+ runOnUiThread { tv.text = error::class.simpleName }
}
private fun initWriteOptions() {
@@ -174,7 +143,7 @@ class WriteOptions {
}
fun updatePin2(chbx: CompoundButton) {
- val value = CardEnvironment.DEFAULT_PIN2
+ val value = SessionEnvironment.DEFAULT_PIN2
pin2 = if (chbx.isChecked) value else null
}
}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/_main/MainViewModel.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/_main/MainViewModel.kt
index a599bcb479..a50da93a68 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/_main/MainViewModel.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/_main/MainViewModel.kt
@@ -2,7 +2,7 @@ package com.tangem.tangemtest._main
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
-import com.tangem.tasks.TaskEvent
+import com.tangem.commands.CommandResponse
import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
/**
@@ -11,16 +11,16 @@ import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
class MainViewModel : ViewModel() {
val ldDescriptionSwitch = MutableLiveData(false)
- var responseEvent: TaskEvent<*>? = null
+ var commandResponse: CommandResponse? = null
fun switchToggled(state: Boolean) {
ldDescriptionSwitch.postValue(state)
}
- fun changeResponseEvent(event: TaskEvent<*>?) {
+ fun changeResponseEvent(commandResponse: CommandResponse?) {
Log.d(this, "changeResponseEvent")
- val reqEvent = event ?: return
+ val response = commandResponse ?: return
- responseEvent = reqEvent
+ this.commandResponse = response
}
}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/Action.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/Action.kt
index a5f736fe1f..e8358b8071 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/Action.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/Action.kt
@@ -1,6 +1,7 @@
package com.tangem.tangemtest.ucase.domain.actions
-import com.tangem.CardManager
+import com.tangem.TangemSdk
+import com.tangem.common.CompletionResult
import com.tangem.tangemtest._arch.structure.Id
import com.tangem.tangemtest._arch.structure.Payload
import com.tangem.tangemtest._arch.structure.PayloadHolder
@@ -8,7 +9,6 @@ import com.tangem.tangemtest._arch.structure.abstraction.Item
import com.tangem.tangemtest.ucase.domain.paramsManager.ActionCallback
import com.tangem.tangemtest.ucase.domain.paramsManager.triggers.afterAction.AfterActionModification
import com.tangem.tangemtest.ucase.domain.paramsManager.triggers.changeConsequence.ItemsChangeConsequence
-import com.tangem.tasks.TaskEvent
/**
[REDACTED_AUTHOR]
@@ -17,7 +17,7 @@ import com.tangem.tasks.TaskEvent
* and then processing the response. It also allows you to extract the main action as a lambda expression
*/
data class AttrForAction(
- val cardManager: CardManager,
+ val tangemSdk: TangemSdk,
val itemList: List- ,
val payload: Payload,
val consequence: ItemsChangeConsequence?
@@ -31,17 +31,17 @@ interface Action {
abstract class BaseAction : Action {
protected open fun handleResult(
payload: PayloadHolder,
- taskEvent: TaskEvent<*>,
+ commandResult: CompletionResult<*>,
modifier: AfterActionModification?,
attrs: AttrForAction,
callback: ActionCallback
) {
val modifiedItems = mutableListOf
- ()
- modifier?.modify(payload, taskEvent, attrs.itemList)?.forEach { item ->
+ modifier?.modify(payload, commandResult, attrs.itemList)?.forEach { item ->
modifiedItems.add(item)
attrs.consequence?.affectChanges(payload, item, attrs.itemList)?.let { modifiedItems.addAll(it) }
}
- callback(taskEvent, modifiedItems)
+ callback(commandResult, modifiedItems)
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? = null
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/DepersonalizeAction.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/DepersonalizeAction.kt
index 5f49aa15aa..5dd9d80fc1 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/DepersonalizeAction.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/DepersonalizeAction.kt
@@ -14,7 +14,7 @@ class DepersonalizeAction : BaseAction() {
val item = attrs.itemList.findItem(TlvId.CardId) ?: return
val cardId = item.viewModel.data as? String ?: return
- attrs.cardManager.depersonalize(cardId) { handleResult(payload, it, null, attrs, callback) }
+ attrs.tangemSdk.depersonalize(cardId) { handleResult(payload, it, null, attrs, callback) }
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/PersonalizeAction.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/PersonalizeAction.kt
index 21143ddec8..612b728c24 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/PersonalizeAction.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/PersonalizeAction.kt
@@ -40,7 +40,7 @@ class PersonalizeAction : BaseAction() {
val personalizeConfig = PersonalizationConfigConverter().convert(itemList, PersonalizationConfig())
val cardConfig = PersonalizationConfigToCardConfig().convert(personalizeConfig)
- attrs.cardManager.personalize(cardConfig, issuer, manufacturer, acquirer) {
+ attrs.tangemSdk.personalize(cardConfig, issuer, manufacturer, acquirer) {
handleResult(payload, it, null, attrs, callback)
}
}
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/ScanAction.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/ScanAction.kt
index 5264be9aed..213fea8b63 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/ScanAction.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/ScanAction.kt
@@ -9,6 +9,6 @@ import com.tangem.tangemtest.ucase.domain.paramsManager.triggers.afterAction.Aft
*/
class ScanAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
- attrs.cardManager.scanCard { handleResult(payload, it, AfterScanModifier(), attrs, callback) }
+ attrs.tangemSdk.scanCard { handleResult(payload, it, AfterScanModifier(), attrs, callback) }
}
}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/SignAction.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/SignAction.kt
index d71eaeb900..375c2ce9a7 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/SignAction.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/actions/SignAction.kt
@@ -16,7 +16,7 @@ class SignAction : BaseAction() {
val hash = dataForHashing.getData() as? ByteArray ?: return
val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return
- attrs.cardManager.sign(arrayOf(hash), stringOf(cardId)) { handleResult(payload, it, null, attrs, callback) }
+ attrs.tangemSdk.sign(arrayOf(hash), stringOf(cardId)) { handleResult(payload, it, null, attrs, callback) }
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/ItemsManager.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/ItemsManager.kt
index 42b92174ad..a43809684b 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/ItemsManager.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/ItemsManager.kt
@@ -1,14 +1,14 @@
package com.tangem.tangemtest.ucase.domain.paramsManager
-import com.tangem.CardManager
+import com.tangem.TangemSdk
+import com.tangem.common.CompletionResult
import com.tangem.tangemtest._arch.structure.Id
import com.tangem.tangemtest._arch.structure.Payload
import com.tangem.tangemtest._arch.structure.PayloadHolder
import com.tangem.tangemtest._arch.structure.abstraction.Item
import com.tangem.tangemtest.ucase.domain.paramsManager.triggers.changeConsequence.ItemsChangeConsequence
-import com.tangem.tasks.TaskEvent
-typealias ActionResponse = TaskEvent<*>
+typealias ActionResponse = CompletionResult<*>
typealias AffectedList = List
-
typealias AffectedItemsCallback = (AffectedList) -> Unit
typealias ActionCallback = (ActionResponse, AffectedList) -> Unit
@@ -22,8 +22,8 @@ interface ItemsManager : PayloadHolder {
fun setItems(items: List
- )
fun getItems(): List
-
fun setItemChangeConsequences(consequence: ItemsChangeConsequence?)
- fun invokeMainAction(cardManager: CardManager, callback: ActionCallback)
- fun getActionByTag(id: Id, cardManager: CardManager): ((ActionCallback) -> Unit)?
+ fun invokeMainAction(tangemSdk: TangemSdk, callback: ActionCallback)
+ fun getActionByTag(id: Id, tangemSdk: TangemSdk): ((ActionCallback) -> Unit)?
fun attachPayload(payload: Payload)
}
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/BaseItemsManager.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/BaseItemsManager.kt
index 72729d11eb..6ddbc6a916 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/BaseItemsManager.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/BaseItemsManager.kt
@@ -1,7 +1,7 @@
package com.tangem.tangemtest.ucase.domain.paramsManager.managers
import androidx.lifecycle.LifecycleObserver
-import com.tangem.CardManager
+import com.tangem.TangemSdk
import com.tangem.tangemtest._arch.structure.Id
import com.tangem.tangemtest._arch.structure.Payload
import com.tangem.tangemtest._arch.structure.abstraction.Item
@@ -47,12 +47,12 @@ open class BaseItemsManager(protected val action: Action) : ItemsManager, Lifecy
this.changeConsequence = consequence
}
- override fun invokeMainAction(cardManager: CardManager, callback: ActionCallback) {
- action.executeMainAction(this, getAttrsForAction(cardManager), callback)
+ override fun invokeMainAction(tangemSdk: TangemSdk, callback: ActionCallback) {
+ action.executeMainAction(this, getAttrsForAction(tangemSdk), callback)
}
- override fun getActionByTag(id: Id, cardManager: CardManager): ((ActionCallback) -> Unit)? {
- return action.getActionByTag(this, id, getAttrsForAction(cardManager))
+ override fun getActionByTag(id: Id, tangemSdk: TangemSdk): ((ActionCallback) -> Unit)? {
+ return action.getActionByTag(this, id, getAttrsForAction(tangemSdk))
}
override fun attachPayload(payload: Payload) {
@@ -64,6 +64,6 @@ open class BaseItemsManager(protected val action: Action) : ItemsManager, Lifecy
changeConsequence?.affectChanges(this, param, itemList)?.let { callback?.invoke(it) }
}
- protected fun getAttrsForAction(cardManager: CardManager)
- : AttrForAction = AttrForAction(cardManager, itemList, payload, changeConsequence)
+ protected fun getAttrsForAction(tangemSdk: TangemSdk)
+ : AttrForAction = AttrForAction(tangemSdk, itemList, payload, changeConsequence)
}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt
index e67e278aca..1652cd2833 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/managers/PersonalizationItemsManager.kt
@@ -2,7 +2,7 @@ package com.tangem.tangemtest.ucase.domain.paramsManager.managers
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.OnLifecycleEvent
-import com.tangem.CardManager
+import com.tangem.TangemSdk
import com.tangem.tangemtest.commons.Store
import com.tangem.tangemtest.ucase.domain.actions.PersonalizeAction
import com.tangem.tangemtest.ucase.domain.paramsManager.ActionCallback
@@ -23,8 +23,8 @@ class PersonalizationItemsManager(
setItems(converter.convert(config))
}
- override fun invokeMainAction(cardManager: CardManager, callback: ActionCallback) {
- action.executeMainAction(this, getAttrsForAction(cardManager), callback)
+ override fun invokeMainAction(tangemSdk: TangemSdk, callback: ActionCallback) {
+ action.executeMainAction(this, getAttrsForAction(tangemSdk), callback)
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/triggers/afterAction/AfterActionModifiers.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/triggers/afterAction/AfterActionModifiers.kt
index 0b6cecbf64..48ab757ff0 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/triggers/afterAction/AfterActionModifiers.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/triggers/afterAction/AfterActionModifiers.kt
@@ -1,8 +1,8 @@
package com.tangem.tangemtest.ucase.domain.paramsManager.triggers.afterAction
+import com.tangem.common.CompletionResult
import com.tangem.tangemtest._arch.structure.PayloadHolder
import com.tangem.tangemtest._arch.structure.abstraction.Item
-import com.tangem.tasks.TaskEvent
/**
[REDACTED_AUTHOR]
@@ -12,5 +12,5 @@ import com.tangem.tasks.TaskEvent
* Returns a list of items that have been modified
*/
interface AfterActionModification {
- fun modify(payload: PayloadHolder, taskEvent: TaskEvent<*>, itemList: List
- ): List
-
+ fun modify(payload: PayloadHolder, commandResult: CompletionResult<*>, itemList: List
- ): List
-
}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/triggers/afterAction/AfterScanModifier.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/triggers/afterAction/AfterScanModifier.kt
index 5cf644eb32..f63694fcc7 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/triggers/afterAction/AfterScanModifier.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/paramsManager/triggers/afterAction/AfterScanModifier.kt
@@ -2,6 +2,7 @@ package com.tangem.tangemtest.ucase.domain.paramsManager.triggers.afterAction
import com.tangem.commands.Card
import com.tangem.commands.CardStatus
+import com.tangem.common.CompletionResult
import com.tangem.tangemtest._arch.structure.PayloadHolder
import com.tangem.tangemtest._arch.structure.abstraction.Item
import com.tangem.tangemtest._arch.structure.abstraction.findItem
@@ -9,17 +10,16 @@ import com.tangem.tangemtest.ucase.domain.paramsManager.PayloadKey
import com.tangem.tangemtest.ucase.tunnel.ActionView
import com.tangem.tangemtest.ucase.tunnel.CardError
import com.tangem.tangemtest.ucase.variants.TlvId
-import com.tangem.tasks.ScanEvent
-import com.tangem.tasks.TaskEvent
+
import ru.dev.gbixahue.eu4d.lib.android.global.threading.postUI
/**
[REDACTED_AUTHOR]
*/
class AfterScanModifier : AfterActionModification {
- override fun modify(payload: PayloadHolder, taskEvent: TaskEvent<*>, itemList: List
- ): List
- {
+ override fun modify(payload: PayloadHolder, commandResult: CompletionResult<*>, itemList: List
- ): List
- {
val foundItem = itemList.findItem(TlvId.CardId) ?: return listOf()
- val card = smartCast(taskEvent)?.card ?: return listOf()
+ val card = smartCast(commandResult) ?: return listOf()
val actionView = payload.get(PayloadKey.actionView) as? ActionView ?: return listOf()
return if (isNotPersonalized(card)) {
@@ -34,8 +34,8 @@ class AfterScanModifier : AfterActionModification {
}
}
- private fun smartCast(taskEvent: TaskEvent<*>): ScanEvent.OnReadEvent? {
- return (taskEvent as? TaskEvent.Event)?.data as? ScanEvent.OnReadEvent
+ private fun smartCast(commandResult: CompletionResult<*>): Card? {
+ return (commandResult as? CompletionResult.Success)?.data
}
private fun isNotPersonalized(card: Card): Boolean = card.status == CardStatus.NotPersonalized
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/responses/ResponseJsonConverter.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/responses/ResponseJsonConverter.kt
index 84695d90fb..d54bc08a5d 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/responses/ResponseJsonConverter.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/domain/responses/ResponseJsonConverter.kt
@@ -1,12 +1,8 @@
package com.tangem.tangemtest.ucase.domain.responses
import com.google.gson.*
-import com.tangem.commands.ProductMask
-import com.tangem.commands.Settings
-import com.tangem.commands.SettingsMask
-import com.tangem.commands.SigningMethod
+import com.tangem.commands.*
import com.tangem.common.extensions.toHexString
-import com.tangem.tasks.TaskEvent
import java.lang.reflect.Type
import java.text.DateFormat
import java.util.*
@@ -29,12 +25,7 @@ class ResponseJsonConverter {
return builder.create()
}
- fun convertTaskEvent(task: TaskEvent<*>?): String = gson.toJson(task)
-
- fun convertEvent(task: TaskEvent<*>?): String {
- val event = task as? TaskEvent.Event ?: ""
- return gson.toJson(event)
- }
+ fun convertResponse(response: CommandResponse?): String = gson.toJson(response)
}
class ByteTypeAdapter : JsonSerializer {
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/ActionViewModel.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/ActionViewModel.kt
index a44367f98c..ea37c478fd 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/ActionViewModel.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/ActionViewModel.kt
@@ -4,19 +4,19 @@ import android.view.View
import androidx.annotation.UiThread
import androidx.lifecycle.*
import com.google.gson.Gson
-import com.tangem.CardManager
+import com.tangem.SessionError
+import com.tangem.TangemSdk
+import com.tangem.commands.Card
+import com.tangem.commands.CommandResponse
+import com.tangem.common.CompletionResult
import com.tangem.tangemtest._arch.SingleLiveEvent
import com.tangem.tangemtest._arch.structure.Id
import com.tangem.tangemtest._arch.structure.Payload
import com.tangem.tangemtest._arch.structure.abstraction.Item
import com.tangem.tangemtest._arch.structure.abstraction.iterate
-import com.tangem.tangemtest.commons.performAction
import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager
import com.tangem.tangemtest.ucase.domain.responses.ResponseJsonConverter
import com.tangem.tangemtest.ucase.tunnel.ViewScreen
-import com.tangem.tasks.ScanEvent
-import com.tangem.tasks.TaskError
-import com.tangem.tasks.TaskEvent
import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
/**
@@ -28,19 +28,19 @@ class ActionViewModelFactory(private val manager: ItemsManager) : ViewModelProvi
class ActionViewModel(private val itemsManager: ItemsManager) : ViewModel(), LifecycleObserver {
- val seResponseEvent = SingleLiveEvent>()
- val seReadResponse = SingleLiveEvent()
- val seResponse = SingleLiveEvent()
+ val seResponse = SingleLiveEvent()
+ val seResponseData = SingleLiveEvent()
+ val seResponseCardData = SingleLiveEvent()
val ldItemList = MutableLiveData(itemsManager.getItems())
val seError: MutableLiveData = SingleLiveEvent()
val seChangedItems: MutableLiveData
> = SingleLiveEvent()
private val notifier: Notifier = Notifier(this)
- private lateinit var cardManager: CardManager
+ private lateinit var tangemSdk: TangemSdk
- fun setCardManager(cardManager: CardManager) {
- this.cardManager = cardManager
+ fun setCardManager(tangemSdk: TangemSdk) {
+ this.tangemSdk = tangemSdk
}
@Deprecated("Events must be send directly from the Widget")
@@ -54,15 +54,17 @@ class ActionViewModel(private val itemsManager: ItemsManager) : ViewModel(), Lif
//invokes Scan, Sign etc...
fun invokeMainAction() {
- performAction(itemsManager, cardManager, { paramsManager, cardManager ->
- paramsManager.invokeMainAction(cardManager) { response, listOfChangedParams ->
- notifier.handleActionResult(response, listOfChangedParams)
- }
- })
+ if (!::tangemSdk.isInitialized) {
+ Log.e(this, "TangemSdk isn't initialized")
+ return
+ }
+ itemsManager.invokeMainAction(tangemSdk) { response, listOfChangedParams ->
+ notifier.handleActionResult(response, listOfChangedParams)
+ }
}
fun getItemAction(id: Id): (() -> Unit)? {
- val itemFunction = itemsManager.getActionByTag(id, cardManager) ?: return null
+ val itemFunction = itemsManager.getActionByTag(id, tangemSdk) ?: return null
return {
itemFunction { response, listOfChangedParams ->
@@ -91,12 +93,12 @@ class ActionViewModel(private val itemsManager: ItemsManager) : ViewModel(), Lif
internal class Notifier(private val vm: ActionViewModel) {
- private var notShowedError: TaskError? = null
+ private var notShowedError: SessionError? = null
private val gson: Gson = ResponseJsonConverter().gson
- fun handleActionResult(response: TaskEvent<*>, list: List- ) {
+ fun handleActionResult(result: CompletionResult<*>, list: List
- ) {
if (list.isNotEmpty()) notifyItemsChanged(list)
- handleResponse(response)
+ handleCompletionResult(result)
}
@UiThread
@@ -104,47 +106,35 @@ internal class Notifier(private val vm: ActionViewModel) {
vm.seChangedItems.postValue(list)
}
- fun handleResponse(response: TaskEvent<*>) {
- val taskEvent = response as? TaskEvent<*> ?: return
+ fun handleCompletionResult(result: CompletionResult<*>) {
+ val commandResponse = result as? CompletionResult ?: return
- when (taskEvent) {
- is TaskEvent.Completion -> handleCompletionEvent(taskEvent)
- is TaskEvent.Event -> {
- handleDataEvent(taskEvent.data)
- vm.seResponseEvent.postValue(taskEvent)
- }
+ when (commandResponse) {
+ is CompletionResult.Success -> handleData(commandResponse.data)
+ is CompletionResult.Failure -> handleError(commandResponse.error)
}
}
- private fun handleDataEvent(event: Any?) {
+ private fun handleData(event: CommandResponse?) {
+ vm.seResponse.postValue(event)
when (event) {
- is ScanEvent.OnReadEvent -> vm.seReadResponse.postValue(gson.toJson(event))
- is ScanEvent.OnVerifyEvent -> {
- }
- else -> vm.seResponse.postValue(gson.toJson(event))
+ is Card -> vm.seResponseCardData.postValue(event)
+ else -> vm.seResponseData.postValue(event)
}
}
- private fun handleCompletionEvent(taskEvent: TaskEvent.Completion<*>) {
- if (taskEvent.error == null) {
- Log.d(this, "error = null")
- if (notShowedError != null) {
- vm.seError.postValue("${notShowedError!!::class.simpleName}")
- notShowedError = null
- }
- } else {
- Log.d(this, "error = ${taskEvent.error}")
- when (taskEvent.error) {
- is TaskError.UserCancelled -> {
- if (notShowedError == null) {
- vm.seError.postValue("User canceled the action")
- } else {
- vm.seError.postValue("${notShowedError!!::class.simpleName}")
- notShowedError = null
- }
+ private fun handleError(error: SessionError) {
+ Log.d(this, "error = $error")
+ when (error) {
+ is SessionError.UserCancelled -> {
+ if (notShowedError == null) {
+ vm.seError.postValue("User canceled the action")
+ } else {
+ vm.seError.postValue("${notShowedError!!::class.simpleName}")
+ notShowedError = null
}
- else -> notShowedError = taskEvent.error
}
+ else -> notShowedError = error
}
}
}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/BaseCardActionFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/BaseCardActionFragment.kt
index b9186f495a..7e50f755ef 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/BaseCardActionFragment.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/ui/BaseCardActionFragment.kt
@@ -9,7 +9,8 @@ import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.google.android.material.floatingactionbutton.FloatingActionButton
-import com.tangem.CardManager
+import com.tangem.TangemSdk
+import com.tangem.commands.Card
import com.tangem.tangem_sdk_new.extensions.init
import com.tangem.tangemtest.R
import com.tangem.tangemtest._arch.structure.Id
@@ -43,7 +44,7 @@ abstract class BaseCardActionFragment : BaseFragment(), ActionView {
bindViews()
viewLifecycleOwner.lifecycle.addObserver(actionVM)
- actionVM.setCardManager(CardManager.init(requireActivity()))
+ actionVM.setCardManager(TangemSdk.init(requireActivity()))
actionVM.attachToPayload(mutableMapOf(PayloadKey.actionView to this as ActionView))
initFab()
@@ -75,28 +76,37 @@ abstract class BaseCardActionFragment : BaseFragment(), ActionView {
protected open fun subscribeToViewModelChanges() {
Log.d(this, "subscribeToViewModelChanges")
- listenEvent()
- listenReadResponse()
listenResponse()
+ listenResponseData()
+ listenResponseCardData()
listenError()
listenChangedItems()
listenDescriptionSwitchChanges()
}
- protected open fun listenEvent() {
- actionVM.seResponseEvent.observe(viewLifecycleOwner, Observer {
+ private fun listenResponse() {
+ actionVM.seResponse.observe(viewLifecycleOwner, Observer {
+ Log.d(this, "listen response: $it")
mainActivityVM.changeResponseEvent(it)
})
}
- protected open fun listenReadResponse() {}
-
- protected open fun listenResponse() {
- actionVM.seResponse.observe(viewLifecycleOwner, Observer {
+ protected open fun listenResponseData() {
+ actionVM.seResponseData.observe(viewLifecycleOwner, Observer {
+ Log.d(this, "listen responseData: $it")
navigateTo(R.id.action_nav_card_action_to_response_screen)
})
}
+ protected open fun listenResponseCardData() {
+ actionVM.seResponseCardData.observe(viewLifecycleOwner, Observer {
+ Log.d(this, "listen responseCardData: $it")
+ responseCardDataHandled(it)
+ })
+ }
+
+ protected open fun responseCardDataHandled(card: Card?) {}
+
protected open fun listenError() {
actionVM.seError.observe(viewLifecycleOwner, Observer { showSnackbar(it) })
}
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/dto/DefaultPersonalizationParams.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/dto/DefaultPersonalizationParams.kt
index d82099cab8..ace112c0af 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/dto/DefaultPersonalizationParams.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/dto/DefaultPersonalizationParams.kt
@@ -1,9 +1,9 @@
package com.tangem.tangemtest.ucase.variants.personalize.dto
+import com.tangem.KeyPair
import com.tangem.commands.personalization.entities.Acquirer
import com.tangem.commands.personalization.entities.Issuer
import com.tangem.commands.personalization.entities.Manufacturer
-import com.tangem.common.KeyPair
/**
[REDACTED_AUTHOR]
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/PersonalizationFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/PersonalizationFragment.kt
index d0216c725b..4b950d8b57 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/PersonalizationFragment.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/personalize/ui/PersonalizationFragment.kt
@@ -3,6 +3,7 @@ package com.tangem.tangemtest.ucase.variants.personalize.ui
import android.os.Bundle
import android.view.View
import androidx.lifecycle.Observer
+import com.tangem.commands.Card
import com.tangem.tangemtest.R
import com.tangem.tangemtest._arch.structure.Id
import com.tangem.tangemtest._arch.structure.abstraction.Item
@@ -52,20 +53,6 @@ class PersonalizationFragment : BaseCardActionFragment() {
})
}
- override fun subscribeToViewModelChanges() {
- Log.d(this, "subscribeToViewModelChanges")
- listenEvent()
- listenError()
- listenDescriptionSwitchChanges()
- }
-
- override fun listenEvent() {
- actionVM.seResponseEvent.observe(viewLifecycleOwner, Observer {
- mainActivityVM.changeResponseEvent(it)
- navigateTo(R.id.action_nav_card_action_to_response_screen)
- })
- }
-
override fun showSnackbar(id: Id, additionalHandler: ((Id) -> Int)?) {
super.showSnackbar(id) {
when (id) {
@@ -75,4 +62,9 @@ class PersonalizationFragment : BaseCardActionFragment() {
}
}
}
+
+ override fun responseCardDataHandled(card: Card?) {
+ super.responseCardDataHandled(card)
+ navigateTo(R.id.action_nav_card_action_to_response_screen)
+ }
}
\ No newline at end of file
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ResponseViewModel.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ResponseViewModel.kt
index 6216ffbddc..dae8eef20d 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ResponseViewModel.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ResponseViewModel.kt
@@ -3,6 +3,7 @@ package com.tangem.tangemtest.ucase.variants.responses
import android.view.View
import androidx.lifecycle.ViewModel
import com.tangem.commands.Card
+import com.tangem.commands.CommandResponse
import com.tangem.commands.SignResponse
import com.tangem.commands.personalization.DepersonalizeResponse
import com.tangem.tangemtest.R
@@ -10,8 +11,6 @@ import com.tangem.tangemtest._arch.structure.abstraction.Item
import com.tangem.tangemtest._arch.structure.abstraction.ModelToItems
import com.tangem.tangemtest._arch.structure.abstraction.iterate
import com.tangem.tangemtest.ucase.variants.responses.converter.ConvertersStore
-import com.tangem.tasks.ScanEvent
-import com.tangem.tasks.TaskEvent
import ru.dev.gbixahue.eu4d.lib.android.global.log.Log
/**
@@ -22,13 +21,13 @@ class ResponseViewModel : ViewModel() {
private val convertersHolder = ConvertersStore()
private var itemList: List
- ? = null
- fun createItemList(taskEvent: TaskEvent<*>?): List
- {
+ fun createItemList(response: CommandResponse?): List
- {
Log.d(this, "createItemList: itemList size: ${itemList?.size ?: 0}")
- val event = taskEvent as? TaskEvent.Event ?: return emptyList()
- val type = event.data::class.java
+ val responseEvent = response ?: return emptyList()
+ val type = responseEvent::class.java
val converter = convertersHolder.get(type) as? ModelToItems ?: return emptyList()
- itemList = converter.convert(event.data)
+ itemList = converter.convert(responseEvent)
return itemList!!
}
@@ -38,13 +37,12 @@ class ResponseViewModel : ViewModel() {
}
}
- fun determineTitleId(taskEvent: TaskEvent<*>?): Int {
- val event = taskEvent as? TaskEvent.Event ?: return R.string.unknown
+ fun determineTitleId(response: CommandResponse?): Int {
+ val responseEvent = response ?: return R.string.unknown
- return when (event.data) {
- is ScanEvent.OnReadEvent -> R.string.fg_name_response_scan
- is SignResponse -> R.string.fg_name_response_sign
+ return when (responseEvent) {
is Card -> R.string.fg_name_response_personalization
+ is SignResponse -> R.string.fg_name_response_sign
is DepersonalizeResponse -> R.string.fg_name_response_depersonalization
else -> R.string.unknown
}
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/ConvertersStore.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/ConvertersStore.kt
index 9b1dc76a49..067d47027c 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/ConvertersStore.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/ConvertersStore.kt
@@ -3,13 +3,12 @@ package com.tangem.tangemtest.ucase.variants.responses.converter
import com.tangem.commands.Card
import com.tangem.commands.SignResponse
import com.tangem.commands.personalization.DepersonalizeResponse
-import com.tangem.tasks.ScanEvent
import ru.dev.gbixahue.eu4d.lib.kotlin.common.BaseTypedHolder
import java.lang.reflect.Type
class ConvertersStore : BaseTypedHolder() {
init {
- register(ScanEvent.OnReadEvent::class.java, ReadEventConverter())
+// register(CompletionResult.Success::class.java, ReadEventConverter())
register(SignResponse::class.java, SignResponseConverter())
register(Card::class.java, CardConverter())
register(DepersonalizeResponse::class.java, DepersonalizeResponseConverter())
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/SimpleConverters.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/SimpleConverters.kt
index a1c997465b..b0c43734b1 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/SimpleConverters.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/converter/SimpleConverters.kt
@@ -1,19 +1,20 @@
package com.tangem.tangemtest.ucase.variants.responses.converter
+import com.tangem.commands.Card
import com.tangem.commands.SignResponse
import com.tangem.commands.personalization.DepersonalizeResponse
+import com.tangem.common.CompletionResult
import com.tangem.tangemtest._arch.structure.StringId
import com.tangem.tangemtest._arch.structure.abstraction.Item
import com.tangem.tangemtest._arch.structure.abstraction.ModelToItems
import com.tangem.tangemtest._arch.structure.impl.TextItem
-import com.tangem.tasks.ScanEvent
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
/**
[REDACTED_AUTHOR]
*/
-class ReadEventConverter : ModelToItems {
- override fun convert(from: ScanEvent.OnReadEvent): List
- = CardConverter().convert(from.card)
+class ReadEventConverter : ModelToItems> {
+ override fun convert(from: CompletionResult.Success): List
- = CardConverter().convert(from.data)
}
class SignResponseConverter : ModelToItems {
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/ResponseFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/ResponseFragment.kt
index 4477f12894..a42d51e237 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/ResponseFragment.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/responses/ui/ResponseFragment.kt
@@ -33,7 +33,7 @@ open class ResponseFragment : BaseFragment() {
}
private fun setTittle() {
- val titleId = selfVM.determineTitleId(mainActivityVM.responseEvent)
+ val titleId = selfVM.determineTitleId(mainActivityVM.commandResponse)
activity?.setTitle(titleId)
}
@@ -47,7 +47,7 @@ open class ResponseFragment : BaseFragment() {
private fun buildWidgets() {
val builder = WidgetBuilder(ResponseItemBuilder())
- val itemList = selfVM.createItemList(mainActivityVM.responseEvent)
+ val itemList = selfVM.createItemList(mainActivityVM.commandResponse)
itemList.forEach { builder.build(it, itemContainer) }
}
@@ -67,7 +67,7 @@ open class ResponseFragment : BaseFragment() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_share -> {
- shareText(ResponseJsonConverter().convertEvent(mainActivityVM.responseEvent))
+ shareText(ResponseJsonConverter().convertResponse(mainActivityVM.commandResponse))
}
}
return super.onOptionsItemSelected(item)
diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/scan/ui/ScanActionFragment.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/scan/ui/ScanActionFragment.kt
index 1e5ed5eb9b..90e3931375 100644
--- a/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/scan/ui/ScanActionFragment.kt
+++ b/tangem-demo/src/main/java/com/tangem/tangemtest/ucase/variants/scan/ui/ScanActionFragment.kt
@@ -1,8 +1,6 @@
package com.tangem.tangemtest.ucase.variants.scan.ui
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.Observer
+import com.tangem.commands.Card
import com.tangem.tangemtest.R
import com.tangem.tangemtest.ucase.domain.paramsManager.ItemsManager
import com.tangem.tangemtest.ucase.domain.paramsManager.managers.ScanItemsManager
@@ -17,14 +15,12 @@ class ScanActionFragment : BaseCardActionFragment() {
override fun getLayoutId(): Int = R.layout.fg_action_card_scan
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- enableActionFab(true)
+ override fun initFab() {
+ actionFab.setOnClickListener { actionVM.invokeMainAction() }
}
- override fun listenReadResponse() {
- actionVM.seReadResponse.observe(viewLifecycleOwner, Observer {
- navigateTo(R.id.action_nav_card_action_to_response_screen)
- })
+ override fun responseCardDataHandled(card: Card?) {
+ super.responseCardDataHandled(card)
+ navigateTo(R.id.action_nav_card_action_to_response_screen)
}
}
\ No newline at end of file
diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultSessionViewDelegate.kt
similarity index 87%
rename from tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt
rename to tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultSessionViewDelegate.kt
index e1dd5bb69b..d9cdf14304 100644
--- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt
+++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultSessionViewDelegate.kt
@@ -6,24 +6,24 @@ import android.view.View
import android.view.animation.DecelerateInterpolator
import androidx.fragment.app.FragmentActivity
import com.google.android.material.bottomsheet.BottomSheetDialog
-import com.tangem.CardManagerDelegate
import com.tangem.Log
import com.tangem.LoggerInterface
+import com.tangem.Message
+import com.tangem.SessionViewDelegate
import com.tangem.common.CompletionResult
import com.tangem.tangem_sdk_new.extensions.hide
import com.tangem.tangem_sdk_new.extensions.show
import com.tangem.tangem_sdk_new.nfc.NfcReader
import com.tangem.tangem_sdk_new.ui.NfcEnableDialog
import com.tangem.tangem_sdk_new.ui.TouchCardAnimation
-import com.tangem.tasks.TaskError
import kotlinx.android.synthetic.main.layout_touch_card.*
import kotlinx.android.synthetic.main.nfc_bottom_sheet.*
/**
- * Default implementation of [CardManagerDelegate].
+ * Default implementation of [SessionViewDelegate].
* If no customisation is required, this is the preferred way to use Tangem SDK.
*/
-class DefaultCardManagerDelegate(private val reader: NfcReader) : CardManagerDelegate {
+class DefaultSessionViewDelegate(private val reader: NfcReader) : SessionViewDelegate {
lateinit var activity: FragmentActivity
private var readingDialog: BottomSheetDialog? = null
@@ -33,13 +33,13 @@ class DefaultCardManagerDelegate(private val reader: NfcReader) : CardManagerDel
setLogger()
}
- override fun onNfcSessionStarted(cardId: String?) {
+ override fun onNfcSessionStarted(cardId: String?, message: Message?) {
reader.readingCancelled = false
- postUI { showReadingDialog(activity, cardId) }
+ postUI { showReadingDialog(activity, cardId, message) }
if (!reader.nfcEnabled) showNFCEnableDialog()
}
- private fun showReadingDialog(activity: FragmentActivity, cardId: String?) {
+ private fun showReadingDialog(activity: FragmentActivity, cardId: String?, message: Message?) {
val dialogView = activity.layoutInflater.inflate(R.layout.nfc_bottom_sheet, null)
readingDialog = BottomSheetDialog(activity)
readingDialog?.setContentView(dialogView)
@@ -56,6 +56,10 @@ class DefaultCardManagerDelegate(private val reader: NfcReader) : CardManagerDel
readingDialog?.tvCardId?.visibility = View.VISIBLE
readingDialog?.tvCardId?.text = cardId
}
+ if (message != null) {
+ if (message.body != null) readingDialog?.tvTaskText?.text = message.body
+ if (message.header != null) readingDialog?.tvTaskTitle?.text = message.header
+ }
}
readingDialog?.setOnCancelListener {
reader.readingCancelled = true
@@ -132,25 +136,29 @@ class DefaultCardManagerDelegate(private val reader: NfcReader) : CardManagerDel
}
}
- override fun onNfcSessionCompleted() {
+ override fun onNfcSessionCompleted(message: Message?) {
postUI {
readingDialog?.lTouchCard?.hide()
readingDialog?.flSecurityDelay?.hide()
readingDialog?.flCompletion?.show()
readingDialog?.ivCompletion?.setImageDrawable(activity.getDrawable(R.drawable.ic_done_135dp))
+ if (message != null) {
+ if (message.body != null) readingDialog?.tvTaskText?.text = message.body
+ if (message.header != null) readingDialog?.tvTaskTitle?.text = message.header
+ }
performHapticFeedback()
}
postUI(300) { readingDialog?.dismiss() }
}
- override fun onError(error: TaskError) {
+ override fun onError(errorMessage: String) {
postUI {
readingDialog?.lTouchCard?.hide()
readingDialog?.flSecurityDelay?.hide()
readingDialog?.flCompletion?.hide()
readingDialog?.flError?.show()
readingDialog?.tvTaskTitle?.text = activity.getText(R.string.dialog_error)
- readingDialog?.tvTaskText?.text = "${error::class.simpleName}: ${error.code}"
+ readingDialog?.tvTaskText?.text = errorMessage
performHapticFeedback()
}
}
diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/TerminalKeysStorage.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/TerminalKeysStorage.kt
index 70b2cfa431..0e4eabae9c 100644
--- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/TerminalKeysStorage.kt
+++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/TerminalKeysStorage.kt
@@ -3,7 +3,7 @@ package com.tangem.tangem_sdk_new
import android.app.Application
import android.content.SharedPreferences
import at.favre.lib.armadillo.Armadillo
-import com.tangem.common.KeyPair
+import com.tangem.KeyPair
import com.tangem.common.TerminalKeysService
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toHexString
@@ -12,7 +12,7 @@ import com.tangem.crypto.CryptoUtils
/**
* Service for managing Terminal keypair, used for Linked Terminal feature.
- * Needs to be provided to [com.tangem.CardManager] by calling [com.tangem.CardManager.setTerminalKeysService]
+ * Needs to be provided to [com.tangem.TangemSdk] by calling [com.tangem.TangemSdk.setTerminalKeysService]
* Linked Terminal feature can be disabled manually by editing [com.tangem.Config].
* @param applicationContext is required to retrieve an instance of [SharedPreferences]
*/
diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/CardManager.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/TangemSdk.kt
similarity index 62%
rename from tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/CardManager.kt
rename to tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/TangemSdk.kt
index b2364c13cf..f69b7c96cf 100644
--- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/CardManager.kt
+++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/extensions/TangemSdk.kt
@@ -1,21 +1,21 @@
package com.tangem.tangem_sdk_new.extensions
import androidx.fragment.app.FragmentActivity
-import com.tangem.CardManager
-import com.tangem.tangem_sdk_new.DefaultCardManagerDelegate
+import com.tangem.TangemSdk
+import com.tangem.tangem_sdk_new.DefaultSessionViewDelegate
import com.tangem.tangem_sdk_new.NfcLifecycleObserver
import com.tangem.tangem_sdk_new.TerminalKeysStorage
import com.tangem.tangem_sdk_new.nfc.NfcManager
-fun CardManager.Companion.init(activity: FragmentActivity): CardManager {
+fun TangemSdk.Companion.init(activity: FragmentActivity): TangemSdk {
val nfcManager = NfcManager().apply {
this.setCurrentActivity(activity)
activity.lifecycle.addObserver(NfcLifecycleObserver(this))
}
- val cardManagerDelegate = DefaultCardManagerDelegate(nfcManager.reader).apply {
+ val viewDelegate = DefaultSessionViewDelegate(nfcManager.reader).apply {
this.activity = activity
}
- return CardManager(nfcManager.reader, cardManagerDelegate).apply {
+ return TangemSdk(nfcManager.reader, viewDelegate).apply {
this.setTerminalKeysService(TerminalKeysStorage(activity.application))
}
}
\ No newline at end of file
diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt
index 5ba6b11d4b..845dbb2abd 100644
--- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt
+++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt
@@ -6,10 +6,10 @@ import android.nfc.tech.IsoDep
import android.nfc.tech.NfcV
import com.tangem.CardReader
import com.tangem.Log
+import com.tangem.SessionError
import com.tangem.common.CompletionResult
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.ResponseApdu
-import com.tangem.tasks.TaskError
/**
* Provides NFC communication between an Android application and Tangem card.
@@ -38,7 +38,7 @@ class NfcReader : CardReader {
// Stops reading and sends failure callback to a task
// if reading is cancelled (when user closes nfc bottom sheet dialog).
closeSession()
- callback?.invoke(CompletionResult.Failure(TaskError.UserCancelled()))
+ callback?.invoke(CompletionResult.Failure(SessionError.UserCancelled()))
}
}
@@ -67,7 +67,7 @@ class NfcReader : CardReader {
private fun transceiveData() {
if (readingCancelled) {
- callback?.invoke(CompletionResult.Failure(TaskError.UserCancelled()))
+ callback?.invoke(CompletionResult.Failure(SessionError.UserCancelled()))
return
}
if (data == null) return
@@ -76,7 +76,7 @@ class NfcReader : CardReader {
try {
rawResponse = isoDep?.transceive(data)
} catch (exception: TagLostException) {
- callback?.invoke(CompletionResult.Failure(TaskError.TagLost()))
+ callback?.invoke(CompletionResult.Failure(SessionError.TagLost()))
isoDep = null
return
} catch (exception: Exception) {
@@ -110,7 +110,7 @@ class NfcReader : CardReader {
when (response) {
is SlixReadResult.Failure -> {
Log.e(this::class.simpleName!!, "${response.exception.message}")
- callback?.invoke(CompletionResult.Failure(TaskError.ErrorProcessingCommand()))
+ callback?.invoke(CompletionResult.Failure(SessionError.ErrorProcessingCommand()))
}
is SlixReadResult.Success -> {
callback?.invoke(CompletionResult.Success(ResponseApdu(response.data)))
diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/SlixTagReader.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/SlixTagReader.kt
index 587ded11a3..79f99b4eba 100644
--- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/SlixTagReader.kt
+++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/SlixTagReader.kt
@@ -7,7 +7,7 @@ import com.tangem.common.apdu.StatusWord
import com.tangem.common.extensions.toByteArray
import com.tangem.common.extensions.toHexString
import com.tangem.common.tlv.Tlv
-import com.tangem.common.tlv.TlvMapper
+import com.tangem.common.tlv.TlvDecoder
import com.tangem.common.tlv.TlvTag
import java.io.ByteArrayOutputStream
import java.io.IOException
@@ -64,9 +64,9 @@ class SlixTagReader() {
val areaBuf = readMultipleBlocks(1, blocksCount)
- val tlvNdef = TlvMapper(Tlv.deserialize(areaBuf, true) ?: listOf())
+ val tlvNdef = TlvDecoder(Tlv.deserialize(areaBuf, true) ?: listOf())
- return NdefMessage(tlvNdef.map(TlvTag.CardPublicKey))
+ return NdefMessage(tlvNdef.decode(TlvTag.CardPublicKey))
}
private fun readSingleBlock(blockNo: Int): ByteArray {