Skip to content

Commit 0ea1e64

Browse files
committed
Android serial: full overhaul (lifecycle FSM, async write pump, strategy backend)
Replaces the vendored QSerialPort backport with a standalone QGCAndroidSerialPort that wraps a strategy engine (IQSerialPortEngine). Production uses QAndroidSerialEngine; host tests use MockQSerialPortEngine — same contract, no JNI dependency. Java side: - Explicit port lifecycle FSM (UsbSerialLifecycle) replacing scattered state. - Consolidated USB permission handling (QGCUsbPermissionHandler). - AsyncUsbWritePump: bounded queue + N workers per port + per-baud token-bucket throttle. forBulkTransfer (N=4) for CDC-ACM/CP210x/CH34x/mik3y FTDI; forD2xx (N=1) for D2XX-backed FTDI. Ownership-transfer submit() — pump owns the buffer until onComplete fires, eliminating a per-write heap copy. - BoundedPool for write-scratch byte[] reuse. - READ_QUEUE_DEPTH=3 (was 2) to ride out GC pauses at high baud. - Typed Java exception channel surfaces as QGCSerialPortError on the C++ side instead of opaque IOException strings. - D2XX gated off by default (ENABLE_D2XX=false). Tracks #14146: canOpenViaD2XX() returns true on Android 14 / OneUI 6 then the actual open fails. VCP-mode FtdiSerialDriver covers the same chips. C++ side: - JNIEnv caching on the hot write path (static getJniEnv + checkAndClearExceptions) — drops a QJniEnvironment construction per call. - Read offset sentinel in QGCAndroidSerialPort: readData advances an offset and compacts only when half-consumed, instead of erase-from-front on every drain. - QGCSerialPortAdapter: strategy-pattern backend (AndroidSerialBackend always, HostSerialBackend on !Q_OS_ANDROID). Modeled on Qt's QNetworkAccessBackend. Collapses ~32 Q_OS_ANDROID conditionals down to 4 (include guard, host error mapper, host backend class, factory dispatch). - Batched setSerialParameters(baud, dataBits, stopBits, parity) — collapses what was 4 sequential single-param JNI hops into 1. Wired through Bootloader, SerialLink, GPSProvider. Tests: - JVM unit tests: AsyncUsbWritePumpTest (7), BoundedPoolTest (4). - C++ unit tests via MockQSerialPortEngine: QGCAndroidSerialPortTest covers lifecycle, setters (cached-while-closed + applied-while-open), batched parameter setter, exception → error mapping, expectClosure suppression. - QGCSerialPortAdapterTest exercises the strategy dispatch.
1 parent 129ad72 commit 0ea1e64

88 files changed

Lines changed: 7854 additions & 6430 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/mcp-config.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"mcpServers": {
3+
"qt-docs": {
4+
"url": "https://qt-docs-mcp.qt.io/mcp"
5+
}
6+
}
7+
}

