This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

OTA DFU in background with no notification?

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

Parents Reply Children
Related