Implement reading payload from NfcA tags, replace intent/characteristic value with that

This commit is contained in:
Kumi 2024-01-11 10:14:42 +01:00
parent 60d6865ede
commit dcdbb3a275

View file

@ -17,6 +17,8 @@ import android.content.pm.PackageManager
import android.nfc.NfcAdapter import android.nfc.NfcAdapter
import android.nfc.NfcManager import android.nfc.NfcManager
import android.nfc.Tag import android.nfc.Tag
import android.nfc.TagLostException
import android.nfc.tech.NfcA
import android.os.Bundle import android.os.Bundle
import android.os.ParcelUuid import android.os.ParcelUuid
import android.util.Log import android.util.Log
@ -35,6 +37,8 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import systems.kumi.simplerfiddemo.ui.theme.SimpleRFIDDemoTheme import systems.kumi.simplerfiddemo.ui.theme.SimpleRFIDDemoTheme
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.util.UUID import java.util.UUID
@ -61,6 +65,26 @@ class MainActivity : ComponentActivity() {
val manager = getSystemService(Context.NFC_SERVICE) as NfcManager; val manager = getSystemService(Context.NFC_SERVICE) as NfcManager;
nfcAdapter = manager.defaultAdapter; nfcAdapter = manager.defaultAdapter;
// Get required permissions
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_ADVERTISE,
Manifest.permission.NFC),
1
)
}
if (nfcAdapter != null && nfcAdapter.isEnabled) { if (nfcAdapter != null && nfcAdapter.isEnabled) {
// NFC is available // NFC is available
@ -80,7 +104,7 @@ class MainActivity : ComponentActivity() {
) { ) {
Column(modifier = Modifier.padding(16.dp)) { Column(modifier = Modifier.padding(16.dp)) {
Status() Status()
Button(onClick = { emitIntent("sample-id") }) { Button(onClick = { emitIntent("sample-id", "sample-content") }) {
Text(text = "Emit sample Intent") Text(text = "Emit sample Intent")
} }
} }
@ -224,45 +248,72 @@ class MainActivity : ComponentActivity() {
return String(hexChars) return String(hexChars)
} }
fun emitIntent(id: String) { @SuppressLint("MissingPermission")
fun emitIntent(id: String, content: String? = null) {
Log.i("BLE", "Setting characteristic and emitting intent: $id") Log.i("BLE", "Setting characteristic and emitting intent: $id")
characteristic.value = id.toByteArray(Charsets.UTF_8) if (content != null) {
synchronized(connectedDevices) { characteristic.value = content.toByteArray(Charsets.UTF_8)
for (device in connectedDevices) { synchronized(connectedDevices) {
if (ActivityCompat.checkSelfPermission( for (device in connectedDevices) {
this, gattServer.notifyCharacteristicChanged(device, characteristic, false)
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_ADVERTISE
),
1
)
return
} }
gattServer.notifyCharacteristicChanged(device, characteristic, false) }
val intent = Intent("systems.kumi.simplerfiddemo.NEW_TAG")
intent.putExtra("data", content)
sendBroadcast(intent)
}
}
fun readFromTag(tag: Tag): String? {
NfcA.get(tag)?.use { nfcA ->
try {
nfcA.connect()
val bufferSize = 256
val result = ByteArray(bufferSize)
for (block in 4 until 4 + (bufferSize / 4)) {
val command = byteArrayOf(0x30, block.toByte()) // READ command 0x30 for ISO/IEC 14443, and block number
val response = nfcA.transceive(command)
val index = (block - 4) * 4
if (index < result.size) {
val length = Math.min(response.size, result.size - index)
System.arraycopy(response, 0, result, index, length)
}
if (response.indexOf(0x00) != -1) {
break
}
}
// Assuming the data is encoded in UTF-8 and zero terminated
val dataString = result.toString(StandardCharsets.UTF_8).split("\u0000")[0]
return dataString
} catch (e: IOException) {
Log.e("NFC", "IOException while reading tag", e)
} catch (e: TagLostException) {
Log.e("NFC", "TagLostException while reading tag", e)
} }
} }
return null
val intent = Intent("systems.kumi.simplerfiddemo.NEW_TAG")
intent.putExtra("data", id)
sendBroadcast(intent)
} }
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
fun onNewTag(tag: Tag) { fun onNewTag(tag: Tag) {
val tag_id = toHexString(tag.id) val tag_id = toHexString(tag.id)
Log.d("NFC", "New tag detected: ${tag_id}") Log.d("NFC", "New tag detected: ${tag_id}")
emitIntent(tag_id) val tag_content = readFromTag(tag)
Log.d("NFC", "Tag content: ${tag_content}")
emitIntent(tag_id, tag_content)
setContent() { setContent() {
SimpleRFIDDemoTheme { SimpleRFIDDemoTheme {
@ -271,9 +322,9 @@ class MainActivity : ComponentActivity() {
color = MaterialTheme.colorScheme.background color = MaterialTheme.colorScheme.background
) { ) {
Column(modifier = Modifier.padding(16.dp)) { Column(modifier = Modifier.padding(16.dp)) {
Status(tag_id) Status(tag_id, tag_content)
Button(onClick = { emitIntent("sample-id") }) { Button(onClick = { emitIntent(tag_id, tag_content) }) {
Text(text = "Emit sample Intent") Text(text = "Emit Intent")
} }
} }
} }
@ -283,9 +334,9 @@ class MainActivity : ComponentActivity() {
} }
@Composable @Composable
fun Status(id: String? = null) { fun Status(id: String? = null, content: String? = null) {
Text( Text(
text = "Status: ${if (id != null) "Tag detected: $id" else "Waiting for tag..."}", text = "Status: ${if (id != null) "Tag detected.\nID: $id\nContent: $content" else "Waiting for tag..."}",
modifier = Modifier modifier = Modifier
) )
} }