Updated on 2026-08-14
This commit is contained in:
parent
0c9dce4b23
commit
2ddc76b2c0
17 changed files with 148 additions and 207 deletions
|
|
@ -9,10 +9,9 @@ import com.tangem.tasks.*
|
|||
|
||||
class CardManager(
|
||||
private val reader: CardReader,
|
||||
private val cardManagerDelegate: CardManagerDelegate? = null,
|
||||
dataStorage: DataStorage? = null) {
|
||||
private val cardManagerDelegate: CardManagerDelegate? = null) {
|
||||
|
||||
var isBusy = false
|
||||
private var isBusy = false
|
||||
private set
|
||||
|
||||
private val cardEnvironmentRepository = mutableMapOf<String, CardEnvironment>()
|
||||
|
|
@ -22,13 +21,13 @@ class CardManager(
|
|||
}
|
||||
|
||||
fun scanCard(callback: (result: TaskEvent<ScanEvent>) -> Unit) {
|
||||
val task = ScanTask(cardManagerDelegate, reader)
|
||||
val task = ScanTask()
|
||||
runTask(task, callback = callback)
|
||||
}
|
||||
|
||||
fun sign(hashes: Array<ByteArray>, cardId: String,
|
||||
callback: (result: TaskEvent<SignResponse>) -> Unit) {
|
||||
var signCommand: SignCommand
|
||||
val signCommand: SignCommand
|
||||
try {
|
||||
signCommand = SignCommand(hashes, cardId)
|
||||
} catch (error: Exception) {
|
||||
|
|
@ -39,16 +38,34 @@ class CardManager(
|
|||
}
|
||||
return
|
||||
}
|
||||
val task = SingleCommandTask(signCommand, cardManagerDelegate, reader)
|
||||
val task = SingleCommandTask(signCommand)
|
||||
runTask(task, cardId, callback)
|
||||
}
|
||||
|
||||
fun <T> runTask(task: Task<T>, cardId: String? = null,
|
||||
callback: (result: TaskEvent<T>) -> Unit) {
|
||||
// AppExecutors.diskIO().execute {
|
||||
|
||||
if (isBusy) {
|
||||
callback(TaskEvent.Completion(TaskError.Busy()))
|
||||
return
|
||||
}
|
||||
|
||||
val environment = fetchCardEnvironment(cardId)
|
||||
isBusy = true
|
||||
task.run(environment, callback)
|
||||
|
||||
task.reader = reader
|
||||
task.delegate = cardManagerDelegate
|
||||
|
||||
task.run(environment) {
|
||||
when (it) {
|
||||
is TaskEvent.Event -> callback(it)
|
||||
is TaskEvent.Completion -> {
|
||||
isBusy = false
|
||||
callback(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +76,7 @@ class CardManager(
|
|||
fun <T : CommandResponse> runCommand(commandSerializer: CommandSerializer<T>,
|
||||
cardId: String? = null,
|
||||
callback: (result: TaskEvent<T>) -> Unit) {
|
||||
val task = SingleCommandTask(commandSerializer, cardManagerDelegate, reader)
|
||||
val task = SingleCommandTask(commandSerializer)
|
||||
runTask(task, cardId, callback)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ import com.tangem.tasks.TaskError
|
|||
interface CardManagerDelegate {
|
||||
|
||||
fun showSecurityDelay(ms: Int)
|
||||
fun hideSecurityDelay()
|
||||
fun requestPin(success: () -> String, error: (cardError: TaskError.CardError) -> TaskError.CardError)
|
||||
|
||||
fun openNfcPopup()
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
package com.tangem
|
||||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.apdu.CommandApdu
|
||||
import com.tangem.common.apdu.ResponseApdu
|
||||
|
||||
interface CardReader {
|
||||
var readingActive: Boolean
|
||||
fun sendApdu(apduSerialized: ByteArray, callback: (response: CompletionResult<ResponseApdu>) -> Unit)
|
||||
fun transceiveApdu(apdu: CommandApdu, callback: (response: CompletionResult<ResponseApdu>) -> Unit)
|
||||
fun setStartSession()
|
||||
}
|
||||
|
|
@ -27,9 +27,9 @@ class CheckWalletCommand(
|
|||
|
||||
override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
|
||||
val tlvData = listOf(
|
||||
Tlv(TlvTag.Pin, TlvTag.Pin.code, cardEnvironment.pin1.calculateSha256()),
|
||||
Tlv(TlvTag.CardId, TlvTag.CardId.code, cid.hexToBytes()),
|
||||
Tlv(TlvTag.Challenge, TlvTag.Challenge.code, challenge)
|
||||
Tlv(TlvTag.Pin, cardEnvironment.pin1.calculateSha256()),
|
||||
Tlv(TlvTag.CardId, cid.hexToBytes()),
|
||||
Tlv(TlvTag.Challenge, challenge)
|
||||
)
|
||||
|
||||
return CommandApdu(instructionCode, tlvData)
|
||||
|
|
|
|||
|
|
@ -3,58 +3,23 @@ package com.tangem.commands
|
|||
import com.tangem.CardEnvironment
|
||||
import com.tangem.common.apdu.CommandApdu
|
||||
import com.tangem.common.apdu.ResponseApdu
|
||||
import com.tangem.common.extentions.toInt
|
||||
import com.tangem.common.tlv.TlvTag
|
||||
import com.tangem.enums.Instruction
|
||||
import com.tangem.tasks.TaskError
|
||||
|
||||
//interface TlvMappable {
|
||||
// fun responseFromTlv(tlvList: List<Tlv>): CommandResponse?
|
||||
//}
|
||||
|
||||
interface CommandResponse
|
||||
// : TlvMappable {
|
||||
//
|
||||
//}
|
||||
|
||||
|
||||
abstract class CommandSerializer<T : CommandResponse>() {
|
||||
abstract class CommandSerializer<T : CommandResponse> {
|
||||
|
||||
abstract val instruction: Instruction
|
||||
abstract val instructionCode: Int
|
||||
|
||||
abstract fun serialize(cardEnvironment: CardEnvironment): CommandApdu
|
||||
abstract fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): T?
|
||||
}
|
||||
|
||||
sealed class CommandEvent {
|
||||
class Success(val response: Any) : CommandEvent()
|
||||
class Failure(val taskError: TaskError) : CommandEvent()
|
||||
class UserCancellation : CommandEvent()
|
||||
}
|
||||
|
||||
//class CheckWalletResponse(
|
||||
// val cardId: String,
|
||||
// val salt: ByteArray,
|
||||
// val walletSignature: ByteArray
|
||||
//) : CommandResponse, TlvMappable by CheckWalletResponse {
|
||||
//
|
||||
// companion object : TlvMappable {
|
||||
// override fun responseFromTlv(tlvList: List<Tlv>): CommandResponse? {
|
||||
// val mapper = TlvMapper(tlvList)
|
||||
//
|
||||
// return try {
|
||||
// CheckWalletResponse(
|
||||
// mapper.map(TlvTag.CardId),
|
||||
// mapper.map(TlvTag.Salt),
|
||||
// mapper.map(TlvTag.Signature)
|
||||
// )
|
||||
// } catch (exception: TlvMapperException) {
|
||||
// null
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
fun deserializeSecurityDelay(responseApdu: ResponseApdu, cardEnvironment: CardEnvironment): Int? {
|
||||
val tlv = responseApdu.getTlvData(cardEnvironment.encryptionKey)
|
||||
return tlv?.find { it.tag == TlvTag.Pause }?.value?.toInt()
|
||||
}
|
||||
}
|
||||
|
|
@ -100,13 +100,10 @@ class ReadCardCommand : CommandSerializer<ReadCardResponse>() {
|
|||
|
||||
override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
|
||||
|
||||
val tlvData = mutableListOf(
|
||||
Tlv(TlvTag.Pin, TlvTag.Pin.code, cardEnvironment.pin1.calculateSha256())
|
||||
)
|
||||
val tlvData = mutableListOf(Tlv(TlvTag.Pin, cardEnvironment.pin1.calculateSha256()))
|
||||
|
||||
cardEnvironment.terminalKeys?.let {
|
||||
Tlv(TlvTag.TerminalPublicKey,
|
||||
TlvTag.TerminalPublicKey.code, it.publicKey)
|
||||
Tlv(TlvTag.TerminalPublicKey, it.publicKey)
|
||||
}
|
||||
|
||||
return CommandApdu(instructionCode, tlvData)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,14 @@ import com.tangem.crypto.sign
|
|||
import com.tangem.enums.Instruction
|
||||
import com.tangem.tasks.TaskError
|
||||
|
||||
class SignResponse(
|
||||
val cardId: String,
|
||||
val signature: ByteArray,
|
||||
val remainingSignatures: Int,
|
||||
val signedHashes: Int
|
||||
) : CommandResponse
|
||||
|
||||
|
||||
class SignCommand(private val hashes: Array<ByteArray>, private val cardId: String)
|
||||
: CommandSerializer<SignResponse>() {
|
||||
|
||||
|
|
@ -34,12 +42,11 @@ class SignCommand(private val hashes: Array<ByteArray>, private val cardId: Stri
|
|||
|
||||
override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
|
||||
val tlvData = mutableListOf(
|
||||
Tlv(TlvTag.Pin, TlvTag.Pin.code, cardEnvironment.pin1.calculateSha256()),
|
||||
Tlv(TlvTag.Pin2, TlvTag.Pin2.code, cardEnvironment.pin2.calculateSha256()),
|
||||
Tlv(TlvTag.CardId, TlvTag.CardId.code, cardId.hexToBytes()),
|
||||
Tlv(TlvTag.TransactionOutHashSize,
|
||||
TlvTag.TransactionOutHashSize.code, byteArrayOf(hashSizes.toByte())),
|
||||
Tlv(TlvTag.TransactionOutHash, TlvTag.TransactionOutHash.code, dataToSign)
|
||||
Tlv(TlvTag.Pin, cardEnvironment.pin1.calculateSha256()),
|
||||
Tlv(TlvTag.Pin2, cardEnvironment.pin2.calculateSha256()),
|
||||
Tlv(TlvTag.CardId, cardId.hexToBytes()),
|
||||
Tlv(TlvTag.TransactionOutHashSize,byteArrayOf(hashSizes.toByte())),
|
||||
Tlv(TlvTag.TransactionOutHash, dataToSign)
|
||||
)
|
||||
|
||||
addTerminalSignature(cardEnvironment, tlvData)
|
||||
|
|
@ -50,9 +57,8 @@ class SignCommand(private val hashes: Array<ByteArray>, private val cardId: Stri
|
|||
private fun addTerminalSignature(cardEnvironment: CardEnvironment, tlvData: MutableList<Tlv>) {
|
||||
cardEnvironment.terminalKeys?.let {
|
||||
val signedData = dataToSign.sign(it.privateKey)
|
||||
tlvData.add(Tlv(TlvTag.TerminalTransactionSignature,
|
||||
TlvTag.TerminalTransactionSignature.code, signedData))
|
||||
tlvData.add(Tlv(TlvTag.TerminalPublicKey, TlvTag.TerminalPublicKey.code, it.publicKey))
|
||||
tlvData.add(Tlv(TlvTag.TerminalTransactionSignature, signedData))
|
||||
tlvData.add(Tlv(TlvTag.TerminalPublicKey, it.publicKey))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,11 +73,4 @@ class SignCommand(private val hashes: Array<ByteArray>, private val cardId: Stri
|
|||
tlvMapper.map(TlvTag.SignedHashes)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class SignResponse(
|
||||
val cardId: String,
|
||||
val signature: ByteArray,
|
||||
val remainingSignatures: Int,
|
||||
val signedHashes: Int
|
||||
) : CommandResponse
|
||||
}
|
||||
|
|
@ -19,10 +19,14 @@ class CommandApdu(
|
|||
private val encryptionMode: EncryptionMode = EncryptionMode.NONE,
|
||||
private val encryptionKey: ByteArray? = null) {
|
||||
|
||||
val apduData: ByteArray
|
||||
|
||||
fun toBytes(): ByteArray {
|
||||
init {
|
||||
apduData = toBytes()
|
||||
}
|
||||
|
||||
// var length = 4 // CLA, INS, P1, P2
|
||||
|
||||
private fun toBytes(): ByteArray {
|
||||
|
||||
val data = if (tlvList.isNotEmpty()) {
|
||||
tlvList.toBytes()
|
||||
|
|
@ -31,13 +35,6 @@ class CommandApdu(
|
|||
}
|
||||
|
||||
val lc = data.size
|
||||
//
|
||||
// if (data.isNotEmpty()) {
|
||||
// length += 1 // LC
|
||||
// if (lc >= 256)
|
||||
// length += 2
|
||||
// length += data.size // DATA
|
||||
// }
|
||||
|
||||
|
||||
val byteStream = ByteArrayOutputStream()
|
||||
|
|
@ -50,45 +47,13 @@ class CommandApdu(
|
|||
byteStream.write(data)
|
||||
}
|
||||
return byteStream.toByteArray()
|
||||
|
||||
// val apdu = ByteArray(length)
|
||||
//
|
||||
// var index = 0
|
||||
// apdu[index] = cla
|
||||
// index++
|
||||
// apdu[index] = instruction
|
||||
// index++
|
||||
// apdu[index] = p1
|
||||
// index++
|
||||
// apdu[index] = p2
|
||||
// index++
|
||||
// if (lc != 0) {
|
||||
// if (lc < 256) {
|
||||
// apdu[index] = lc.toByte()
|
||||
// index++
|
||||
// } else {
|
||||
// apdu[index] = 0
|
||||
// index++
|
||||
// apdu[index] = (lc shr 8).toByte()
|
||||
// index++
|
||||
// apdu[index] = (lc and 0xFF).toByte()
|
||||
// index++
|
||||
// }
|
||||
//
|
||||
// System.arraycopy(data, 0, apdu, index, data.size)
|
||||
// index += data.size
|
||||
// }
|
||||
// return apdu
|
||||
}
|
||||
|
||||
private fun writeLength(stream: ByteArrayOutputStream, lc: Int) {
|
||||
// if (lc < 256) {
|
||||
// stream.write(lc)
|
||||
// } else {
|
||||
stream.write(0)
|
||||
stream.write(lc shr 8)
|
||||
stream.write(lc and 0xFF)
|
||||
// }
|
||||
|
||||
stream.write(0)
|
||||
stream.write(lc shr 8)
|
||||
stream.write(lc and 0xFF)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import com.tangem.enums.Status
|
|||
|
||||
class ResponseApdu(val data: ByteArray) {
|
||||
|
||||
val sw1: Int = 0x00FF and data[data.size - 2].toInt()
|
||||
val sw2: Int = 0x00FF and data[data.size - 1].toInt()
|
||||
private val sw1: Int = 0x00FF and data[data.size - 2].toInt()
|
||||
private val sw2: Int = 0x00FF and data[data.size - 1].toInt()
|
||||
|
||||
val sw: Int = sw1 shl 8 or sw2
|
||||
|
||||
|
|
|
|||
|
|
@ -3,53 +3,68 @@ package com.tangem.common.tlv
|
|||
import java.io.ByteArrayInputStream
|
||||
import java.io.IOException
|
||||
|
||||
class Tlv(val tag: TlvTag, val tagCode: Int, val value: ByteArray = byteArrayOf()) {
|
||||
class Tlv {
|
||||
|
||||
val tag: TlvTag
|
||||
val value: ByteArray
|
||||
val tagCode: Int
|
||||
|
||||
constructor(tagCode: Int, value: ByteArray = byteArrayOf()) {
|
||||
this.tag = TlvTag.byCode(tagCode)
|
||||
this.tagCode = tagCode
|
||||
this.value = value
|
||||
}
|
||||
|
||||
constructor(tag: TlvTag, value: ByteArray = byteArrayOf()) {
|
||||
this.tag = tag
|
||||
this.tagCode = tag.code
|
||||
this.value = value
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
fun tlvFromBytes(stream: ByteArrayInputStream): Tlv? {
|
||||
val code = stream.read()
|
||||
if (code == -1) return null
|
||||
var len = stream.read()
|
||||
if (len == -1)
|
||||
throw IOException("Can't read TLV")
|
||||
if (len == 0xFF) {
|
||||
val lenH = stream.read()
|
||||
if (lenH == -1)
|
||||
throw IOException("Can't read TLV")
|
||||
len = stream.read()
|
||||
companion object {
|
||||
fun tlvFromBytes(stream: ByteArrayInputStream): Tlv? {
|
||||
val code = stream.read()
|
||||
if (code == -1) return null
|
||||
var len = stream.read()
|
||||
if (len == -1)
|
||||
throw IOException("Can't read TLV")
|
||||
len = len or (lenH shl 8)
|
||||
}
|
||||
val value = ByteArray(len)
|
||||
if (len > 0) {
|
||||
if (len != stream.read(value)) {
|
||||
throw IOException("Can't read TLV")
|
||||
if (len == 0xFF) {
|
||||
val lenH = stream.read()
|
||||
if (lenH == -1)
|
||||
throw IOException("Can't read TLV")
|
||||
len = stream.read()
|
||||
if (len == -1)
|
||||
throw IOException("Can't read TLV")
|
||||
len = len or (lenH shl 8)
|
||||
}
|
||||
}
|
||||
val tag = TlvTag.byCode(code)
|
||||
return Tlv(tag, code, value)
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun fromBytes(mData: ByteArray): List<Tlv> {
|
||||
val tlvList = mutableListOf<Tlv>()
|
||||
val stream = ByteArrayInputStream(mData)
|
||||
var tlv: Tlv? = null
|
||||
do {
|
||||
try {
|
||||
tlv = Tlv.tlvFromBytes(stream)
|
||||
if (tlv != null) tlvList.add(tlv)
|
||||
} catch (e: IOException) {
|
||||
throw TlvMapperException("TLVError: " + e.message)
|
||||
val value = ByteArray(len)
|
||||
if (len > 0) {
|
||||
if (len != stream.read(value)) {
|
||||
throw IOException("Can't read TLV")
|
||||
}
|
||||
}
|
||||
val tag = TlvTag.byCode(code)
|
||||
return if (tag == TlvTag.Unknown) Tlv(code, value) else Tlv(tag, value)
|
||||
}
|
||||
|
||||
} while (tlv != null)
|
||||
return tlvList
|
||||
|
||||
fun fromBytes(mData: ByteArray): List<Tlv> {
|
||||
val tlvList = mutableListOf<Tlv>()
|
||||
val stream = ByteArrayInputStream(mData)
|
||||
var tlv: Tlv? = null
|
||||
do {
|
||||
try {
|
||||
tlv = Tlv.tlvFromBytes(stream)
|
||||
if (tlv != null) tlvList.add(tlv)
|
||||
} catch (e: IOException) {
|
||||
throw TlvMapperException("TLVError: " + e.message)
|
||||
}
|
||||
|
||||
} while (tlv != null)
|
||||
return tlvList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package com.tangem.tasks
|
||||
|
||||
import com.tangem.CardEnvironment
|
||||
import com.tangem.CardManagerDelegate
|
||||
import com.tangem.CardReader
|
||||
import com.tangem.commands.CheckWalletCommand
|
||||
import com.tangem.commands.EllipticCurve
|
||||
import com.tangem.commands.ReadCardCommand
|
||||
|
|
@ -16,7 +14,7 @@ sealed class ScanEvent {
|
|||
}
|
||||
|
||||
|
||||
internal class ScanTask(delegate: CardManagerDelegate? = null, reader: CardReader) : Task<ScanEvent>(delegate, reader) {
|
||||
internal class ScanTask : Task<ScanEvent>() {
|
||||
|
||||
private lateinit var readCardData: ReadCardResponse
|
||||
private lateinit var challenge: ByteArray
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
package com.tangem.tasks
|
||||
|
||||
import com.tangem.CardEnvironment
|
||||
import com.tangem.CardManagerDelegate
|
||||
import com.tangem.CardReader
|
||||
import com.tangem.commands.CommandResponse
|
||||
import com.tangem.commands.CommandSerializer
|
||||
|
||||
class SingleCommandTask<Event : CommandResponse>(
|
||||
private val commandSerializer: CommandSerializer<Event>,
|
||||
delegate: CardManagerDelegate? = null,
|
||||
reader: CardReader) : Task<Event>(delegate, reader) {
|
||||
private val commandSerializer: CommandSerializer<Event>) : Task<Event>() {
|
||||
|
||||
override fun onRun(cardEnvironment: CardEnvironment,
|
||||
callback: (result: TaskEvent<Event>) -> Unit) {
|
||||
|
|
|
|||
|
|
@ -7,17 +7,18 @@ import com.tangem.Log
|
|||
import com.tangem.commands.CommandResponse
|
||||
import com.tangem.commands.CommandSerializer
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extentions.toInt
|
||||
import com.tangem.common.tlv.TlvTag
|
||||
import com.tangem.enums.Status
|
||||
|
||||
abstract class Task<T>(protected val delegate: CardManagerDelegate? = null, protected val reader: CardReader) {
|
||||
abstract class Task<T> {
|
||||
|
||||
var delegate: CardManagerDelegate? = null
|
||||
var reader: CardReader? = null
|
||||
|
||||
fun run(cardEnvironment: CardEnvironment,
|
||||
callback: (result: TaskEvent<T>) -> Unit) {
|
||||
|
||||
delegate?.openNfcPopup()
|
||||
reader.setStartSession()
|
||||
reader?.setStartSession()
|
||||
Log.i(this::class.simpleName!!, "Nfc task is started")
|
||||
onRun(cardEnvironment, callback)
|
||||
|
||||
|
|
@ -34,8 +35,8 @@ abstract class Task<T>(protected val delegate: CardManagerDelegate? = null, prot
|
|||
Log.i(this::class.simpleName!!, "Nfc command ${commandSerializer::class.simpleName!!} is initiated")
|
||||
|
||||
|
||||
reader.sendApdu(
|
||||
commandSerializer.serialize(cardEnvironment).toBytes()) { result ->
|
||||
reader?.transceiveApdu(
|
||||
commandSerializer.serialize(cardEnvironment)) { result ->
|
||||
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
|
|
@ -61,10 +62,9 @@ abstract class Task<T>(protected val delegate: CardManagerDelegate? = null, prot
|
|||
Status.InsNotSupported -> callback(TaskEvent.Completion(TaskError.InsNotSupported()))
|
||||
Status.NeedEncryption -> callback(TaskEvent.Completion(TaskError.NeedEncryption()))
|
||||
Status.NeedPause -> {
|
||||
val tlv = responseApdu.getTlvData(cardEnvironment.encryptionKey)
|
||||
val ms = tlv?.find { it.tag == TlvTag.Pause }?.value?.toInt()
|
||||
if (ms != null) delegate?.showSecurityDelay(ms)
|
||||
Log.i(this::class.simpleName!!, "Nfc command ${commandSerializer::class.simpleName!!} triggered security delay of $ms milliseconds")
|
||||
val remainingTime = commandSerializer.deserializeSecurityDelay(responseApdu, cardEnvironment)
|
||||
if (remainingTime != null) delegate?.showSecurityDelay(remainingTime)
|
||||
Log.i(this::class.simpleName!!, "Nfc command ${commandSerializer::class.simpleName!!} triggered security delay of $remainingTime milliseconds")
|
||||
sendCommand(commandSerializer, cardEnvironment, callback)
|
||||
}
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ abstract class Task<T>(protected val delegate: CardManagerDelegate? = null, prot
|
|||
is CompletionResult.Failure ->
|
||||
if (result.error is TaskError.UserCancelledError) {
|
||||
callback(TaskEvent.Completion(TaskError.UserCancelledError()))
|
||||
reader.readingActive = false
|
||||
reader?.readingActive = false
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -85,6 +85,7 @@ sealed class TaskError(description: String? = null) : Exception(description) {
|
|||
class MappingError : TaskError()
|
||||
class GenericError(description: String? = null) : TaskError(description)
|
||||
class UserCancelledError() : TaskError()
|
||||
class Busy(): TaskError()
|
||||
|
||||
class ErrorProcessingCommand : TaskError()
|
||||
class InvalidState : TaskError()
|
||||
|
|
@ -104,12 +105,6 @@ sealed class TaskError(description: String? = null) : Exception(description) {
|
|||
class HashSizeMustBeEqual() : TaskError()
|
||||
}
|
||||
|
||||
sealed class TaskResult {
|
||||
data class Success(val resultData: Any) : TaskResult()
|
||||
data class CommandCompleted(val resultData: Any) : TaskResult()
|
||||
data class Error(val error: TaskError) : TaskResult()
|
||||
}
|
||||
|
||||
sealed class TaskEvent<T> {
|
||||
class Event<T>(val data: T) : TaskEvent<T>()
|
||||
class Completion<T>(val error: TaskError? = null) : TaskEvent<T>()
|
||||
|
|
|
|||
|
|
@ -4,24 +4,23 @@ import androidx.fragment.app.FragmentActivity
|
|||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.tangem.CardManagerDelegate
|
||||
import com.tangem.Log
|
||||
import com.tangem.tasks.Task
|
||||
import com.tangem.tasks.TaskError
|
||||
import kotlinx.android.synthetic.main.layout_touch_card.*
|
||||
|
||||
|
||||
class BasicCardManagerDelegate(private val activity: FragmentActivity, private val reader: NfcReader) : CardManagerDelegate {
|
||||
class DefaultCardManagerDelegate(private val activity: FragmentActivity, private val reader: NfcReader) : CardManagerDelegate {
|
||||
|
||||
private var dialog: BottomSheetDialog? = null
|
||||
|
||||
private var task: Task<*>? = null
|
||||
|
||||
override fun showSecurityDelay(ms: Int) {
|
||||
// activity.runOnUiThread{
|
||||
// activity.tv_security_delay?.text = "Security delay. $ms left."
|
||||
// }
|
||||
}
|
||||
|
||||
override fun hideSecurityDelay() {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun requestPin(success: () -> String, error: (cardError: TaskError.CardError) -> TaskError.CardError) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
|
@ -48,6 +47,7 @@ class BasicCardManagerDelegate(private val activity: FragmentActivity, private v
|
|||
}
|
||||
dialog?.setOnDismissListener {
|
||||
reader.readingCancelled = false
|
||||
task = null
|
||||
Log.i(this::class.simpleName!!, "readingCancelled is set to true")
|
||||
}
|
||||
dialog?.show()
|
||||
|
|
@ -56,6 +56,7 @@ class BasicCardManagerDelegate(private val activity: FragmentActivity, private v
|
|||
}
|
||||
|
||||
override fun closeNfcPopup() {
|
||||
task = null
|
||||
activity.runOnUiThread {
|
||||
dialog?.dismiss()
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import android.nfc.tech.IsoDep
|
|||
import com.tangem.CardReader
|
||||
import com.tangem.Log
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.apdu.CommandApdu
|
||||
import com.tangem.common.apdu.ResponseApdu
|
||||
import com.tangem.tasks.TaskError
|
||||
|
||||
|
|
@ -18,7 +19,6 @@ class NfcReader : CardReader {
|
|||
}
|
||||
}
|
||||
override var readingActive = false
|
||||
var startSession = false
|
||||
var readingCancelled = false
|
||||
set(value) {
|
||||
if (value) readingActive = false
|
||||
|
|
@ -33,9 +33,8 @@ class NfcReader : CardReader {
|
|||
readingCancelled = false
|
||||
}
|
||||
|
||||
override fun sendApdu(apduSerialized: ByteArray, callback: (response: CompletionResult<ResponseApdu>) -> Unit) {
|
||||
data = apduSerialized
|
||||
// readingActive = true
|
||||
override fun transceiveApdu(apdu: CommandApdu, callback: (response: CompletionResult<ResponseApdu>) -> Unit) {
|
||||
data = apdu.apduData
|
||||
this.callback = callback
|
||||
if (isoDep != null) {
|
||||
try {
|
||||
|
|
@ -61,18 +60,12 @@ class NfcReader : CardReader {
|
|||
}
|
||||
|
||||
fun onTagDiscovered(tag: Tag?) {
|
||||
// if (readingActive) {
|
||||
// if (startSession) {
|
||||
// connect()
|
||||
// startSession = false
|
||||
// }
|
||||
isoDep = IsoDep.get(tag)
|
||||
transceiveData()
|
||||
}
|
||||
|
||||
|
||||
private fun connect() {
|
||||
// val timeout = isoDep?.timeout
|
||||
isoDep?.connect()
|
||||
isoDep?.close()
|
||||
isoDep?.connect()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
android:layout_width="400dp"
|
||||
android:layout_height="250dp"
|
||||
android:gravity="center_vertical|center_horizontal"
|
||||
tools:ignore="contentDescription">
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_behavior="@string/bottom_sheet_behavior">
|
||||
|
||||
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
<include
|
||||
layout="@layout/layout_touch_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="300dp"
|
||||
android:layout_height="250dp"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue