Hi, I have implemented OTA DFU on Android with your official DFU library. We want the DFU to happen in background at a certain trigger (car driving, triggered from device = user will stay near device) and without bothering the user that this is happening. My implementation was all good and working fine when the app was in the foreground while this was happening, but since we don't expect the user to be staring at his phone while driving - this needs to happen in the background of course. Problem is, when I tested this the following happend:
SDK 15.3 softdevice s132.
starter created controller initiated listener registred onDfuProcessStarting FA:11:1B:B1:D7:C4 onEnablingDfuMode onDeviceConnecting DfuBaseService: Connection state change error: 133 newState: 0 DfuBaseService: Device not reachable. Check if the device with address FA:11:1B:B1:D7:C4 is in range, is advertising and is connectable DfuBaseService: Connection state change error: 133 newState: 0 DfuBaseService: Device not reachable. Check if the device with address FA:11:1B:B1:D7:C4 is in range, is advertising and is connectable DfuBaseService: Connection state change error: 133 newState: 0 DfuBaseService: Device not reachable. Check if the device with address FA:11:1B:B1:D7:C4 is in range, is advertising and is onError 133 type 1 message GATT ERROR
It is implemented in the following way.
a Presenter class contains the function scheduleDFU
private fun scheduleDFU() { val fwFile = File(context.getExternalFilesDir(null).toString() + File.separator.toString() + "fw.zip") Log.d("DFUTEST","scheduleDFU with " + fwFile.absolutePath + " " + fwFile.absolutePath) val starter = deviceComm.getConnectedDevice()?.address?.let { DfuServiceInitiator(it) .setDeviceName(deviceComm.getConnectedDevice()?.name) .setKeepBond(true) // keep bond after dfu .setForceDfu(true) .setPacketsReceiptNotificationsEnabled(false) .setDisableNotification(true) // no foreground notification .setForeground(false) .setPrepareDataObjectDelay(400L) } starter!!.setZip(fwFile.toUri(), fwFile.absolutePath) Log.d("DFUTEST","starter created") dfuServiceController = starter!!.start(context, DfuService::class.java) Log.d("DFUTEST","controller initiated") DfuServiceListenerHelper.registerProgressListener(context, dfuProgressListener) Log.d("DFUTEST","listener registred") }
I didn't want any notifications, and disabled that as you can see above and so the implementation of DfuBaseService (as pr your examples) is very bare bones:
class DfuService : DfuBaseService() { @Override protected override fun getNotificationTarget(): Class<out Activity> { Log.d("DFUTEST","getNotificationTarget") return NotificationActivity::class.java } @Override protected override fun isDebug(): Boolean { return super.isDebug() } @Override protected override fun updateForegroundNotification(builder: NotificationCompat.Builder) { Log.d("DFUTEST","updateForegroundNot") super.updateForegroundNotification(builder) } }
The progress listener is also pretty simple, all it does is log and unsubscribe itself
private val dfuProgressListener: DfuProgressListener = object : DfuProgressListenerAdapter() { override fun onDeviceConnecting(deviceAddress: String) { Log.d("DFUTEST","onDeviceConnecting") } override fun onDfuProcessStarting(deviceAddress: String) { App.dfuInProgress = true Log.d("DFUTEST","onDfuProcessStarting " + deviceAddress ) } override fun onEnablingDfuMode(deviceAddress: String) { Log.d("DFUTEST","onEnablingDfuMode") } override fun onFirmwareValidating(deviceAddress: String) { Log.d("DFUTEST","onFirmwareValidating") } override fun onDeviceDisconnecting(deviceAddress: String) { Log.d("DFUTEST","onDeviceDisconnecting " + deviceAddress) //DfuServiceListenerHelper.unregisterProgressListener(context, this) } override fun onDfuCompleted(deviceAddress: String) { Log.d("DFUTEST","onDfuCompleted") App.dfuInProgress = false DfuServiceListenerHelper.unregisterProgressListener(context, this) } override fun onDfuAborted(deviceAddress: String) { Log.d("DFUTEST","onDfuAborted") DfuServiceListenerHelper.unregisterProgressListener(context, this) } override fun onProgressChanged( deviceAddress: String, percent: Int, speed: Float, avgSpeed: Float, currentPart: Int, partsTotal: Int ) { Log.d("DFUTEST","onProgressChanged / " + percent) } override fun onError(deviceAddress: String, error: Int, errorType: Int, message: String) { Log.d("DFUTEST","onError " + error + " type " + errorType + " message " + message) } }
So my question:
I assume this has to do with me disabling the foreground notification when setting up the DfuServiceInitiator, but I was under the impression that it was possible to do this without a notification?
Best
Søren