docs: move BUG_REPORT.md to docs/
This commit is contained in:
parent
33935de4f2
commit
369ac49602
1 changed files with 0 additions and 0 deletions
178
BUG_REPORT.md
178
BUG_REPORT.md
|
|
@ -1,178 +0,0 @@
|
|||
# Traccar Client Bug Report: Location Data Not Reaching Server
|
||||
|
||||
**Date**: April 30, 2026
|
||||
**Status**: Investigating
|
||||
|
||||
## Issue Summary
|
||||
|
||||
The Traccar Client app shows the device as **always offline** and no location reports reach the self-hosted Traccar server, even when:
|
||||
- The correct Device ID is set and registered on the server
|
||||
- The correct Server URL is configured
|
||||
- The tracking toggle is ON
|
||||
- The "Send Location" button appears to work
|
||||
|
||||
## Root Causes Identified
|
||||
|
||||
### Critical Bugs
|
||||
|
||||
#### 1. Heartbeat Never Fires (Process Isolation Issue)
|
||||
|
||||
**File**: `lib/bridge/location_bridge.dart` (Dart) and `android/app/src/main/kotlin/com/traccar/traccar_client/location/HeartbeatScheduler.kt`
|
||||
|
||||
**Problem**: The `HeartbeatWorker` runs in a separate process via Android WorkManager. When it executes, the static `onHeartbeatCallback` variable is always `null` because companion object static variables are not shared across process boundaries.
|
||||
|
||||
```kotlin
|
||||
// HeartbeatScheduler.kt
|
||||
class HeartbeatWorker(...) : Worker(...) {
|
||||
override fun doWork(): Result {
|
||||
onHeartbeatCallback?.invoke() // Always null!
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var onHeartbeatCallback: (() -> Unit)? = null // Not shared across processes
|
||||
}
|
||||
```
|
||||
|
||||
**Impact**: Heartbeat locations are never sent, causing the device to appear offline after initial connection wears off.
|
||||
|
||||
---
|
||||
|
||||
#### 2. ConnectivityReceiver Never Registered
|
||||
|
||||
**File**: `android/app/src/main/kotlin/com/traccar/traccar_client/service/LocationTrackingService.kt`
|
||||
|
||||
**Problem**: The `ConnectivityReceiver` is created in `onCreate()` but **never registered** with the system. The code creates the receiver but doesn't call `registerReceiver()`.
|
||||
|
||||
```kotlin
|
||||
// LocationTrackingService.kt - onCreate()
|
||||
connectivityReceiver = ConnectivityReceiver { online ->
|
||||
isNetworkAvailable = online
|
||||
logEvent("NETWORK_CHANGE", "Network: ${if (online) "online" else "offline"}")
|
||||
if (online) syncBufferedLocations()
|
||||
}
|
||||
// MISSING: registerReceiver(connectivityReceiver, intentFilter)
|
||||
```
|
||||
|
||||
**Impact**:
|
||||
- Network state is never detected
|
||||
- When the app goes offline, buffered locations are never synced when connectivity returns
|
||||
- App never knows if it's online or offline
|
||||
|
||||
---
|
||||
|
||||
#### 3. Timestamp Format Mismatch
|
||||
|
||||
**File**: `android/app/src/main/kotlin/com/traccar/traccar_client/network/TraccarHttpClient.kt`
|
||||
|
||||
**Problem**: The code sends timestamps as epoch milliseconds (e.g., `1704067200000`), but Traccar expects **ISO 8601 format** (e.g., `2024-01-01T00:00:00.000Z`).
|
||||
|
||||
```kotlin
|
||||
// TraccarHttpClient.kt:55-61
|
||||
return "$baseUrl/?" +
|
||||
// ...
|
||||
"×tamp=$timestamp" // Sends: 1704067200000
|
||||
// Should send: 2024-01-01T00:00:00.000Z
|
||||
```
|
||||
|
||||
**Impact**: Server may ignore or misinterpret timestamps, causing positions to not appear correctly on the timeline or be rejected entirely.
|
||||
|
||||
---
|
||||
|
||||
### Important Bugs (From Code Review)
|
||||
|
||||
#### 4. Memory Leak - Stream Subscription Never Cancelled
|
||||
|
||||
**File**: `lib/main_screen.dart:52-67`
|
||||
|
||||
```dart
|
||||
Future<void> _initLocationStream() async {
|
||||
// ...
|
||||
LocationBridge.locationUpdates.listen((location) { // Subscription created
|
||||
// ...
|
||||
});
|
||||
// MISSING: dispose() never cancels this subscription
|
||||
}
|
||||
```
|
||||
|
||||
**Impact**: Memory leak that accumulates over time, especially when navigating away and back to the screen.
|
||||
|
||||
---
|
||||
|
||||
#### 5. Settings Number Fields Never Save
|
||||
|
||||
**File**: `lib/settings_screen.dart:149-174`
|
||||
|
||||
**Problem**: `_buildNumberField()` uses `initialValue` (which creates an internal controller) and `onSaved` callback. However, `_saveSettings()` never calls `formKey.currentState.save()`, so the `onSaved` callbacks at lines 161-172 **never execute**.
|
||||
|
||||
```dart
|
||||
// settings_screen.dart
|
||||
Future<void> _saveSettings() async {
|
||||
await Preferences.setServerUrl(_serverUrlController.text);
|
||||
await Preferences.setDeviceId(_deviceIdController.text);
|
||||
// ... number fields use onSaved but form.save() is never called!
|
||||
await LocationBridge.updateConfig({...});
|
||||
}
|
||||
```
|
||||
|
||||
**Impact**: Distance Filter, Update Interval, and Heartbeat settings are silently ignored when saving. The UI shows the new values but they aren't persisted.
|
||||
|
||||
---
|
||||
|
||||
#### 6. Distance Filter May Block All Updates
|
||||
|
||||
**File**: `lib/bridge/location_bridge.dart` (Android side: `DistanceFilterProcessor.kt`)
|
||||
|
||||
**Problem**: With default `distanceFilter = 75` meters, if the device is stationary or moving less than 75m, **all locations are filtered out**. The `intervalFilter` only serves as a fallback when distance filter would reject, not as a primary interval mechanism.
|
||||
|
||||
**Impact**: Stationary devices or devices in slow-moving traffic may not send any location updates.
|
||||
|
||||
---
|
||||
|
||||
## Verification Steps
|
||||
|
||||
To diagnose where the flow breaks, check the **Status/Logs** screen in the app:
|
||||
|
||||
| Log Entry | Color | Meaning |
|
||||
|-----------|-------|---------|
|
||||
| `LOCATION` | Green | Location received from GPS |
|
||||
| `SYNC` | Cyan | Location successfully sent to server |
|
||||
| `ERROR` | Red | Failed to send location |
|
||||
| `FILTERED` | Grey | Location rejected by distance/interval filter |
|
||||
| `NETWORK_CHANGE` | White | Network state changed |
|
||||
|
||||
**Questions**:
|
||||
1. Do you see `LOCATION` entries?
|
||||
2. Do you see `SYNC` entries after `LOCATION`?
|
||||
3. Do you see any `ERROR` entries?
|
||||
4. Do you see `NETWORK_CHANGE` entries?
|
||||
|
||||
---
|
||||
|
||||
## Files Affected
|
||||
|
||||
### Dart/Flutter Files
|
||||
- `lib/main_screen.dart` - Memory leak, optimistic toggle
|
||||
- `lib/settings_screen.dart` - Number fields not saving
|
||||
- `lib/status_screen.dart` - OK
|
||||
- `lib/preferences.dart` - OK
|
||||
- `lib/bridge/location_bridge.dart` - OK
|
||||
- `lib/main.dart` - OK
|
||||
|
||||
### Android/Kotlin Files
|
||||
- `android/.../location/HeartbeatScheduler.kt` - Heartbeat never fires
|
||||
- `android/.../service/LocationTrackingService.kt` - ConnectivityReceiver not registered
|
||||
- `android/.../network/TraccarHttpClient.kt` - Timestamp format wrong
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The device appears offline because:
|
||||
|
||||
1. **Heartbeat locations are never sent** - WorkManager process isolation breaks the callback mechanism
|
||||
2. **Buffered locations are never synced** - ConnectivityReceiver was never registered
|
||||
3. **Timestamps may be malformed** - Server may reject positions due to timestamp format
|
||||
|
||||
**Recommendation**: Fix the three critical bugs (Heartbeat, ConnectivityReceiver, Timestamp) first, then re-test. Check the Status/Logs screen to confirm which stage the flow is breaking at.
|
||||
Loading…
Add table
Add a link
Reference in a new issue