Updated on 2026-08-14
This commit is contained in:
parent
0645cffc25
commit
72a2623faa
13 changed files with 287 additions and 2 deletions
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
|
|
@ -13,6 +13,8 @@
|
|||
<option value="$PROJECT_DIR$/tangem-card" />
|
||||
<option value="$PROJECT_DIR$/tangem-card-new" />
|
||||
<option value="$PROJECT_DIR$/tangem-sdk" />
|
||||
<option value="$PROJECT_DIR$/tangem-sdk-new" />
|
||||
<option value="$PROJECT_DIR$/tangemtest" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
|
|
|
|||
|
|
@ -23,4 +23,4 @@ allprojects {
|
|||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
include ':app', ':tangem-sdk', ':server-android', ':tangem-card', ':tangem-card-new'
|
||||
include ':app', ':tangem-sdk', ':server-android', ':tangem-card', ':tangem-card-new', ':tangem-sdk-new', ':tangemtest'
|
||||
|
|
|
|||
1
tangem-sdk-new/.gitignore
vendored
Normal file
1
tangem-sdk-new/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
47
tangem-sdk-new/build.gradle
Normal file
47
tangem-sdk-new/build.gradle
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.0"
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles 'consumer-rules.pro'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':tangem-card-new')
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.1.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
|
||||
implementation "androidx.lifecycle:lifecycle-runtime:2.1.0"
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:2.1.0"
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
}
|
||||
0
tangem-sdk-new/consumer-rules.pro
Normal file
0
tangem-sdk-new/consumer-rules.pro
Normal file
21
tangem-sdk-new/proguard-rules.pro
vendored
Normal file
21
tangem-sdk-new/proguard-rules.pro
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
5
tangem-sdk-new/src/main/AndroidManifest.xml
Normal file
5
tangem-sdk-new/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.tangem.tangem_sdk_new" >
|
||||
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.tangem.tangem_sdk_new
|
||||
|
||||
import android.app.AlertDialog
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.tangem.CardError
|
||||
import com.tangem.CardManagerDelegate
|
||||
|
||||
class BasicCardManagerDelegate(val activity: FragmentActivity) : CardManagerDelegate {
|
||||
|
||||
private var dialog: AlertDialog? = null
|
||||
|
||||
override fun showSecurityDelay(seconds: Int) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun hideSecurityDelay() {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun requestPin(success: () -> String, error: (cardError: CardError) -> CardError) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun openNfcPopup() {
|
||||
|
||||
dialog = AlertDialog.Builder(activity)
|
||||
.setTitle("NFC reader mode")
|
||||
.create()
|
||||
dialog?.show()
|
||||
|
||||
}
|
||||
|
||||
override fun closeNfcPopup() {
|
||||
dialog?.dismiss()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.tangem_sdk_new
|
||||
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
|
||||
|
||||
class NfcLifecycleObserver(private var nfcManager: NfcManager) : DefaultLifecycleObserver {
|
||||
|
||||
override fun onResume(owner: LifecycleOwner) {
|
||||
super.onResume(owner)
|
||||
nfcManager.onResume()
|
||||
}
|
||||
|
||||
override fun onPause(owner: LifecycleOwner) {
|
||||
super.onPause(owner)
|
||||
nfcManager.onPause()
|
||||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
super.onStop(owner)
|
||||
nfcManager.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
super.onDestroy(owner)
|
||||
nfcManager.onDestroy()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package com.tangem.tangem_sdk_new
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.nfc.NfcAdapter
|
||||
import android.nfc.Tag
|
||||
import android.nfc.tech.IsoDep
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
|
||||
class NfcManager(private val reader: NfcReader) : NfcAdapter.ReaderCallback {
|
||||
|
||||
|
||||
private var activity: FragmentActivity? = null
|
||||
private var nfcAdapter: NfcAdapter? = null
|
||||
private var readerCallback: NfcAdapter.ReaderCallback? = null
|
||||
// private var nfcEnableDialog: NfcEnableDialog? = null
|
||||
|
||||
|
||||
fun setCurrentActivity(activity: FragmentActivity, readerCallback: NfcAdapter.ReaderCallback) {
|
||||
this.activity = activity
|
||||
nfcAdapter = NfcAdapter.getDefaultAdapter(activity)
|
||||
this.readerCallback = readerCallback
|
||||
}
|
||||
|
||||
private val mBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val action = intent.action ?: return
|
||||
if (action == NfcAdapter.ACTION_ADAPTER_STATE_CHANGED) {
|
||||
if (intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, NfcAdapter.STATE_ON) == NfcAdapter.STATE_ON)
|
||||
enableReaderMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTagDiscovered(tag: Tag?) {
|
||||
reader.isoDep = IsoDep.get(tag)
|
||||
reader.onTagDiscovered(tag)
|
||||
if (!reader.readingActive) ignoreTag(tag)
|
||||
}
|
||||
|
||||
|
||||
fun onResume() {
|
||||
val filter = IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)
|
||||
activity?.registerReceiver(mBroadcastReceiver, filter)
|
||||
|
||||
if (nfcAdapter == null || nfcAdapter?.isEnabled != true)
|
||||
// showNFCEnableDialog()
|
||||
else
|
||||
enableReaderMode()
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
activity?.unregisterReceiver(mBroadcastReceiver)
|
||||
disableReaderMode()
|
||||
}
|
||||
|
||||
fun onStop() {
|
||||
// nfcEnableDialog?.dismiss()
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
activity = null
|
||||
nfcAdapter = null
|
||||
readerCallback = null
|
||||
}
|
||||
|
||||
// private fun showNFCEnableDialog() {
|
||||
// nfcEnableDialog = NfcEnableDialog()
|
||||
// activity?.supportFragmentManager?.let { nfcEnableDialog?.show(it, NfcEnableDialog.TAG) }
|
||||
// }
|
||||
|
||||
private fun enableReaderMode() {
|
||||
val options = Bundle()
|
||||
nfcAdapter?.enableReaderMode(activity, readerCallback, READER_FLAGS, options)
|
||||
}
|
||||
|
||||
private fun disableReaderMode() {
|
||||
nfcAdapter?.disableReaderMode(activity)
|
||||
}
|
||||
|
||||
fun ignoreTag(tag: Tag?) {
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
nfcAdapter?.ignore(tag, 1500, null, null)
|
||||
}
|
||||
IsoDep.get(tag)?.close()
|
||||
}
|
||||
|
||||
companion object {
|
||||
// reader mode flags: listen for type A (not B), skipping ndef check
|
||||
private const val READER_FLAGS = NfcAdapter.FLAG_READER_NFC_A or
|
||||
NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK or
|
||||
NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tangem.tangem_sdk_new
|
||||
|
||||
import android.nfc.Tag
|
||||
import android.nfc.tech.IsoDep
|
||||
import com.tangem.CardReader
|
||||
import com.tangem.data.ResponseApdu
|
||||
|
||||
class NfcReader() : CardReader {
|
||||
|
||||
var isoDep: IsoDep? = null
|
||||
var readingActive = false
|
||||
|
||||
var data: ByteArray? = null
|
||||
var callback: ((responseApdu: ResponseApdu) -> Unit)? = null
|
||||
|
||||
override fun sendApdu(apduSerialized: ByteArray, callback: (responseApdu: ResponseApdu) -> Unit) {
|
||||
data = apduSerialized
|
||||
this.callback = callback
|
||||
}
|
||||
|
||||
fun onTagDiscovered(tag: Tag?) {
|
||||
if (data != null) {
|
||||
readingActive = true
|
||||
connect()
|
||||
val rawResponse = isoDep?.transceive(data)
|
||||
if (rawResponse != null) {
|
||||
readingActive = false
|
||||
data = null
|
||||
}
|
||||
rawResponse?.let { callback?.invoke(ResponseApdu(it)) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun connect() {
|
||||
val timeout = isoDep?.timeout
|
||||
isoDep?.connect()
|
||||
isoDep?.close()
|
||||
isoDep?.connect()
|
||||
isoDep?.timeout = timeout ?: 0
|
||||
}
|
||||
|
||||
}
|
||||
3
tangem-sdk-new/src/main/res/values/strings.xml
Normal file
3
tangem-sdk-new/src/main/res/values/strings.xml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">Tangem Sdk</string>
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue