MerginMaps / MerginMaps/mobile
bluetooth scan fails silently
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 388
- Forks
- 87
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 20
Description
**Description**
When Bluetooth device discovery fails to even start, the app tells the user nothing and gets stuck
showing "Scanning for devices…" over an empty list, forever. There is no way for the user to
learn what is wrong, because the cause is never surfaced.
Internal support ticket: https://odoo.lutraconsulting.co.uk/odoo/all-tickets/16924
```
2026-08-26T13:21:42.435Z Bluetooth discovery: Error occured during device discovery, error code #6
2026-08-26T13:21:42.436Z Bluetooth discovery: Started discovering devices, method 3
```
**Environment**
Production
**Application (+ app version, build, operating system)**
- Mergin Maps mobile **2026.3.2 (839651)**
- Android-specific
Probably, it only became reachable in practice once Qt 6 added
**Steps to reproduce**
1. Bluetooth switched **on**. At least one discoverable Bluetooth device nearby.
2. Open Mergin Maps and grant the **Nearby devices** permission when prompted (this is `BLUETOOTH_SCAN` + `BLUETOOTH_CONNECT` - it must be *granted*, otherwise you hit the separate,
correctly-handled "Bluetooth permission is required" branch.
3. Now turn location off, either way round - both produce error `#6`:
- a) System **Location** master switch off - Settings → Location → Use location
- b) Settings → Apps → Mergin Maps → Permissions → **Location** → *Don't allow*
4. In the app: Settings → **Manage GPS receivers** → **Connect new receiver** → **Bluetooth**.
**Actual results**
Empty device list with "Scanning for devices…" spinning indefinitely. No message, no hint that location is involved, even after the user fixes the location setting and returns to the screen - the model still believes it is discovering, so nothing restarts it.
The log contains `error code #6` and nothing else actionable.
**Expected results**
The drawer stops the spinner and tells the user what to do - for error `#6`. Retrying after the user fixes the setting should work without reopening the app.
The log could carry `errorString()` so support can distinguish "location permission not granted" from "location service turned off" without a round trip to the customer.
**Extra debug info**
Three separate defects combine here:
1. **The discovery error never reaches QML.** `BluetoothDiscoveryModel` has no error signal — the `errorOccurred` handler only writes to the log (`app/bluetoothdiscoverymodel.cpp:28-32`). The drawer therefore cannot say anything.
2. **The model gets stuck in `discovering == true`.** On Android the error is delivered *synchronously* from inside `QBluetoothDeviceDiscoveryAgent::start()`, and `setDiscovering()` assigns `mDiscovering` only *after* `start()` returns (`app/bluetoothdiscoverymodel.cpp:102-121`). The re-entrant `finishedDiscovery()` hits the `mDiscovering == discovering` early-return and does nothing; the outer call then sets `mDiscovering = true`. The footer spinner (`app/qml/gps/MMBluetoothProviderDrawer.qml:78`) never goes away.
3. **The log throws away the one piece of information support needs.** We log the numeric code but not `errorString()` (`app/bluetoothdiscoverymodel.cpp:30`). Error `#6`(`LocationServiceTurnedOffError`) has *two* distinct causes in Qt's Android backend — location permission not granted, and the device-wide location service being off — and the code alone cannot tell them apart.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with app/bluetoothdiscoverymodel.cpp:28-32 and 102-121, then inspect the spinner in app/qml/gps/MMBluetoothProviderDrawer.qml:78. Reproduce the Android flow with location disabled and trace the synchronous discovery error and retry path. Done means error #6 reaches the drawer, the spinner stops with actionable guidance, retry works after fixing the setting, and the log includes errorString().
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, cpp
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100