Skip to content

Commit

Permalink
Add detection of UUID to Bluetooth scans
Browse files Browse the repository at this point in the history
  • Loading branch information
AbandonedCart committed Sep 12, 2023
1 parent 9b1fe0b commit 30950b9
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 68 deletions.
121 changes: 62 additions & 59 deletions app/src/main/java/com/hiddenramblings/tagmo/bluetooth/GattService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,53 +46,6 @@ import java.nio.charset.Charset
import java.util.Objects
import java.util.UUID

/**
* Service for managing connection and data communication with a GATT server
* hosted on a given Bluetooth LE device based on core/java/android/bluetooth
*
* Android Bluetooth Low Energy Status Codes
*
* 0 0x00 BLE_HCI_STATUS_CODE_SUCCESS
* 1 0x01 BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND
* 2 0x02 BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER
* 5 0x05 BLE_HCI_AUTHENTICATION_FAILURE
* 6 0x06 BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING
* 7 0x07 BLE_HCI_MEMORY_CAPACITY_EXCEEDED
* 8 0x08 BLE_HCI_CONNECTION_TIMEOUT
* 12 0x0C BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED
* 18 0x12 BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS
* 19 0x13 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION
* 20 0x14 BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES
* 21 0x15 BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF
* 22 0x16 BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION
* 26 0x1A BLE_HCI_UNSUPPORTED_REMOTE_FEATURE
* 30 0x1E BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS
* 31 0x1F BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR
* 34 0x22 BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT
* 36 0x24 BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED
* 40 0x28 BLE_HCI_INSTANT_PASSED
* 41 0x29 BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED
* 42 0x2A BLE_HCI_DIFFERENT_TRANSACTION_COLLISION
* 58 0x3A BLE_HCI_CONTROLLER_BUSY
* 59 0x3B BLE_HCI_CONN_INTERVAL_UNACCEPTABLE
* 60 0x3C BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT
* 61 0x3D BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE
* 62 0x3E BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED
* 128 0x80 GATT_NO_RESSOURCES
* 129 0x81 GATT_INTERNAL_ERROR
* 130 0x82 GATT_WRONG_STATE
* 131 0x83 GATT_DB_FULL
* 132 0x84 GATT_BUSY
* 133 0x85 GATT_ERROR
* 135 0x87 GATT_ILLEGAL_PARAMETER
* 137 0x89 GATT_AUTH_FAIL
* 138 0x8A GATT_MORE
* 139 0x8B GATT_INVALID_CFG
* 140 0x8C GATT_SERVICE_STARTED
* 141 0x8D GATT_ENCRYPED_NO_MITM
* 142 0x8E GATT_NOT_ENCRYPTED
**/

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
@SuppressLint("MissingPermission")
class GattService : Service() {
Expand Down Expand Up @@ -703,9 +656,11 @@ class GattService : Service() {
throw IllegalAccessException(getString(R.string.fail_bluetooth_adapter))
}
val services = supportedGattServices
if (services.isNullOrEmpty()) throw UnsupportedOperationException(
getString(R.string.gatt_write_failed, serviceType.logTag)
)
if (services.isNullOrEmpty()) {
throw UnsupportedOperationException(
getString(R.string.gatt_services_null, serviceType.logTag)
)
}
for (customService in services) {
when (customService.uuid) {
Nordic.NUS -> {
Expand All @@ -724,6 +679,34 @@ class GattService : Service() {
setCharacteristicRX()
}

fun setOmllboServicesUUID() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
throw IllegalAccessException(getString(R.string.fail_bluetooth_adapter))
}
val services = supportedGattServices
if (services.isNullOrEmpty()) {
throw UnsupportedOperationException(
getString(R.string.gatt_services_null, serviceType.logTag)
)
}
for (customService in services) {
when (customService.uuid) {
Nordic.NUS -> {
omllboInterface = false
break
}
Nordic.OmllboNUS -> {
omllboInterface = true
break
}
else -> {
continue
}
}
}
setCharacteristicRX()
}

private fun getCharacteristicRX(mCustomService: BluetoothGattService): BluetoothGattCharacteristic {
var mReadCharacteristic = mCustomService.getCharacteristic(GattRX)
if (mBluetoothGatt?.readCharacteristic(mReadCharacteristic) != true) run breaking@{
Expand All @@ -748,9 +731,11 @@ class GattService : Service() {
val mCustomService = mBluetoothGatt!!.getService(GattNUS)
if (null == mCustomService) {
val services = supportedGattServices
if (services.isNullOrEmpty()) throw UnsupportedOperationException(
getString(R.string.gatt_write_failed, serviceType.logTag)
)
if (services.isNullOrEmpty()) {
throw UnsupportedOperationException(
getString(R.string.gatt_services_null, serviceType.logTag)
)
}
for (service in services) {
Debug.verbose(this.javaClass, "GattReadService: ${service.uuid}")
mCharacteristicRX = getCharacteristicRX(service)
Expand Down Expand Up @@ -786,9 +771,11 @@ class GattService : Service() {
val mCustomService = mBluetoothGatt!!.getService(GattNUS)
if (null == mCustomService) {
val services = supportedGattServices
if (services.isNullOrEmpty()) throw UnsupportedOperationException(
getString(R.string.gatt_write_failed, serviceType.logTag)
)
if (services.isNullOrEmpty()) {
throw UnsupportedOperationException(
getString(R.string.gatt_services_null, serviceType.logTag)
)
}
for (customService in services) {
Debug.verbose(this.javaClass, "GattWriteService: ${customService.uuid}")
mCharacteristicTX = getCharacteristicTX(customService)
Expand Down Expand Up @@ -1298,8 +1285,24 @@ class GattService : Service() {

companion object {
private var legacyInterface = false
val GattNUS: UUID = if (legacyInterface) Nordic.LegacyNUS else Nordic.NUS
val GattTX: UUID = if (legacyInterface) Nordic.LegacyTX else Nordic.TX
val GattRX: UUID = if (legacyInterface) Nordic.LegacyRX else Nordic.RX
private var omllboInterface = false
val GattNUS: UUID = if (legacyInterface)
Nordic.LegacyNUS
else if (omllboInterface)
Nordic.OmllboNUS
else
Nordic.NUS
val GattTX: UUID = if (legacyInterface)
Nordic.LegacyTX
else if (omllboInterface)
Nordic.OmllboTX
else
Nordic.TX
val GattRX: UUID = if (legacyInterface)
Nordic.LegacyRX
else if (omllboInterface)
Nordic.OmllboRX
else
Nordic.RX
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ object Nordic {
val LegacyTX = UUID.fromString("78290002-d52e-473f-a9f4-f03da7c67dd1")
val LegacyRX = UUID.fromString("78290003-d52e-473f-a9f4-f03da7c67dd1")

val omllboNUS: UUID = UUID.fromString("0000ff10-0000-1000-8000-00805f9b34fb")
val omllboTX: UUID = UUID.fromString("0000ff11-0000-1000-8000-00805f9b34fb")
val omllboRX: UUID = UUID.fromString("0000ff12-0000-1000-8000-00805f9b34fb")
val OmllboNUS: UUID = UUID.fromString("0000ff10-0000-1000-8000-00805f9b34fb")
val OmllboTX: UUID = UUID.fromString("0000ff11-0000-1000-8000-00805f9b34fb")
val OmllboRX: UUID = UUID.fromString("0000ff12-0000-1000-8000-00805f9b34fb")

fun UUID.isUUID(uuid: UUID): Boolean {
return this.compareTo(uuid) == 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ import org.json.JSONException
import org.json.JSONObject
import java.io.IOException
import java.text.ParseException
import java.util.UUID


@SuppressLint("NewApi")
open class GattSlotFragment : Fragment(), GattSlotAdapter.OnAmiiboClickListener, BluetoothListener {
Expand Down Expand Up @@ -129,6 +131,8 @@ open class GattSlotFragment : Fragment(), GattSlotAdapter.OnAmiiboClickListener,
LOCKED, AMIIBO, MENU, WRITE
}

val separator = System.getProperty("line.separator") ?: "\n"

private var browserActivity: BrowserActivity? = null
private val fragmentHandler = Handler(Looper.getMainLooper())

Expand Down Expand Up @@ -641,12 +645,24 @@ open class GattSlotFragment : Fragment(), GattSlotAdapter.OnAmiiboClickListener,

@SuppressLint("InflateParams")
private fun displayScanResult(
deviceDialog: AlertDialog, device: BluetoothDevice) : View {
deviceDialog: AlertDialog, device: BluetoothDevice, services: List<UUID> = listOf()) : View {
val detectedType = getDeviceType(device)
val item = this.layoutInflater.inflate(R.layout.device_bluetooth, null)
item.findViewById<TextView>(R.id.device_name).text = device.name
item.findViewById<TextView>(R.id.device_address).text =
requireActivity().getString(R.string.device_address, device.address)
if (services.isNotEmpty()) {
val serviceList = StringBuilder()
services.forEachIndexed { index, uuid ->
if (services.lastIndex == index)
serviceList.append(uuid)
else
serviceList.append(separator).append(uuid)
}
item.findViewById<TextView>(R.id.device_address).text =
requireActivity().getString(R.string.device_services, serviceList.toString())
} else {
item.findViewById<TextView>(R.id.device_address).text =
requireActivity().getString(R.string.device_address, device.address)
}

item.findViewById<Spinner>(R.id.gatt_type_spinner).apply {
onItemSelectedListener = object : OnItemSelectedListener {
Expand Down Expand Up @@ -692,6 +708,14 @@ open class GattSlotFragment : Fragment(), GattSlotAdapter.OnAmiiboClickListener,
}
}

private fun getServiceUUIDs(scanResult: ScanResult): List<UUID> {
val serviceList: MutableList<UUID> = ArrayList()
scanResult.scanRecord!!.serviceUuids.forEach {
if (!serviceList.contains(it.uuid)) serviceList.add(it.uuid)
}
return serviceList
}

@SuppressLint("MissingPermission", "NewApi")
private fun scanBluetoothServices(deviceDialog: AlertDialog) {
mBluetoothAdapter = mBluetoothAdapter
Expand All @@ -716,7 +740,7 @@ open class GattSlotFragment : Fragment(), GattSlotAdapter.OnAmiiboClickListener,
if (!devices.contains(result.device)) {
devices.add(result.device)
deviceDialog.findViewById<LinearLayout>(R.id.bluetooth_result)?.addView(
displayScanResult(deviceDialog, result.device)
displayScanResult(deviceDialog, result.device, getServiceUUIDs(result))
)
}
}
Expand All @@ -730,7 +754,7 @@ open class GattSlotFragment : Fragment(), GattSlotAdapter.OnAmiiboClickListener,
if (!devices.contains(result.device)) {
devices.add(result.device)
deviceDialog.findViewById<LinearLayout>(R.id.bluetooth_result)?.addView(
displayScanResult(deviceDialog, result.device)
displayScanResult(deviceDialog, result.device, getServiceUUIDs(result))
)
}
}
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@
<string name="shop_hardware">Shop amiibo hardware</string>
<string name="gatt_missing">No nearby GATT devices found!</string>
<string name="device_invalid">Not a valid GATT device!</string>
<string name="gatt_write_failed">%1$s write characteristic missing!</string>
<string name="gatt_services_null">%1$s services not found!</string>
<string name="xor_invalid">Empty collection can\'t be reduced</string>
<string name="connect_device">Connect device</string>
<string name="gatt_scanning">Scanning for Bluetooth GATT&#8230;</string>
Expand All @@ -341,6 +341,7 @@

<string name="paired_devices">Paired Bluetooth Devices</string>
<string name="device_address">MAC: %1$s</string>
<string name="device_services">UUID: %1$s</string>
<string name="switch_devices">Switch / disconnect device</string>

<string name="clone_random">Clone with random serial</string>
Expand Down

0 comments on commit 30950b9

Please sign in to comment.