commit f1d504e6bba93697091a11bd0a44cc810c4787c3
parent b1d1144e11ac869257ddf863abff2bc4494581f7
Author: Iván Ávalos <avalos@disroot.org>
Date: Wed, 21 May 2025 19:04:54 +0200
[wallet] fix NFC from Android to Android and clear p2p URI
bug 0009986
bug 0009985
Diffstat:
7 files changed, 65 insertions(+), 14 deletions(-)
diff --git a/cashier/src/main/java/net/taler/cashier/MainActivity.kt b/cashier/src/main/java/net/taler/cashier/MainActivity.kt
@@ -44,6 +44,8 @@ class MainActivity : AppCompatActivity() {
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
nav = navHostFragment.navController
+
+ TalerNfcService.startService(this)
}
override fun onStart() {
@@ -63,6 +65,11 @@ class MainActivity : AppCompatActivity() {
TalerNfcService.unsetDefaultHandler(this)
}
+ override fun onDestroy() {
+ super.onDestroy()
+ TalerNfcService.stopService(this)
+ }
+
@Deprecated("Deprecated in Java")
override fun onBackPressed() {
if (!configManager.hasConfig() && nav.currentDestination?.id == R.id.configFragment) {
diff --git a/merchant-terminal/src/main/java/net/taler/merchantpos/MainActivity.kt b/merchant-terminal/src/main/java/net/taler/merchantpos/MainActivity.kt
@@ -58,6 +58,8 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener {
ui = ActivityMainBinding.inflate(layoutInflater)
setContentView(ui.root)
+ TalerNfcService.startService(this)
+
model.paymentManager.payment.observe(this) { payment ->
payment?.talerPayUri?.let {
TalerNfcService.setUri(this, it)
@@ -109,6 +111,11 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener {
TalerNfcService.unsetDefaultHandler(this)
}
+ override fun onDestroy() {
+ super.onDestroy()
+ TalerNfcService.stopService(this)
+ }
+
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.nav_order -> nav.navigate(R.id.action_global_order)
diff --git a/taler-kotlin-android/src/main/java/net/taler/lib/android/TalerNfcService.kt b/taler-kotlin-android/src/main/java/net/taler/lib/android/TalerNfcService.kt
@@ -18,9 +18,11 @@ package net.taler.lib.android
import android.app.Activity
import android.app.Service
+import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.content.IntentFilter
import android.nfc.NdefMessage
import android.nfc.NdefRecord
import android.nfc.NfcAdapter.getDefaultAdapter
@@ -28,6 +30,7 @@ import android.nfc.cardemulation.CardEmulation
import android.nfc.cardemulation.HostApduService
import android.os.Bundle
import android.util.Log
+import androidx.localbroadcastmanager.content.LocalBroadcastManager
import java.math.BigInteger
class TalerNfcService : HostApduService() {
@@ -52,11 +55,14 @@ class TalerNfcService : HostApduService() {
private var readCapabilityContainerCheck = false
- override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- intent?.getStringExtra("uri")?.let { uri = it }
-
- Log.d(TAG, "onStartCommand() | URI: $uri")
+ private val broadcastReceiver = object: BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ intent?.getStringExtra("uri").let { uri = it }
+ Log.d(TAG, "onReceive() | URI: $uri")
+ }
+ }
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return Service.START_STICKY
}
@@ -201,14 +207,24 @@ class TalerNfcService : HostApduService() {
return fillByteArrayToFixedDimension(filledArray, fixedSize)
}
+ override fun onCreate() {
+ super.onCreate()
+ LocalBroadcastManager.getInstance(this).registerReceiver(
+ broadcastReceiver,
+ IntentFilter(SET_URI_INTENT),
+ )
+ }
+
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy() NFC service")
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver)
uri = null
}
companion object {
private const val TAG = "taler-wallet-hce"
+ const val SET_URI_INTENT = "taler-wallet-set-url"
private val APDU_SELECT = byteArrayOf(
0x00.toByte(), // CLA - Class - Class of instruction
@@ -245,14 +261,14 @@ class TalerNfcService : HostApduService() {
)
private val READ_CAPABILITY_CONTAINER_RESPONSE = byteArrayOf(
- 0x00.toByte(), 0x11.toByte(), // CCLEN length of the CC file
+ 0x00.toByte(), 0x0F.toByte(), // CCLEN length of the CC file
0x20.toByte(), // Mapping Version 2.0
- 0xFF.toByte(), 0xFF.toByte(), // MLe maximum
- 0xFF.toByte(), 0xFF.toByte(), // MLc maximum
+ 0x00.toByte(), 0x3B.toByte(), // MLe maximum
+ 0x00.toByte(), 0x34.toByte(), // MLc maximum
0x04.toByte(), // T field of the NDEF File Control TLV
0x06.toByte(), // L field of the NDEF File Control TLV
0xE1.toByte(), 0x04.toByte(), // File Identifier of NDEF file
- 0xFF.toByte(), 0xFE.toByte(), // Maximum NDEF file size of 65534 bytes
+ 0x00.toByte(), 0xFE.toByte(), // Maximum NDEF file size of 65534 bytes
0x00.toByte(), // Read access without any security
0xFF.toByte(), // Write access without any security
0x90.toByte(), 0x00.toByte(), // A_OKAY
@@ -318,17 +334,30 @@ class TalerNfcService : HostApduService() {
emulation.unsetPreferredService(activity)
}
+ fun startService(activity: Activity) {
+ val intent = Intent(activity, TalerNfcService::class.java)
+ activity.startService(intent)
+ }
+
+ fun stopService(activity: Activity) {
+ val intent = Intent(activity, TalerNfcService::class.java)
+ activity.stopService(intent)
+ }
+
fun setUri(activity: Activity, uri: String) {
if (!hasNfc(activity)) return
- val intent = Intent(activity, TalerNfcService::class.java)
+ val broadcastManager = LocalBroadcastManager.getInstance(activity)
+ val intent = Intent(SET_URI_INTENT)
intent.putExtra("uri", uri)
- activity.startService(intent)
+ broadcastManager.sendBroadcast(intent)
}
fun clearUri(activity: Activity) {
if (!hasNfc(activity)) return
- val intent = Intent(activity, TalerNfcService::class.java)
- activity.stopService(intent)
+ val broadcastManager = LocalBroadcastManager.getInstance(activity)
+ val intent = Intent(SET_URI_INTENT)
+ intent.putExtra("uri", null as String?)
+ broadcastManager.sendBroadcast(intent)
}
}
}
\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/MainActivity.kt b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
@@ -78,6 +78,8 @@ class MainActivity : AppCompatActivity(), OnPreferenceStartFragmentCallback {
setContentView(ui.root)
setupInsets()
+ TalerNfcService.startService(this)
+
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
nav = navHostFragment.navController
@@ -263,6 +265,7 @@ class MainActivity : AppCompatActivity(), OnPreferenceStartFragmentCallback {
override fun onDestroy() {
super.onDestroy()
+ TalerNfcService.stopService(this)
TalerNfcService.clearUri(this)
model.stopWallet()
}
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
@@ -61,6 +61,11 @@ abstract class TransactionDetailFragment : Fragment() {
}
}
+ override fun onDestroy() {
+ super.onDestroy()
+ transactionManager.selectTransaction(null)
+ }
+
private fun dialogTitle(t: TransactionAction): Int = when (t) {
Delete -> R.string.transactions_delete_dialog_title
Abort -> R.string.transactions_abort_dialog_title
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
@@ -191,7 +191,7 @@ class TransactionManager(
} ?: Log.d(TAG, "Error updating selected transaction $id")
}
- fun selectTransaction(tx: Transaction) = scope.launch {
+ fun selectTransaction(tx: Transaction?) = scope.launch {
mSelectedTransaction.value = tx
}
diff --git a/wallet/src/main/res/xml/apduservice.xml b/wallet/src/main/res/xml/apduservice.xml
@@ -18,7 +18,7 @@
android:description="@string/host_apdu_service_desc"
android:requireDeviceUnlock="true">
<aid-group
- android:category="other"
+ android:category="payment"
android:description="@string/host_apdu_service_desc">
<aid-filter android:name="F00054414C4552" />
<aid-filter android:name="D2760000850101"/>