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

Cannot get Android-DFU-Library to "start"

I am trying to use the Android-DFU-Library.  I have successfully implemented it in my project (the implementation key in gradle). However, even utilizing the documentation and example programs, I cannot get it to work.  (I have made the iOS version work)

I created my DfuProgressListener, I have created a DfuServiceInitiator, I have set the path fo the ZIP file (via setZip), and when I call "start"... nothing.  Note, I am not doing this inside of an activity.  This code is part of an Android library (AAR) that we use for isolating our bluetooth subsystem from companies we license our devices to.  We handle all the low level BLE operations in here, such as setting up and enabling all our custom characteristics, as well as taking data we receive from our device and putting it into packages to return.  The "context" that is passed in is the application context of the app that instantiates this library. 

My code:

public void updateGen2Firmware(Context context, String path) {
Log.v (TAG, "Starting");

final DfuServiceInitiator starter = new DfuServiceInitiator(macAddress).setDeviceName(deviceName).setKeepBond(false);
starter.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);

Log.v (TAG, "Setting zip to: " + path);

starter.setZip(path);

Log.v (TAG, "setting up progress listener");
DfuServiceListenerHelper.registerProgressListener(context, mDfuProgressListener);

Log.v (TAG, "calling the 'start' of starter");

starter.start(context, DfuBaseService.class);
}



Parents
  • Hello,

    You have to extend the DfuBaseService.class with your own class. The base one is abstract and requires few methods to be overridden. Have a look at his example: https://github.com/NordicSemiconductor/Android-nRF-Toolbox/blob/master/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuService.java

    This is explained in the documentation: github.com/.../documentation

    In this class you may also modify the notification that will be displayed during DFU. If you don't want any notification, disable them using the initiator.

    Also, setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled should be used only if your fw is based on SDK 12.x., and setKeepBond only when your device is bonded. The false parameter assumes that after successful dfu the target will loose all the bond information.

    Hope that helped!

    Aleksander

  • I'm doing this inside of a library, not as part of an application.  "getNotificationTarget()" is defined as follows:

    protected Class<? extends Activity> getNotificationTarget

    How can I use that when I have no Activity being used in the library? 

  • You may return null and disable notifications, and provide then, if you want, on your own based on the progress listener.

  • I did that.  Still nothing after calling "start"

    I've updated the code to use my new class:

    public void updateGen2Firmware(Context context, String path) {
    Log.v (TAG, "Starting");

    final DfuServiceInitiator starter = new DfuServiceInitiator(macAddress).setDeviceName(deviceName).setKeepBond(false);
    starter.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);

    Log.v (TAG, "Setting zip to: " + path);

    starter.setZip(path);

    Log.v (TAG, "setting up progress listener");
    DfuServiceListenerHelper.registerProgressListener(context, mDfuProgressListener);

    Log.v (TAG, "calling the 'start' of starter");

    starter.start(context, NordicDfuService.class);
    }


    And here is the implementation of that class:

    import android.app.Activity;

    import no.nordicsemi.android.dfu.DfuBaseService;

    public class NordicDfuService extends DfuBaseService {
    @Override
    protected Class<? extends Activity> getNotificationTarget() {

    /*
    * As a target activity the NotificationActivity is returned, not the MainActivity. This is because the notification must create a new task:
    *
    * intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    *
    * when user press it. Using NotificationActivity we can check whether the new activity is a root activity (that means no other activity was open before)
    * or that there is other activity already open. In the later case the notificationActivity will just be closed. System will restore the previous activity.
    * However if the application has been closed during upload and user click the notification a NotificationActivity will be launched as a root activity.
    * It will create and start the main activity and terminate itself.
    *
    * This method may be used to restore the target activity in case the application was closed or is open. It may also be used to recreate an activity
    * history (see NotificationActivity).
    */
    //return NotificationActivity.class;
    return null;

    }

    @Override
    protected boolean isDebug() {

    // return BuildConfig.DEBUG;
    return true;

    }
    }



    It really doesn't look like it is even starting.

    Note - I am using SDK12, so all the buttonless / bonding stuff should be right.  

