I'm currently building a chat app based on Bluetooth Low Energy Advertisments. I tried to build a client following this tutorial by android, but my BluetoothLeScanner doesnt seem to retrieve any BLE 2M PHY scanResults. I was able to achieve the desired result by using the nRF Connect app, so it's probably not a hardware issue
class BluetoothAdvertiser(private var bluetoothAdapter: BluetoothAdapter) {
private val TAG: String = BluetoothAdvertiser::class.java.simpleName
private var advertiseUUID: ParcelUuid =
ParcelUuid(UUID.fromString("e889813c-5d19-49e2-8bc4-d4596b4f5250"))
private var advertiser: BluetoothLeAdvertiser = bluetoothAdapter.bluetoothLeAdvertiser
private var maxDataLength: Int = 0
private lateinit var currentAdvertisingData: AdvertiseData
private lateinit var currentAdvertisingSet: AdvertisingSet
fun init(): Boolean {
Log.d(TAG, "init: ")
if (!this.checkDeviceHardware()) {
return false
}
this.initAdvertiser("123")
return true
}
private fun checkDeviceHardware(): Boolean {
if (!this.bluetoothAdapter.isLe2MPhySupported) {
Log.e(TAG, "init: 2M PHY not supported")
return false
}
if (!this.bluetoothAdapter.isLeExtendedAdvertisingSupported) {
Log.e(TAG, "init: LE Extended Advertising not supported")
return false
}
this.maxDataLength = this.bluetoothAdapter.leMaximumAdvertisingDataLength
Log.d(TAG, "init: leMaximumAdvertisingDataLength: " + this.maxDataLength)
return true
}
private fun initAdvertiser(message: String): Boolean {
val setParameters: AdvertisingSetParameters = AdvertisingSetParameters.Builder()
.setLegacyMode(false)
.setInterval(AdvertisingSetParameters.INTERVAL_HIGH)
.setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MEDIUM)
.setPrimaryPhy(BluetoothDevice.PHY_LE_CODED)
.setSecondaryPhy(BluetoothDevice.PHY_LE_2M)
.build()
val advertiseData: AdvertiseData = AdvertiseData.Builder()
.setIncludeDeviceName(true)
.addServiceUuid(advertiseUUID)
.addServiceData(advertiseUUID, message.encodeToByteArray())
.build()
val periodicParameters: PeriodicAdvertisingParameters = PeriodicAdvertisingParameters.Builder()
.setInterval(800)
.build()
return try {
this.advertiser.startAdvertisingSet(
setParameters,
advertiseData,
advertiseData,
periodicParameters,
advertiseData,
this.advertisingSetCallback
)
true
} catch (e: SecurityException) {
Log.w(TAG, "initAdvertiser: ",e)
false
}
}
fun changeAdvertisingData(message: String){
try{
Log.d(TAG, "changeAdvertisingData: message: $message" )
this.currentAdvertisingSet.setAdvertisingData(AdvertiseData.Builder().addServiceData(this.advertiseUUID,message.encodeToByteArray()).build())
} catch (e: SecurityException) {
Log.w(TAG, "initAdvertiser: ",e)
}
}
private var advertisingSetCallback: AdvertisingSetCallback = object : AdvertisingSetCallback() {
override fun onAdvertisingSetStarted(
advertisingSet: AdvertisingSet,
txPower: Int,
status: Int
) {
Log.i(
TAG, "onAdvertisingSetStarted(): txPower: $txPower , status: $status "
)
currentAdvertisingSet = advertisingSet
}
override fun onAdvertisingSetStopped(advertisingSet: AdvertisingSet) {
Log.i(TAG, "onAdvertisingSetStopped():")
}
}
The code above is working as intended, but I didn't set up the BluetoothLeScanner for non-legacy advertisements, below is my now working scanner