Skip to content

Commit 2b8db77

Browse files
authored
DFU over USB support for Android (betaflight#4990)
1 parent 3ff9a2c commit 2b8db77

15 files changed

Lines changed: 2469 additions & 245 deletions

DFU_ANDROID_IMPLEMENTATION.md

Lines changed: 489 additions & 0 deletions
Large diffs are not rendered by default.

android/app/src/main/AndroidManifest.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@
5050
<action android:name="com.betaflight.USB_PERMISSION" />
5151
</intent-filter>
5252
</receiver>
53+
54+
<!-- Explicit receiver for DFU USB permission on Android 14+ -->
55+
<receiver
56+
android:name="betaflight.app.protocols.dfu.DfuUsbPermissionReceiver"
57+
android:exported="false">
58+
<intent-filter>
59+
<action android:name="com.betaflight.DFU_USB_PERMISSION" />
60+
</intent-filter>
61+
</receiver>
5362
</application>
5463

5564
<!-- Permissions -->
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,43 @@
11
package betaflight.app;
22

3+
import android.content.Intent;
4+
import android.hardware.usb.UsbManager;
35
import android.os.Bundle;
46

57
import betaflight.app.protocols.serial.BetaflightSerialPlugin;
68
import com.getcapacitor.BridgeActivity;
79
import betaflight.app.protocols.tcp.BetaflightTcpPlugin;
810
import betaflight.app.protocols.ble.BetaflightBlePlugin;
11+
import betaflight.app.protocols.dfu.BetaflightDfuPlugin;
912

1013
public class MainActivity extends BridgeActivity {
1114
@Override
1215
public void onCreate(Bundle savedInstanceState) {
1316
registerPlugin(BetaflightSerialPlugin.class);
1417
registerPlugin(BetaflightBlePlugin.class);
1518
registerPlugin(BetaflightTcpPlugin.class);
19+
registerPlugin(BetaflightDfuPlugin.class);
20+
21+
// If started or recreated by a USB device attachment intent (e.g. the FC
22+
// re-enumerates after DFU flash), replace it with a plain launcher intent
23+
// BEFORE super.onCreate → BridgeActivity.load() processes it.
24+
// USB events are already handled by plugin BroadcastReceivers; without this
25+
// guard, Capacitor recreates the WebView and the app appears to restart.
26+
if (getIntent() != null
27+
&& UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(getIntent().getAction())) {
28+
setIntent(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER));
29+
}
30+
1631
super.onCreate(savedInstanceState);
1732
}
33+
34+
@Override
35+
protected void onNewIntent(Intent intent) {
36+
if (intent != null
37+
&& UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
38+
setIntent(intent);
39+
return;
40+
}
41+
super.onNewIntent(intent);
42+
}
1843
}

0 commit comments

Comments
 (0)