From 8ee3bf8aacd5b3f86c35f5191786882a659c900b Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 25 Feb 2020 17:00:28 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../src/main/java/com/tangem/CardManager.kt | 2 +- .../tangem/commands/ReadUserDataCommand.kt | 8 +- .../main/java/com/tangem/common/tlv/TlvTag.kt | 2 +- tangem-demo/src/main/AndroidManifest.xml | 27 ++ .../com/tangem/tangemtest/MainActivity.kt | 7 +- .../tangem/tangemtest/TestUserDataActivity.kt | 180 +++++++++++++ .../src/main/res/layout/a_test_user_data.xml | 238 ++++++++++++++++++ .../src/main/res/layout/activity_main.xml | 171 +++++++------ .../src/main/res/layout/m_delimiter_h.xml | 7 + tangem-demo/src/main/res/values/colors.xml | 2 + tangem-demo/src/main/res/values/dimens.xml | 6 + 11 files changed, 561 insertions(+), 89 deletions(-) create mode 100644 tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt create mode 100644 tangem-demo/src/main/res/layout/a_test_user_data.xml create mode 100644 tangem-demo/src/main/res/layout/m_delimiter_h.xml create mode 100644 tangem-demo/src/main/res/values/dimens.xml diff --git a/tangem-core/src/main/java/com/tangem/CardManager.kt b/tangem-core/src/main/java/com/tangem/CardManager.kt index b679c726ce..99ddc6ce35 100644 --- a/tangem-core/src/main/java/com/tangem/CardManager.kt +++ b/tangem-core/src/main/java/com/tangem/CardManager.kt @@ -191,7 +191,7 @@ class CardManager( */ fun writeUserData( cardId: String, - userData: ByteArray, + userData: ByteArray? = null, userProtectedData: ByteArray? = null, userCounter: Int? = null, userProtectedCounter: Int? = null, 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 ae301c2230..3628d9cad7 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadUserDataCommand.kt @@ -67,10 +67,10 @@ class ReadUserDataCommand: CommandSerializer() { val mapper = TlvMapper(tlvData) ReadUserDataResponse( cardId = mapper.map(TlvTag.CardId), - userData = mapper.map(TlvTag.IssuerData), - userProtectedData = mapper.map(TlvTag.IssuerDataSignature), - userCounter = mapper.map(TlvTag.IssuerDataCounter), - userProtectedCounter = mapper.map(TlvTag.IssuerDataCounter) + userData = mapper.map(TlvTag.UserData), + userProtectedData = mapper.map(TlvTag.UserProtectedData), + userCounter = mapper.map(TlvTag.UserCounter), + userProtectedCounter = mapper.map(TlvTag.UserProtectedCounter) ) } catch (exception: Exception) { throw TaskError.SerializeCommandError() diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt index 43732307e6..d37500e221 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt @@ -125,7 +125,7 @@ enum class TlvTag(val code: Int) { MaxSignatures, PauseBeforePin2, RemainingSignatures, SignedHashes, Health, TokenDecimal, Offset, Size -> TlvValueType.Uint16 - UserCounter, IssuerDataCounter -> TlvValueType.Uint32 + UserCounter, UserProtectedCounter, IssuerDataCounter -> TlvValueType.Uint32 IsActivated, TerminalIsLinked -> TlvValueType.BoolValue ManufactureDateTime -> TlvValueType.DateTime ProductMask -> TlvValueType.ProductMask diff --git a/tangem-demo/src/main/AndroidManifest.xml b/tangem-demo/src/main/AndroidManifest.xml index 2235a4e852..f90fa6c597 100644 --- a/tangem-demo/src/main/AndroidManifest.xml +++ b/tangem-demo/src/main/AndroidManifest.xml @@ -16,6 +16,7 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> + @@ -46,6 +47,32 @@ android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" /> + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/MainActivity.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/MainActivity.kt index 967c62c688..01207d703d 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/MainActivity.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/MainActivity.kt @@ -1,13 +1,9 @@ package com.tangem.tangemtest +import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.tangem.CardManager -import com.tangem.common.extensions.hexToBytes -import com.tangem.common.extensions.toByteArray -import com.tangem.common.extensions.toHexString -import com.tangem.crypto.CryptoUtils -import com.tangem.crypto.sign import com.tangem.tangem_sdk_new.extensions.init import com.tangem.tasks.ScanEvent import com.tangem.tasks.TaskError @@ -154,6 +150,7 @@ class MainActivity : AppCompatActivity() { } } } + btn_read_write_user_data?.setOnClickListener { startActivity(Intent(this, TestUserDataActivity::class.java)) } } private fun createSampleHashes(): Array { diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt new file mode 100644 index 0000000000..2c31306bba --- /dev/null +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/TestUserDataActivity.kt @@ -0,0 +1,180 @@ +package com.tangem.tangemtest + +import android.os.Bundle +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.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.a_test_user_data.* +import java.nio.charset.StandardCharsets + +/** +[REDACTED_AUTHOR] + */ +class TestUserDataActivity: AppCompatActivity() { + + private lateinit var cardManager: CardManager + private lateinit var writeOptions: WriteOptions + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.a_test_user_data) + + init() + initWriteOptions() + } + + private fun init() { + cardManager = CardManager.init(this) + + btn_scan?.setOnClickListener { _ -> + cardManager.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 + } + } + } + } + + btn_write.setOnClickListener { + if (writeOptions.cardId == null) return@setOnClickListener + + cardManager.writeUserData( + writeOptions.cardId !!, + writeOptions.userData, + writeOptions.userProtectedData, + writeOptions.userCounter, + 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" + } + } + } + } + } + + btn_read.setOnClickListener { + if (writeOptions.cardId == null) return@setOnClickListener + + cardManager.readUserData(writeOptions.cardId !!) { + when (it) { + is TaskEvent.Completion -> handleError(tv_read_result, it.error) + is TaskEvent.Event -> { + 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 + + 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() + } + + } + } + } + } + } + + private fun handleError(tv: TextView, error: TaskError?) { + val er = error ?: return + if (er is TaskError.UserCancelled) return + + runOnUiThread { tv.text = er::class.simpleName } + } + + private fun initWriteOptions() { + writeOptions = WriteOptions() + + chb_with_ud.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateData(buttonView) } + chb_with_ud_protected.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateProtectedData(buttonView) } + chb_with_counter.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateCounter(buttonView) } + chb_with_protected_counter.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updateProtectedCounter(buttonView) } + chb_with_pin2.setOnCheckedChangeListener { buttonView, isChecked -> writeOptions.updatePin2(buttonView) } + } + + private fun showReadWriteSection(show: Boolean) { + val state = if (show) View.VISIBLE else View.GONE + cl_read_write.visibility = state + } +} + +class WriteOptions { + var cardId: String? = null + var userData: ByteArray? = null + var userProtectedData: ByteArray? = null + var userCounter: Int? = null + var userProtectedCounter: Int? = null + var pin2: String? = null + + fun updateData(chbx: CompoundButton) { + val value = "simple user data".toByteArray() + userData = if (chbx.isChecked) value else null + } + + fun updateProtectedData(chbx: CompoundButton) { + val value = "protected user data".toByteArray() + userProtectedData = if (chbx.isChecked) value else null + } + + fun updateCounter(chbx: CompoundButton) { + val value = if (userCounter == null) 0 else userCounter !! + 1 + userCounter = if (chbx.isChecked) value else null + } + + fun updateProtectedCounter(chbx: CompoundButton) { + val value = if (userProtectedCounter == null) 0 else userProtectedCounter !! + 1 + userProtectedCounter = if (chbx.isChecked) value else null + } + + fun updatePin2(chbx: CompoundButton) { + val value = CardEnvironment.DEFAULT_PIN2 + pin2 = if (chbx.isChecked) value else null + } +} \ No newline at end of file diff --git a/tangem-demo/src/main/res/layout/a_test_user_data.xml b/tangem-demo/src/main/res/layout/a_test_user_data.xml new file mode 100644 index 0000000000..261a6efd64 --- /dev/null +++ b/tangem-demo/src/main/res/layout/a_test_user_data.xml @@ -0,0 +1,238 @@ + + + +