Signal Heatmaps
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/kotlin/com/shadowcheck/mobile/domain/model/HeatmapData.kt
- app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/HeatmapScreen.kt
- app/src/main/kotlin/com/shadowcheck/mobile/ui/screens/maps/HeatmapScreen.kt
- app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/MapScreen.kt
- app/src/main/kotlin/com/shadowcheck/mobile/domain/model/UnifiedSighting.kt
Signal Heatmaps in ShadowCheck Mobile provide a multi-dimensional visualization of wireless signal density and temporal activity. This system transforms raw sighting data from WiFi, Bluetooth, and Cellular networks into spatial and temporal representations, allowing users to identify patterns of signal congestion, coverage gaps, and device activity over time.
The feature is divided into two primary modes: Spatial Heatmaps, which use geographic coordinates to map signal intensity across physical locations, and Temporal Heatmaps, which visualize signal sightings across a 24-hour daily cycle over a week-long period.
Sources: app/src/main/kotlin/com/shadowcheck/mobile/domain/model/HeatmapData.kt, app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/HeatmapScreen.kt
Spatial Heatmap Generation
The spatial heatmap system aggregates raw network data into a grid-based coordinate system to calculate signal density and intensity.
Heatmap Data Structures
The core data model for spatial heatmaps consists of HeatmapPoint and HeatmapLayer. Each point represents a summarized grid cell containing geographic coordinates, signal intensity (normalized 0.0 to 1.0), average signal strength, and the total count of networks or devices found in that area.
| Field | Type | Description |
|---|---|---|
latitude | Double | Geographic latitude of the grid center. |
longitude | Double | Geographic longitude of the grid center. |
intensity | Float | Normalized value (0.0 to 1.0) representing density. |
signalStrength | Int | Average signal strength (dBm) within the cell. |
networkCount | Int | Number of distinct sightings in the grid cell. |
Sources: app/src/main/kotlin/com/shadowcheck/mobile/domain/model/HeatmapData.kt:5-11
Generation Logic
The HeatmapGenerator object contains specialized functions for generating layers based on the radio type. Each function uses a gridSize to group sightings:
- WiFi: Default grid size of 0.0001 (~11 meters). Intensity is calculated as
count / 10f. - Bluetooth: Default grid size of 0.0001 (~11 meters). Intensity is calculated as
count / 5f. - Cellular: Default grid size of 0.001 (~111 meters). Intensity is calculated as
count / 3f.
Sources: app/src/main/kotlin/com/shadowcheck/mobile/domain/model/HeatmapData.kt:20-80
The diagram above illustrates the data transformation pipeline from database entities to rendered map layers.
Sources: app/src/main/kotlin/com/shadowcheck/mobile/domain/model/HeatmapData.kt:23-45
Temporal Heatmap System
Temporal heatmaps visualize "Activity by Day/Hour," allowing for the analysis of network presence patterns across a specific week.
Temporal Logic and State
The TemporalHeatmapCanvas uses a 7x24 grid representing the days of the week and hours of the day. Data is fetched from the database based on a weekOffset, which determines the start and end timestamps for the query.
- Days: Sunday (0) through Saturday (6).
- Hours: 0 to 23.
- Filtering: Users can filter the heatmap by
selectedType(WiFi, Bluetooth, Cellular) and search for specific SSIDs or BSSIDs.
Sources: app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/HeatmapScreen.kt:34-60
Visual Intensity Levels
Intensity is rendered using a color-coded scale based on the relative count of sightings in a specific time slot compared to the maxCount of the entire week.
| Intensity Level | Color Hex | Description |
|---|---|---|
| Empty | #263238 | No activity recorded. |
| Low | #1A237E | < 25% of max weekly activity. |
| Medium | #0D47A1 | 25% - 50% of max weekly activity. |
| High | #01579B | 50% - 75% of max weekly activity. |
| Very High | #006064 | > 75% of max weekly activity. |
Sources: app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/HeatmapScreen.kt:180-205
Map Integration and Rendering
The application supports rendering these heatmaps using both GoogleMap and Mapbox providers, configured in the settings.
Layer Visualization
In the HeatmapScreen (Map implementation), users can toggle between WiFi, Bluetooth, and Cellular layers. The visualization utilizes a color gradient based on the intensity of the HeatmapPoint.
This sequence shows how user interactions trigger database queries and subsequent map updates.
Sources: app/src/main/kotlin/com/shadowcheck/mobile/ui/screens/maps/HeatmapScreen.kt:35-55, app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/MapScreen.kt:45-80
Color Gradients by Radio Type
Different radio types utilize distinct color schemes to help differentiate between overlapping signal sources:
- WiFi: Green (Low) → Yellow (Medium) → Red (High).
- Bluetooth: Green (Low) → Cyan (Medium) → Blue (High).
- Cellular: Green (Low) → Orange (Medium) → Magenta (High).
Sources: app/src/main/kotlin/com/shadowcheck/mobile/ui/screens/maps/HeatmapScreen.kt:145-170
Implementation Details
Database Interaction
The heatmap screens rely on Flow updates from the ShadowCheckDatabase. Sightings are grouped and filtered in the LaunchedEffect block of the UI components.
// Example of fetching temporal data
val filtered = allNetworks.filter {
it.timestamp in startOfWeek..endOfWeek
}
timeSlots = filtered.groupBy {
Pair(getDayOfWeek(it.timestamp), getHourOfDay(it.timestamp))
}.mapValues { it.value.size }
Sources: app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/HeatmapScreen.kt:45-55
Grid Calculation
The spatial grid logic relies on integer division of coordinates by the grid size to create unique buckets for location aggregation.
.groupBy {
Pair(
(it.latitude / gridSize).toInt(),
(it.longitude / gridSize).toInt()
)
}
Sources: app/src/main/kotlin/com/shadowcheck/mobile/domain/model/HeatmapData.kt:25-30
Signal Heatmaps serve as a critical diagnostic tool in ShadowCheck Mobile, converting millions of potential sighting records into actionable visual intelligence for both geographic and time-based signal analysis.