I am implementing a service that uses the autoconnect
feature of bluetoothGatt
to connect to the device and monitor it while it is being connected.
I work on the assumption that the device is already bonded (a coworker is responsible for that part) so autoconnect should not have any problems
my code is as follows:
//the callback is for the class I have created that actually does the connection
class BTService: Service(), CoroutineScope, BTConnection.Callback {
private val btReceiver by lazy { BluetoothStateReceiver(this::btStateChange) } //receiver for bt adapter changes
private var connection:BTConnection? = null
private var readJob:Job? = null
override fun onCreate() {
buildNotificationChannels()
registerReceiver(btReceiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)) //since I can't register this receiver in AndroidManifest any more I did it here
}
private fun btStateChange(enabled: Boolean) {
if (enabled)
startConnecting()
else
stopConnection()
}
private fun startConnecting() {
val address = prefs.address //get the current saved address
val current = connection //get the current connection
//try to stop the current connection if it is different than the one we want to set up
if (current != null && !current.address.equals(address, true))
current.stop()
if (address.isNullOrBlank())
return
//then we create a new connection if needed
val new = if (current == null || !current.address.equals(address, true)) {
Injections.buildConnection(application, address, this)
} else {
current
}
connection = new
new.connect()
}
//this is one of the callbacks from BTConnection.Callback
override fun connected(address: String) {
if (address != connection?.address) return
val cn = connection ?: return
showConnectionNotification()
val notification = buildForegroundNotification()
startForeground(FOREGROUND_ID, notification)
readJob?.cancel()
readJob = launch {
cn.dataFlow //this is a flow that will be emmitting read data
.cancellable()
.flowOn(Dispatchers.IO)
.buffer()
.onEach(this@BTService::parseData)
.flowOn(Dispatchers.Default)
}
}
private suspend fun parseData(bytes:ByteArray) { //this is where the parsing and storage etc happens
}
private fun stopConnection() {
val cn = connection
connection = null
cn?.stop()
}
override fun disconnected(address: String) { //another callback from the connection class
showDisconnectNotification()
stopForeground(true)
}
my code that stops the connection is
fun stop() {
canceled = true
if (connected)
gatt?.disconnect()
launch(Dispatchers.IO) {
delay(1000)
gatt?.close()
gatt = null
}
}
my code is based (and affected) by this really good article I read:
https://medium.com/@martijn.van.welie/making-android-ble-work-part-2-47a3cdaade07
I have also created a receiver for boot events that will call
context.startService(Intent(context, BTService::class.java))
just to make sure that the service is created at least once and the bt receiver is registered
my questions are:
a) is there a chance that my service will be destroyed while it is not in foreground mode? i.e. when the device is not near by and bluetoothGat.connect is suspending while autoconnecting? is it enough for me to return START_STICKY from onStartCommand() to make sure that even when my service is destroyed it will start again?
b) if there is such a case, is there a way to at least recreate the service so the btReceiver is at least registered?
c) when should close()
be called on bluetoothGatt in case of autoconnect = true? only when creating a new connection (in my example where I call Injections.buildConnection)? do I also call it when the bluetoothadapter is disabled? or can I reuse the same connection and bluetoothGatt if the user turns the bluetooth adapter off and on again?
d) is there a way to find out if autoconnect has failed and will not try again? and is there a way to actually test and reproduce such an effect? the article mentioned above says it can happen when the batteries of the peripheral are almost empty, or when you are on the edge of the Bluetooth range
thanks in advance for any help you can provide
from Questions on creating a service that connects automatically to a BLE device on android
No comments:
Post a Comment