Reply Children
  • (facepalm).  Derp.  Forgot to do that.  OK, I did it, and it causes the app to crash.  Because it said:

    java.lang.NullPointerException: getNotificationTarget() must not return null if notifications are enabled

    I definitely want notifications on progress, just I don't have an "activity", as this is in a library.  

  • You may either leave the activity to be specified by the app that will use your lib, or create notifications on your own, based on the progress you will receive, and disable them in the dfu library.

    The activity is required there to specify the target when user clicks the notification to be navigated to.

  • "...or create notifications on your own, based on the progress you will receive, and disable them in the dfu library"

    Can you show me an example of this?  This literally doesn't make sense to me.  Because you have a dfuProgressListener and I don't know why I'm not just tapping into that.  Secondly, I don't even know what you mean by "leave the activity to be specified by the app that will use your lib". I can't pass this in as a parameter, because we don't even create an instance of the "NotificationActivity" class.  It's just the class type... how can I pass that in anywhere?

    All I want is to get stuff on the DFUListener and then pass that to my own callbacks that my library produces.  This shouldn't be so complicated.  

  • I went ahead and passed in the activity to my library.  I now received the following log output.  It looks like it started, but couldn't enable the Bootloader?  The verbose log messages with "waveletDevice" are just messages I dump from the DfuProgressListener

    03-07 08:50:55.199 com.wavelethealth.sdktest 25548 - I DfuBaseService DFU service created. Version: 1.8.1
    03-07 08:50:55.273 com.wavelethealth.sdktest 25548 26284 I DfuBaseService Connecting to the device...
    03-07 08:50:55.292 com.wavelethealth.sdktest 25548 25693 I DfuBaseService Connected to GATT server
    03-07 08:50:55.296 com.wavelethealth.sdktest 25548 25693 I DfuBaseService Attempting to start service discovery... succeed
    03-07 08:50:55.305 com.wavelethealth.sdktest 25548 25693 I DfuBaseService Services discovered
    03-07 08:50:55.308 com.wavelethealth.sdktest 25548 26284 I DfuImpl Buttonless service without bond sharing found -> SDK 13 or newer
    03-07 08:50:55.312 com.wavelethealth.sdktest 25548 - V waveletDevice onDeviceConnected: DD:4C:77:0C:92:B8
    03-07 08:50:55.312 com.wavelethealth.sdktest 25548 - V waveletDevice onDfuProcessStarting: DD:4C:77:0C:92:B8
    03-07 08:50:56.329 com.wavelethealth.sdktest 25548 26284 I DfuImpl Enabling indications...
    03-07 08:50:57.379 com.wavelethealth.sdktest 25548 - V waveletDevice onEnablingDfuMode: DD:4C:77:0C:92:B8
    03-07 08:50:57.411 com.wavelethealth.sdktest 25548 26284 I DfuImpl Sending Enter Bootloader (Op Code = 1)
    03-07 08:50:57.449 com.wavelethealth.sdktest 25548 26284 I DfuImpl Response received (Op Code = 1, Status = 1)
    03-07 08:51:17.505 com.wavelethealth.sdktest 25548 25563 W DfuBaseService Target device disconnected with status: 8
    03-07 08:51:17.531 com.wavelethealth.sdktest 25548 26284 I DfuBaseService Refreshing result: true
    03-07 08:51:17.532 com.wavelethealth.sdktest 25548 26284 I DfuBaseService Cleaning up...
    03-07 08:51:17.535 com.wavelethealth.sdktest 25548 - I DfuBaseService Action received: android.bluetooth.device.action.ACL_DISCONNECTED

  • "how can I pass that in anywhere?" - just like the dfu library is doing (leave the DfuService to be overridden by final app, or pass it as a parameter. Class type is as good as any other.

    If you disable notifications in the initiator this is not required. There just won't be any notification downs by the dfu lib. You will still receive progress with the progress listener. The example (although together with notifications) is in nRF Toolbox.

Related