AGENTS.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,48 @@ cd .github/scripts && PYTHONPATH=. python3 -m pytest tests/ -q
4747
cd tools && uv run --extra scripts --extra test pytest tests/ -q
4848
```
4949

50+
## Android: Install + Logcat
51+
52+
Workflow for installing a debug-built APK to a connected device and capturing logs.
53+
54+
Prereqs (on PATH): `adb`, `zipalign`, `apksigner` (Android `build-tools/<ver>/`). Debug keystore at `~/.android/debug.keystore` (alias `androiddebugkey`, password `android`).
55+
56+
```bash
57+
# Adjust APK path to your Qt-Android build kit/configuration
58+
APK=build/Qt_6_10_3_for_Android_arm64_v8a-Debug/android-build-QGroundControl/QGroundControl.apk
59+
60+
# Re-sign with the debug keystore (Qt's androiddeployqt output is unsigned/misaligned for adb install)
61+
zipalign -p -f 4 "$APK" "${APK%.apk}-aligned.apk"
62+
apksigner sign --ks ~/.android/debug.keystore --ks-pass pass:android --ks-key-alias androiddebugkey \
63+
--key-pass pass:android --out "${APK%.apk}-signed.apk" "${APK%.apk}-aligned.apk"
64+
65+
# Install (replace existing); -r keeps data, add -d to allow downgrade
66+
adb install -r "${APK%.apk}-signed.apk"
67+
68+
# Launch (force-stop first for a clean session)
69+
adb shell am force-stop org.mavlink.qgroundcontrol
70+
adb shell am start -n org.mavlink.qgroundcontrol/.QGCActivity
71+
72+
# Logcat: clear, then stream QGC + serial-related tags only
73+
adb logcat -c
74+
adb logcat -v time \
75+
QGroundControl:V QGCActivity:V QGCUsbSerialManager:V QGCUsbPermissionHandler:V \
76+
QGCFtdiSerialDriver:V QGCSerialListener:V QGCUsbSerialProber:V \
77+
AsyncUsbWritePump:V UsbSerialEnumerator:V UsbSerialIoBridge:V UsbSerialLifecycle:V '*:S'
78+
79+
# Enable per-tag VERBOSE for code paths gated on Log.isLoggable(TAG, VERBOSE).
80+
# Tag must be ≤23 chars; setprop survives until reboot.
81+
adb shell setprop log.tag.QGCSerialListener VERBOSE
82+
adb shell setprop log.tag.UsbSerialIoBridge VERBOSE
83+
adb shell setprop log.tag.AsyncUsbWritePump VERBOSE
84+
85+
# Qt-side verbose categories — set via QT_LOGGING_RULES before launch, or in-app via the log viewer
86+
adb shell am start -n org.mavlink.qgroundcontrol/.QGCActivity \
87+
--es "QT_LOGGING_RULES" "Android.Serial.Engine.debug=true;VehicleSetup.FirmwareUpgrade.debug=true"
88+
```
89+
90+
Tip: run logcat in a background shell (`run_in_background=true`) and grep the captured file rather than streaming into the agent context.
91+
5092
## Golden Rules
5193

5294
1. **Fact System**: ALL vehicle parameters use Facts. Never create custom parameter storage.

android/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,14 @@ android {
184184
lintConfig = file("lint.xml")
185185
}
186186

187+
// Local unit tests run on the host JVM against a stub android.jar where every
188+
// framework method throws "not mocked" by default. Return defaults so plain
189+
// android.util.Log calls become no-ops in tests; tests that need real behavior
190+
// mock those methods explicitly (or use Robolectric).
191+
testOptions {
192+
unitTests.returnDefaultValues = true
193+
}
194+
187195
// Do not compress Qt binary resources file
188196
aaptOptions {
189197
noCompress 'rcc'

android/proguard-rules.pro

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,23 @@
88
-keepclasseswithmembers class org.mavlink.qgroundcontrol.QGCActivity {
99
native <methods>;
1010
}
11-
-keepclasseswithmembers class org.mavlink.qgroundcontrol.QGCUsbSerialManager {
11+
-keepclasseswithmembers class org.mavlink.qgroundcontrol.serial.QGCUsbSerialManager {
12+
native <methods>;
13+
}
14+
-keepclasseswithmembers class org.mavlink.qgroundcontrol.QGCNativeLogSink {
1215
native <methods>;
1316
}
1417
# Static methods are resolved from C++ by method name/signature.
1518
-keepclassmembers class org.mavlink.qgroundcontrol.QGCActivity {
1619
public static *;
1720
}
18-
-keepclassmembers class org.mavlink.qgroundcontrol.QGCUsbSerialManager {
21+
-keepclassmembers class org.mavlink.qgroundcontrol.serial.QGCUsbSerialManager {
1922
public static *;
2023
}
21-
-keep class org.mavlink.qgroundcontrol.QGCUsbId { *; }
22-
-keep class org.mavlink.qgroundcontrol.QGCUsbSerialProber { *; }
2324
-keep class org.mavlink.qgroundcontrol.QGCLogger { *; }
24-
-keep class org.mavlink.qgroundcontrol.QGCFtdiSerialDriver { *; }
25-
-keep class org.mavlink.qgroundcontrol.QGCFtdiSerialDriver$QGCFtdiSerialPort { *; }
26-
-keep class org.mavlink.qgroundcontrol.QGCFtdiDriver { *; }
25+
-keep class org.mavlink.qgroundcontrol.QGCNativeLogSink { *; }
2726
-keep class org.mavlink.qgroundcontrol.QGCSDLManager { *; }
27+
-keep class org.mavlink.qgroundcontrol.serial.** { *; }
2828

2929
# SDL - native method stubs required for JNI registration
3030
-keep class org.libsdl.app.** { *; }

android/res/xml/device_filter.xml

Lines changed: 122 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,125 @@
11
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Android USB device filter for QGC.
4+
5+
When a USB device matching any entry here is attached, Android shows
6+
"Open QGroundControl when this USB device is connected?" with an
7+
optional "Use by default" checkbox. If the user enables the default,
8+
permission persists across reconnects for that specific device and
9+
QGC launches automatically on attach.
10+
11+
Read by the Android OS from the APK manifest at install time — cannot be
12+
generated at runtime. Decimal values are required by the schema (hex in comments).
13+
14+
Keep entries in sync with src/Comms/USBBoardInfo.json (the C++-side board list)
15+
for any flight-controller VID/PIDs that should trigger autostart on attach.
16+
-->
217
<resources>
3-
<!-- Allow anything connected -->
4-
<usb-device />
5-
6-
<!-- 0x0403 / 0x60??: FTDI -->
7-
<!-- <usb-device vendor-id="1027" product-id="24577" /> --> <!-- 0x6001: FT232R -->
8-
<!-- <usb-device vendor-id="1027" product-id="24592" /> --> <!-- 0x6010: FT2232H -->
9-
<!-- <usb-device vendor-id="1027" product-id="24593" /> --> <!-- 0x6011: FT4232H -->
10-
<!-- <usb-device vendor-id="1027" product-id="24596" /> --> <!-- 0x6014: FT232H -->
11-
<!-- <usb-device vendor-id="1027" product-id="24597" /> --> <!-- 0x6015: FT230X, FT231X, FT234XD -->
12-
13-
<!-- 0x10C4 / 0xEA??: Silabs CP210x -->
14-
<!-- <usb-device vendor-id="4292" product-id="60000" /> --> <!-- 0xea60: CP2102 and other CP210x single port devices -->
15-
<!-- <usb-device vendor-id="4292" product-id="60016" /> --> <!-- 0xea70: CP2105 -->
16-
<!-- <usb-device vendor-id="4292" product-id="60017" /> --> <!-- 0xea71: CP2108 -->
17-
18-
<!-- 0x067B / 0x23?3: Prolific PL2303x -->
19-
<!-- <usb-device vendor-id="1659" product-id="8963" /> --> <!-- 0x2303: PL2303HX, HXD, TA, ... -->
20-
<!-- <usb-device vendor-id="1659" product-id="9123" /> --> <!-- 0x23a3: PL2303GC -->
21-
<!-- <usb-device vendor-id="1659" product-id="9139" /> --> <!-- 0x23b3: PL2303GB -->
22-
<!-- <usb-device vendor-id="1659" product-id="9155" /> --> <!-- 0x23c3: PL2303GT -->
23-
<!-- <usb-device vendor-id="1659" product-id="9171" /> --> <!-- 0x23d3: PL2303GL -->
24-
<!-- <usb-device vendor-id="1659" product-id="9187" /> --> <!-- 0x23e3: PL2303GE -->
25-
<!-- <usb-device vendor-id="1659" product-id="9203" /> --> <!-- 0x23f3: PL2303GS -->
26-
27-
<!-- 0x1a86 / 0x?523: Qinheng CH34x -->
28-
<!-- <usb-device vendor-id="6790" product-id="21795" /> --> <!-- 0x5523: CH341A -->
29-
<!-- <usb-device vendor-id="6790" product-id="29987" /> --> <!-- 0x7523: CH340 -->
30-
31-
<!-- CDC driver -->
32-
<!-- <usb-device vendor-id="9025" /> --> <!-- 0x2341 / ......: Arduino -->
33-
<!-- <usb-device vendor-id="5824" product-id="1155" /> --> <!-- 0x16C0 / 0x0483: Teensyduino -->
34-
<!-- <usb-device vendor-id="1003" product-id="8260" /> --> <!-- 0x03EB / 0x2044: Atmel Lufa -->
35-
<!-- <usb-device vendor-id="7855" product-id="4" /> --> <!-- 0x1eaf / 0x0004: Leaflabs Maple -->
36-
<!-- <usb-device vendor-id="3368" product-id="516" /> --> <!-- 0x0d28 / 0x0204: ARM mbed -->
37-
<!-- <usb-device vendor-id="1155" product-id="22336" /> --> <!-- 0x0483 / 0x5740: ST CDC -->
38-
<!-- <usb-device vendor-id="11914" product-id="5" /> --> <!-- 0x2E8A / 0x0005: Raspberry Pi Pico Micropython -->
39-
<!-- <usb-device vendor-id="11914" product-id="10" /> --> <!-- 0x2E8A / 0x000A: Raspberry Pi Pico SDK -->
40-
<!-- <usb-device vendor-id="6790" product-id="21972" /> --> <!-- 0x1A86 / 0x55D4: Qinheng CH9102F -->
18+
19+
<!-- ======================================================================
20+
USB-to-serial bridges (most common adapters for flight controllers)
21+
====================================================================== -->
22+
23+
<!-- 0x0403 / 0x60xx: FTDI -->
24+
<usb-device vendor-id="1027" product-id="24577" /> <!-- 0x6001: FT232R -->
25+
<usb-device vendor-id="1027" product-id="24592" /> <!-- 0x6010: FT2232H -->
26+
<usb-device vendor-id="1027" product-id="24593" /> <!-- 0x6011: FT4232H -->
27+
<usb-device vendor-id="1027" product-id="24596" /> <!-- 0x6014: FT232H -->
28+
<usb-device vendor-id="1027" product-id="24597" /> <!-- 0x6015: FT230X, FT231X, FT234XD -->
29+
30+
<!-- 0x10C4 / 0xEAxx: Silabs CP210x -->
31+
<usb-device vendor-id="4292" product-id="60000" /> <!-- 0xEA60: CP2102/CP210x single port -->
32+
<usb-device vendor-id="4292" product-id="60016" /> <!-- 0xEA70: CP2105 -->
33+
<usb-device vendor-id="4292" product-id="60017" /> <!-- 0xEA71: CP2108 -->
34+
35+
<!-- 0x067B / 0x23x3: Prolific PL2303x -->
36+
<usb-device vendor-id="1659" product-id="8963" /> <!-- 0x2303: PL2303HX, HXD, TA, ... -->
37+
<usb-device vendor-id="1659" product-id="9123" /> <!-- 0x23A3: PL2303GC -->
38+
<usb-device vendor-id="1659" product-id="9139" /> <!-- 0x23B3: PL2303GB -->
39+
<usb-device vendor-id="1659" product-id="9155" /> <!-- 0x23C3: PL2303GT -->
40+
<usb-device vendor-id="1659" product-id="9171" /> <!-- 0x23D3: PL2303GL -->
41+
<usb-device vendor-id="1659" product-id="9187" /> <!-- 0x23E3: PL2303GE -->
42+
<usb-device vendor-id="1659" product-id="9203" /> <!-- 0x23F3: PL2303GS -->
43+
44+
<!-- 0x1A86 / 0xxxxx: Qinheng CH34x / CH9102 -->
45+
<usb-device vendor-id="6790" product-id="21795" /> <!-- 0x5523: CH341A -->
46+
<usb-device vendor-id="6790" product-id="29987" /> <!-- 0x7523: CH340 -->
47+
<usb-device vendor-id="6790" product-id="21972" /> <!-- 0x55D4: CH9102F -->
48+
49+
<!-- ======================================================================
50+
Flight-controller CDC/native-USB VIDs
51+
====================================================================== -->
52+
53+
<!-- 0x26AC: PX4 FMU family -->
54+
<usb-device vendor-id="9900" product-id="16" /> <!-- 0x0010: FMU v1 -->
55+
<usb-device vendor-id="9900" product-id="17" /> <!-- 0x0011: FMU v2/v3 -->
56+
<usb-device vendor-id="9900" product-id="18" /> <!-- 0x0012: FMU v4 -->
57+
<usb-device vendor-id="9900" product-id="19" /> <!-- 0x0013: FMU v4 Pro -->
58+
<usb-device vendor-id="9900" product-id="29" /> <!-- 0x001D: FMU v6X RT -->
59+
<usb-device vendor-id="9900" product-id="48" /> <!-- 0x0030: MindPX v2 -->
60+
<usb-device vendor-id="9900" product-id="50" /> <!-- 0x0032: FMU v5 -->
61+
<usb-device vendor-id="9900" product-id="51" /> <!-- 0x0033: FMU v5X -->
62+
<usb-device vendor-id="9900" product-id="53" /> <!-- 0x0035: FMU v6X -->
63+
<usb-device vendor-id="9900" product-id="54" /> <!-- 0x0036: FMU v6U -->
64+
<usb-device vendor-id="9900" product-id="56" /> <!-- 0x0038: FMU v6C -->
65+
66+
<!-- 0x1209: ArduPilot (pid.codes) -->
67+
<usb-device vendor-id="4617" product-id="22336" /> <!-- 0x5740: ChibiOS -->
68+
<usb-device vendor-id="4617" product-id="22337" /> <!-- 0x5741: ChibiOS v2 -->
69+
70+
<!-- 0x2DAE: CubePilot -->
71+
<usb-device vendor-id="11694" product-id="4097" /> <!-- 0x1001: Cube Black bootloader -->
72+
<usb-device vendor-id="11694" product-id="4098" /> <!-- 0x1002: Cube Yellow bootloader -->
73+
<usb-device vendor-id="11694" product-id="4101" /> <!-- 0x1005: Cube Purple bootloader -->
74+
<usb-device vendor-id="11694" product-id="4113" /> <!-- 0x1011: Cube Black / Black+ -->
75+
<usb-device vendor-id="11694" product-id="4114" /> <!-- 0x1012: Cube Yellow -->
76+
<usb-device vendor-id="11694" product-id="4117" /> <!-- 0x1015: Cube Purple -->
77+
<usb-device vendor-id="11694" product-id="4118" /> <!-- 0x1016: Cube Orange -->
78+
<usb-device vendor-id="11694" product-id="4119" /> <!-- 0x1017: Cube Orange2 -->
79+
<usb-device vendor-id="11694" product-id="4184" /> <!-- 0x1058: Cube Orange+ -->
80+
81+
<!-- 0x3162: Holybro -->
82+
<usb-device vendor-id="12642" product-id="71" /> <!-- 0x0047: Pixhawk 4 -->
83+
<usb-device vendor-id="12642" product-id="73" /> <!-- 0x0049: Pixhawk 4 Mini -->
84+
<usb-device vendor-id="12642" product-id="75" /> <!-- 0x004B: Durandal -->
85+
86+
<!-- 0x3163: CUAV -->
87+
<usb-device vendor-id="12643" product-id="76" /> <!-- 0x004C: Nora / X7Pro -->
88+
89+
<!-- 0x20A0: OpenPilot -->
90+
<usb-device vendor-id="8352" product-id="16732" /> <!-- 0x415C: OPLink -->
91+
<usb-device vendor-id="8352" product-id="16733" /> <!-- 0x415D: CC3D -->
92+
<usb-device vendor-id="8352" product-id="16734" /> <!-- 0x415E: Revolution -->
93+
<usb-device vendor-id="8352" product-id="16848" /> <!-- 0x41D0: Sparky2 -->
94+
95+
<!-- 0x1FC9: Dragonlink -->
96+
<usb-device vendor-id="8137" product-id="131" /> <!-- 0x0083: Dragonlink -->
97+
98+
<!-- 0x27AC: Laser Navigation (VRBrain) -->
99+
<usb-device vendor-id="10156" product-id="4433" /> <!-- 0x1151: VRBrain v51 -->
100+
<usb-device vendor-id="10156" product-id="4434" /> <!-- 0x1152: VRBrain v52 -->
101+
<usb-device vendor-id="10156" product-id="4436" /> <!-- 0x1154: VRBrain v54 -->
102+
<usb-device vendor-id="10156" product-id="4945" /> <!-- 0x1351: VRuBrain v51 -->
103+
<usb-device vendor-id="10156" product-id="6416" /> <!-- 0x1910: VRCore v10 -->
104+
105+
<!-- 0x1546: u-blox GPS receivers -->
106+
<usb-device vendor-id="5446" product-id="421" /> <!-- 0x01A5: u-blox 5 -->
107+
<usb-device vendor-id="5446" product-id="422" /> <!-- 0x01A6: u-blox 6 -->
108+
<usb-device vendor-id="5446" product-id="423" /> <!-- 0x01A7: u-blox 7 -->
109+
<usb-device vendor-id="5446" product-id="424" /> <!-- 0x01A8: u-blox 8 -->
110+
<usb-device vendor-id="5446" product-id="425" /> <!-- 0x01A9: u-blox 9 (ZED-F9P) -->
111+
112+
<!-- 0x0483 / 0x5740: ST CDC (STM32 default) -->
113+
<usb-device vendor-id="1155" product-id="22336" />
114+
115+
<!-- ======================================================================
116+
Generic development boards (kept from the previous catch-all list)
117+
====================================================================== -->
118+
<usb-device vendor-id="9025" /> <!-- 0x2341: Arduino (any PID) -->
119+
<usb-device vendor-id="5824" product-id="1155" /> <!-- 0x16C0 / 0x0483: Teensyduino -->
120+
<usb-device vendor-id="1003" product-id="8260" /> <!-- 0x03EB / 0x2044: Atmel Lufa -->
121+
<usb-device vendor-id="7855" product-id="4" /> <!-- 0x1EAF / 0x0004: Leaflabs Maple -->
122+
<usb-device vendor-id="3368" product-id="516" /> <!-- 0x0D28 / 0x0204: ARM mbed -->
123+
<usb-device vendor-id="11914" product-id="5" /> <!-- 0x2E8A / 0x0005: Pi Pico MicroPython -->
124+
<usb-device vendor-id="11914" product-id="10" /> <!-- 0x2E8A / 0x000A: Pi Pico SDK -->
41125
</resources>

android/src/org/mavlink/qgroundcontrol/QGCActivity.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
import org.freedesktop.gstreamer.GStreamer;
2222

23+
import org.mavlink.qgroundcontrol.serial.QGCUsbSerialManager;
24+
2325
public class QGCActivity extends QtActivity {
2426
private static final String TAG = QGCActivity.class.getSimpleName();
2527
private static final String MULTICAST_LOCK_TAG = "QGroundControl";
@@ -39,7 +41,7 @@ public void onCreate(Bundle savedInstanceState) {
3941
nativeInit();
4042
setupMulticastLock();
4143

42-
QGCUsbSerialManager.initialize(this);
44+
QGCUsbSerialManager.createInstance(this);
4345
QGCSDLManager.initialize(this);
4446
m_storagePermissionController = new QGCStoragePermissionController(this);
4547
}
@@ -61,7 +63,7 @@ protected void onDestroy() {
6163
try {
6264
QGCSDLManager.cleanup();
6365
releaseMulticastLock();
64-
QGCUsbSerialManager.cleanup(this);
66+
QGCUsbSerialManager.destroyInstance();
6567
} catch (final Exception e) {
6668
QGCLogger.e(TAG, "Exception onDestroy()", e);
6769
}
@@ -137,7 +139,7 @@ private String copyFileToDestination(final Uri uri, final String destDir) {
137139
if (cursor != null && cursor.moveToFirst()) {
138140
final int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
139141
if (nameIndex >= 0) {
140-
displayName = cursor.getString(nameIndex);
142+
displayName = cursor.getString(nameIndex);
141143
displayName = sanitizeFilename(displayName);
142144
}
143145
}
@@ -314,8 +316,6 @@ public boolean dispatchKeyEvent(KeyEvent event) {
314316

315317
// Native C++ functions
316318
public native boolean nativeInit();
317-
public native void qgcLogDebug(final String message);
318-
public native void qgcLogWarning(final String message);
319319
public native void nativeStoragePermissionsResult(boolean granted);
320320
public native void onImportResult(final String filePath);
321321
}

0 commit comments

Comments
 (0)