DFU Bootloader version (please complete the following information):
- SDK version: 30
- Bonding used: [no]
- Library version: [e.g. 1.11.0]
Device information (please complete the following information):
- Device: Xiaomi Redmi Note 7
- OS: Android 9
Question
When I am trying to start DFU, nothing happens and I get a message "DFU Service not found". My firmware file has .bin extension (if that makes any difference). I can successfully update firmware using nRF Connect app, but not using my code.
This is the main part of my code:
final DfuServiceInitiator starter = new DfuServiceInitiator(bluetoothDevice.getAddress()) .setDeviceName(bluetoothDevice.getName()) .setKeepBond(true) .setForceDfu(true) .setForeground(false) .setDisableNotification(true) .setPacketsReceiptNotificationsEnabled(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) .setPacketsReceiptNotificationsValue(DfuServiceInitiator.DEFAULT_PRN_VALUE) .setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true) .setPrepareDataObjectDelay(300L); starter.setBinOrHex(DfuService.TYPE_SOFT_DEVICE, fileUri, filePath); starter.start(this, DfuService.class);
Full code:
FlashActivity.java:
public class FlashActivity extends AppCompatActivity {
TextView fileText;
private Uri fileUri;
private String filePath;
BluetoothDevice bluetoothDevice;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
bluetoothDevice = (BluetoothDevice) intent.getExtras().get("Device");
setContentView(R.layout.activity_flash);
}
public void selectFile(View v){
Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
chooseFile.setType("*/*");
chooseFile = Intent.createChooser(chooseFile, "Choose a file");
startActivityForResult(chooseFile, 1);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1:
if (resultCode == -1) {
fileUri = data.getData();
filePath = fileUri.getPath();
fileText = findViewById(R.id.fileText);
fileText.setText(filePath);
}
break;
}
}
public void clickFlash(View v){
final DfuServiceInitiator starter = new DfuServiceInitiator(bluetoothDevice.getAddress())
.setDeviceName(bluetoothDevice.getName())
.setKeepBond(true)
.setForceDfu(true)
.setForeground(false)
.setDisableNotification(true)
.setPacketsReceiptNotificationsEnabled(Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
.setPacketsReceiptNotificationsValue(DfuServiceInitiator.DEFAULT_PRN_VALUE)
.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true)
.setPrepareDataObjectDelay(300L);
starter.setBinOrHex(DfuService.TYPE_SOFT_DEVICE, fileUri, filePath);
starter.start(this, DfuService.class);
}
}DfuService.java:
public class DfuService 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 you press it. You can use NotificationActivity to check whether the new activity
* is a root activity (that means no other activity was open earlier) or that some
* other activity is already open. In the latter case the NotificationActivity will just be
* closed. The system will restore the previous activity. However, if the application has been
* closed during upload and you 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 using
* startActivities(...).
*/
return NotificationActivity.class;
}
@Override
protected boolean isDebug() {
// Here return true if you want the service to print more logs in LogCat.
// Library's BuildConfig in current version of Android Studio is always set to DEBUG=false, so
// make sure you return true or your.app.BuildConfig.DEBUG here.
return BuildConfig.DEBUG;
}
@Override
protected void updateForegroundNotification(@NonNull final NotificationCompat.Builder builder) {
// Customize the foreground service notification here.
}
}
NotificationActivity:
public class NotificationActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// If this activity is the root activity of the task, the app is not running
if (isTaskRoot()) {
// Start the app before finishing
final Intent intent = new Intent(this, WaitActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtras(getIntent().getExtras()); // copy all extras
startActivity(intent);
}
// Now finish, which will drop you to the activity at which you were at the top of the task stack
finish();
}
}
Logs
D/BluetoothGatt: connect() - device: EF:EF:DA:98:65:0B, auto: false
registerApp()
D/BluetoothGatt: registerApp() - UUID=3f8b73f3-2108-4f2e-a639-5bcb2ef109ad
D/BluetoothGatt: onClientRegistered() - status=0 clientIf=14
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=14 device=EF:EF:DA:98:65:0B
D/BluetoothGatt: discoverServices() - device: EF:EF:DA:98:65:0B
D/BluetoothGatt: onSearchComplete() = Device=EF:EF:DA:98:65:0B Status=0
W/DfuBaseService: DFU Service not found.
D/BluetoothGatt: cancelOpen() - device: EF:EF:DA:98:65:0B
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=14 device=EF:EF:DA:98:65:0B
W/mple.safety_ap: Accessing hidden method Landroid/bluetooth/BluetoothGatt;->refresh()Z (light greylist, reflection)
D/BluetoothGatt: refresh() - device: EF:EF:DA:98:65:0B
D/BluetoothGatt: cancelOpen() - device: EF:EF:DA:98:65:0B
D/BluetoothGatt: close()
Final remarks
If possible could you provide me a code snippet ? I am not a pro at Android, the docs are not fully clear to me and the code examples from NordicSemiconductor are hard to follow. Thank you
I also asked the same question here: github.com/.../283