# 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 _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 _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.