Skip to content

Commit

Permalink
refactor: create common ancestor class for odid scanners
Browse files Browse the repository at this point in the history
DT-2604
  • Loading branch information
matejglejtek committed Aug 29, 2023
1 parent 40df49e commit ada49b6
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 175 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,38 @@ import java.nio.ByteBuffer
import java.nio.ByteOrder

class BluetoothScanner(
private val odidPayloadStreamHandler: StreamHandler,
private val bluetoothStateHandler: StreamHandler,
) {
companion object {
const val MAX_MESSAGE_SIZE = 25
}
odidPayloadStreamHandler: StreamHandler,
private val bluetoothStateHandler: StreamHandler,
) : ODIDScanner(odidPayloadStreamHandler) {
private val TAG: String = BluetoothScanner::class.java.getSimpleName()

var isScanning = false
get() = field
set(value) {
field = value
bluetoothStateHandler.send(value)
}
var scanMode = ScanSettings.SCAN_MODE_LOW_LATENCY
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
/* OpenDroneID Bluetooth beacons identify themselves by setting the GAP AD Type to
* "Service Data - 16-bit UUID" and the value to 0xFFFA for ASTM International, ASTM Remote ID.
* https://www.bluetooth.com/specifications/assigned-numbers/ -> "Generic Access Profile"
* https://www.bluetooth.com/specifications/assigned-numbers/ -> "16-bit UUIDs"
* Vol 3, Part B, Section 2.5.1 of the Bluetooth 5.1 Core Specification
* The AD Application Code is set to 0x0D = Open Drone ID.
*/

/// OpenDroneID Bluetooth beacons identify themselves by setting the GAP AD Type to
/// "Service Data - 16-bit UUID" and the value to 0xFFFA for ASTM International, ASTM Remote ID.
/// https://www.bluetooth.com/specifications/assigned-numbers/ -> "Generic Access Profile"
/// https://www.bluetooth.com/specifications/assigned-numbers/ -> "16-bit UUIDs"
/// Vol 3, Part B, Section 2.5.1 of the Bluetooth 5.1 Core Specification
/// The AD Application Code is set to 0x0D = Open Drone ID.

private val serviceUuid = UUID.fromString("0000fffa-0000-1000-8000-00805f9b34fb")
private val serviceParcelUuid = ParcelUuid(serviceUuid)
private val odidAdCode = byteArrayOf(0x0D.toByte())

private val payloadHandler: OdidPayloadHandler = OdidPayloadHandler()

@RequiresApi(Build.VERSION_CODES.O)
fun scan() {
override fun scan() {
if (!bluetoothAdapter.isEnabled) return
val bluetoothLeScanner: BluetoothLeScanner = bluetoothAdapter.bluetoothLeScanner
val builder: ScanFilter.Builder = ScanFilter.Builder()
builder.setServiceData(serviceParcelUuid, odidAdCode)
val scanFilters: MutableList<ScanFilter> = ArrayList()
scanFilters.add(builder.build())

Log.i("bluetooth LE extended supported:", bluetoothAdapter.isLeExtendedAdvertisingSupported.toString())
Log.i("bluetooth LE coded phy supported:", bluetoothAdapter.isLeCodedPhySupported.toString())
Log.i("bluetooth multiple advertisement supported:", bluetoothAdapter.isMultipleAdvertisementSupported.toString())
Log.i("bluetooth max adv data len:", bluetoothAdapter.leMaximumAdvertisingDataLength.toString())
Log.i(TAG, "bluetooth LE extended supported: " + bluetoothAdapter.isLeExtendedAdvertisingSupported.toString())
Log.i(TAG, "bluetooth LE coded phy supported: " + bluetoothAdapter.isLeCodedPhySupported.toString())
Log.i(TAG, "bluetooth multiple advertisement supported: " + bluetoothAdapter.isMultipleAdvertisementSupported.toString())
Log.i(TAG, "bluetooth max adv data len:" + bluetoothAdapter.leMaximumAdvertisingDataLength.toString())

var scanSettings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
Expand All @@ -76,6 +67,27 @@ class BluetoothScanner(
bluetoothStateHandler.send(true)
}

override fun cancel() {
isScanning = false
if (!bluetoothAdapter.isEnabled) return
bluetoothStateHandler.send(false)
bluetoothAdapter.bluetoothLeScanner.stopScan(scanCallback)
}

@RequiresApi(Build.VERSION_CODES.O)
override fun onAdapterStateReceived() {
val rawState = bluetoothAdapter.state
val commonState = getAdapterState()
if (rawState == BluetoothAdapter.STATE_OFF || rawState == BluetoothAdapter.STATE_TURNING_OFF) {
if (bluetoothAdapter.isEnabled) bluetoothAdapter.bluetoothLeScanner.stopScan(scanCallback)
isScanning = false
} else if ((rawState == BluetoothAdapter.STATE_ON)
&& !isScanning) {
cancel()
scan()
}
}

fun setScanPriority(priority: Pigeon.ScanPriority) {
if(priority == Pigeon.ScanPriority.HIGH)
{
Expand Down Expand Up @@ -105,13 +117,6 @@ class BluetoothScanner(
return bluetoothAdapter.leMaximumAdvertisingDataLength;
}

fun cancel() {
isScanning = false
if (!bluetoothAdapter.isEnabled) return
bluetoothStateHandler.send(false)
bluetoothAdapter.bluetoothLeScanner.stopScan(scanCallback)
}

fun getAdapterState(): Int {
return when (bluetoothAdapter.state) {
BluetoothAdapter.STATE_OFF -> 4
Expand All @@ -133,7 +138,7 @@ class BluetoothScanner(
}
if (bytes.size < offset + MAX_MESSAGE_SIZE) return

val payload = payloadHandler.getPayload(
val payload = getPayload(
bytes.copyOfRange(offset.toInt(), MAX_MESSAGE_SIZE + offset.toInt()),
source,
result.device.address,
Expand All @@ -144,33 +149,17 @@ class BluetoothScanner(
odidPayloadStreamHandler.send(payload?.toList() as Any)
}

val adapterStateReceiver: BroadcastReceiver = object : BroadcastReceiver() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context?, intent: Intent?) {
val rawState = bluetoothAdapter.state
val commonState = getAdapterState()
if (rawState == BluetoothAdapter.STATE_OFF || rawState == BluetoothAdapter.STATE_TURNING_OFF) {
if (bluetoothAdapter.isEnabled) bluetoothAdapter.bluetoothLeScanner.stopScan(scanCallback)
isScanning = false
} else if ((rawState == BluetoothAdapter.STATE_ON)
&& !isScanning) {
cancel()
scan()
}
}
}

private val scanCallback: ScanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
handleODIDPayload(result, 6)
}

override fun onBatchScanResults(results: List<ScanResult?>?) {
Log.e("scanner", "Got batch scan results, unable to handle")
Log.e(TAG, "Got batch scan results, unable to handle")
}

override fun onScanFailed(errorCode: Int) {
Log.e("scanner", "Scan failed: $errorCode")
Log.e(TAG, "Scan failed: $errorCode")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package cz.dronetag.flutter_opendroneid

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent

/// Contains common functinality for ODID scanners
/// Creates [ODIDPayload] instances implementin Pigeon PayloadAPI
abstract class ODIDScanner(
val odidPayloadStreamHandler: StreamHandler
) : Pigeon.PayloadApi {

companion object {
const val MAX_MESSAGE_SIZE = 25
}

var isScanning = false
get() = field
set(value) {
field = value
}

val adapterStateReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
onAdapterStateReceived()
}
}

override fun getPayload(rawData: ByteArray, source: Pigeon.MessageSource, macAddress: String, rssi: Long, receivedTimestamp: Long): Pigeon.ODIDPayload {
val builder = Pigeon.ODIDPayload.Builder()

builder.setRawData(rawData)
builder.setReceivedTimestamp(receivedTimestamp)
builder.setMacAddress(macAddress)
builder.setSource(source)
builder.setRssi(rssi)

return builder.build()
}

abstract fun scan()

abstract fun cancel()

abstract fun onAdapterStateReceived()
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,16 @@ import java.util.List;


class WifiNaNScanner (
private val odidPayloadStreamHandler: StreamHandler,
odidPayloadStreamHandler: StreamHandler,
private val wifiStateHandler: StreamHandler,
private val wifiAwareManager: WifiAwareManager?,
private val context: Context
) {
companion object {
const val MAX_MESSAGE_SIZE = 25
}

) : ODIDScanner(odidPayloadStreamHandler) {
private val TAG: String = WifiNaNScanner::class.java.getSimpleName()

private var wifiAwareSession: WifiAwareSession? = null
private val wifiScanEnabled = true
private var wifiAwareSupported = true
var isScanning = false

private val payloadHandler: OdidPayloadHandler = OdidPayloadHandler()
private val TAG: String = WifiNaNScanner::class.java.getSimpleName()

init{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
Expand All @@ -55,14 +49,35 @@ class WifiNaNScanner (
wifiAwareSupported = true
}
}

private val myReceiver: BroadcastReceiver = object : BroadcastReceiver() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context?, intent: Intent?) {
if (wifiAwareManager!!.isAvailable) {
Log.i(TAG, "WiFi Aware became available.")
startScan()
}

override fun scan() {
if (!wifiScanEnabled) {
return
}
isScanning = true
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)) {
Log.i(TAG, "WiFi Aware is not supported.");
wifiAwareSupported = false
return;
}
wifiAwareSupported = true
context.registerReceiver(adapterStateReceiver, IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED))
startScan();
}

@RequiresApi(Build.VERSION_CODES.O)
override fun cancel() {
if (!wifiAwareSupported) return
isScanning = false;
stopScan()
}

@RequiresApi(Build.VERSION_CODES.O)
override fun onAdapterStateReceived() {
if (wifiAwareManager!!.isAvailable) {
Log.i(TAG, "WiFi Aware became available.")
startScan()
}
}

Expand Down Expand Up @@ -101,7 +116,7 @@ class WifiNaNScanner (
transportType: String?
) {
val offset = 4
val payload = payloadHandler.getPayload(
val payload = getPayload(
data.copyOfRange(offset, MAX_MESSAGE_SIZE + offset),
Pigeon.MessageSource.WIFI_NAN,
peerHash.hashCode().toString(),
Expand All @@ -122,8 +137,13 @@ class WifiNaNScanner (
}
}

fun isWifiAwareSupported(): Boolean
{
return wifiAwareSupported;
}

@TargetApi(Build.VERSION_CODES.O)
fun startScan() {
private fun startScan() {
if (!wifiAwareSupported) return
if (wifiAwareManager!!.isAvailable)
{
Expand All @@ -136,41 +156,13 @@ class WifiNaNScanner (
}
}

fun isWifiAwareSupported(): Boolean
{
return wifiAwareSupported;
}

@TargetApi(Build.VERSION_CODES.O)
fun stopScan() {
private fun stopScan() {
if (!wifiAwareSupported) return
if (wifiAwareManager != null && wifiAwareManager!!.isAvailable && wifiAwareSession != null)
{
wifiAwareSession!!.close()
wifiStateHandler.send(false)
}
}

fun scan() {
if (!wifiScanEnabled) {
return
}
isScanning = true
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)) {
Log.i(TAG, "WiFi Aware is not supported.");
wifiAwareSupported = false
return;
}
wifiAwareSupported = true
context.registerReceiver(myReceiver, IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED))
startScan();
}

@RequiresApi(Build.VERSION_CODES.O)
fun cancel() {
if (!wifiAwareSupported) return
isScanning = false;
stopScan()
}
}
Loading

0 comments on commit ada49b6

Please sign in to comment.