Updated on 2026-08-14
This commit is contained in:
parent
d2e1acdee8
commit
8ee3bf8aac
11 changed files with 561 additions and 89 deletions
|
|
@ -191,7 +191,7 @@ class CardManager(
|
|||
*/
|
||||
fun writeUserData(
|
||||
cardId: String,
|
||||
userData: ByteArray,
|
||||
userData: ByteArray? = null,
|
||||
userProtectedData: ByteArray? = null,
|
||||
userCounter: Int? = null,
|
||||
userProtectedCounter: Int? = null,
|
||||
|
|
|
|||
|
|
@ -67,10 +67,10 @@ class ReadUserDataCommand: CommandSerializer<ReadUserDataResponse>() {
|
|||
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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
|
@ -46,6 +47,32 @@
|
|||
android:name="android.nfc.action.TECH_DISCOVERED"
|
||||
android:resource="@xml/nfc_tech_filter" />
|
||||
</activity>
|
||||
|
||||
<activity android:name=".TestUserDataActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data
|
||||
android:host="www.tangem.com"
|
||||
android:scheme="http" />
|
||||
<data
|
||||
android:host="www.tangem.com"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="tangem.com"
|
||||
android:scheme="http" />
|
||||
<data
|
||||
android:host="tangem.com"
|
||||
android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.nfc.action.TECH_DISCOVERED" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.nfc.action.TECH_DISCOVERED"
|
||||
android:resource="@xml/nfc_tech_filter" />
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -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<ByteArray> {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
238
tangem-demo/src/main/res/layout/a_test_user_data.xml
Normal file
238
tangem-demo/src/main/res/layout/a_test_user_data.xml
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_scan"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Scan card" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/cl_read_write"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/chb_with_ud"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="With User data" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/chb_with_ud_protected"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="With User protected data" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/chb_with_pin2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="With Pin2" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/chb_with_counter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="With User counter" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/chb_with_protected_counter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="With User protected counter" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_write"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Write user data"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_begin="205dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_write_result"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Write result"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/btn_write"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline2"
|
||||
app:layout_constraintTop_toTopOf="@+id/btn_write" />
|
||||
|
||||
<include
|
||||
android:id="@+id/m_delimiter_h"
|
||||
layout="@layout/m_delimiter_h"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/delimiter_size"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/btn_write" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_read"
|
||||
android:layout_width="170dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Read User Data"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/m_delimiter_h" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_read_result"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Read result"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/btn_read"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline2"
|
||||
app:layout_constraintTop_toTopOf="@+id/btn_read" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/btn_read"
|
||||
app:layout_constraintVertical_bias="0.0">
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_begin="156dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView6"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Card Id:"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView7"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="User data:"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView6" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView8"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="User protected data:"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView7" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView9"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="User counter:"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView8" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView10"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="User protected counter:"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView9" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_card_cid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="card id" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_data"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintStart_toStartOf="@+id/tv_card_cid"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView6"
|
||||
tools:text="data" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_protected_data"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintStart_toStartOf="@+id/tv_data"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView7"
|
||||
tools:text="protected data" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_counter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintStart_toStartOf="@+id/tv_protected_data"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_protected_data"
|
||||
tools:text="counter" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_protected_counter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintStart_toStartOf="@+id/tv_counter"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_counter"
|
||||
tools:text="protected counter" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
|
@ -1,101 +1,116 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/container"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<TextView
|
||||
android:paddingBottom="48dp"
|
||||
android:layout_marginTop="48dp"
|
||||
android:id="@+id/tv_card_cid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:layout_marginBottom="80dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"/>
|
||||
android:id="@+id/tv_card_cid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginBottom="80dp"
|
||||
android:padding="16dp"
|
||||
android:paddingBottom="48dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_scan"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Read and verify card"
|
||||
app:layout_constraintVertical_bias="0.3"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
android:id="@+id/btn_scan"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Read and verify card"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.25" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_sign"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign transaction"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_scan"
|
||||
android:enabled="false"/>
|
||||
android:id="@+id/btn_sign"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:enabled="false"
|
||||
android:text="Sign transaction"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_scan" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_read_issuer_data"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Read issuer data"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_sign"
|
||||
android:enabled="false"/>
|
||||
android:id="@+id/btn_read_issuer_data"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:enabled="false"
|
||||
android:text="Read issuer data"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_sign" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_write_issuer_data"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Write issuer data"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_read_issuer_data"
|
||||
android:enabled="false"/>
|
||||
android:id="@+id/btn_write_issuer_data"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:enabled="false"
|
||||
android:text="Write issuer data"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_read_issuer_data" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_read_issuer_extra_data"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Read issuer extra data"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_write_issuer_data"
|
||||
android:enabled="false"/>
|
||||
android:id="@+id/btn_read_issuer_extra_data"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:enabled="false"
|
||||
android:text="Read issuer extra data"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_write_issuer_data" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_purge_wallet"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Purge wallet"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_read_issuer_extra_data"
|
||||
android:enabled="false"/>
|
||||
android:id="@+id/btn_purge_wallet"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:enabled="false"
|
||||
android:text="Purge wallet"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_read_issuer_extra_data" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_create_wallet"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Create wallet"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_purge_wallet"
|
||||
android:enabled="false"/>
|
||||
android:id="@+id/btn_create_wallet"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:enabled="false"
|
||||
android:text="Create wallet"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_purge_wallet" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_read_write_user_data"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Read/Write user data"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/btn_create_wallet" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
7
tangem-demo/src/main/res/layout/m_delimiter_h.xml
Normal file
7
tangem-demo/src/main/res/layout/m_delimiter_h.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/m_delimiter_h"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/delimiter_size"
|
||||
android:background="@color/delimiter"
|
||||
android:orientation="vertical" />
|
||||
|
|
@ -3,4 +3,6 @@
|
|||
<color name="colorPrimary">#027aff</color>
|
||||
<color name="colorPrimaryDark">#027AFF</color>
|
||||
<color name="colorAccent">#027AFF</color>
|
||||
|
||||
<color name="delimiter">#000000</color>
|
||||
</resources>
|
||||
|
|
|
|||
6
tangem-demo/src/main/res/values/dimens.xml
Normal file
6
tangem-demo/src/main/res/values/dimens.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<dimen name="delimiter_size">1dp</dimen>
|
||||
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue