Skip to content

fix(android): report compass heading in location updates - #4350

Merged
mfazekas merged 1 commit into
mainfrom
fix/android-location-heading
Oct 13, 2026
Merged

mfazekas merged 1 commit into
mainfrom
fix/android-location-heading

Conversation

@mfazekas

Copy link
Copy Markdown
Contributor

Description

Fixes #4063

On Android heading and course were both filled from the GPS bearing, so a stationary device reported no heading and a moving one reported its course as heading. Android now sends course from the location bearing and heading from the Mapbox location plugin's compass (DefaultLocationProvider with PuckBearing.HEADING, the same source the puck uses). This matches iOS, where heading comes from the HeadingProvider.

The compass runs only while the location module is started (it is stopped on stop() and when the app is paused). Like iOS, a heading change also emits an update with the last location. Mapbox throttles the compass to 2 Hz, and changes under 1° are skipped, matching CLLocationManager's default headingFilter. DefaultLocationProvider also opens its own location request through Mapbox's LocationService. That request uses the same high-accuracy, 1 s settings as ours, so the OS merges the two and the GPS hardware does no extra work.

Behaviour change: on Android, heading now means the compass heading (0–360). Code that relied on it being the direction of travel should use course. Like the Mapbox puck, the value is relative to magnetic north (no declination correction).

Checklist

  • I've read CONTRIBUTING.md
  • I updated the doc/other generated code with running yarn generate in the root folder
  • I have tested the new feature on /example app.
    • In V11 mode/ios
    • In New Architecture mode/ios
    • In V11 mode/android
    • In New Architecture mode/android
  • I added/updated a sample - if a new feature was implemented (/example)

Screenshot OR Video

Evidence from an Android emulator: locations were set with adb emu geo fix, and the compass was turned by rotating the virtual magnetic field (adb emu sensor set magnetic-field).

Before, stationary: no heading at all.

{"longitude":-74.00597,"latitude":40.7142683,"accuracy":3.67,"altitude":5,"speed":0}

Before, moving NE: heading equals course (both GPS bearing).

{"latitude":40.7146542,"heading":37.04,"course":37.04,"speed":21.2,...}

After, stationary, compass turned 0 → 90 → 200 → 300:

heading=0.0 → 15.8 → 68.9 → 88.3 → 89.3 → 168.9 → 199.8 → 272.5 → 298.9 → 300.0   course=none speed=0

After, moving NE with the device pointing west:

lat=40.71465 heading=271.0 course=37.2 speed=21.9
lat=40.71526 heading=270.6 course=37.1 speed=36.1
lat=40.71647 heading=270.6 course=37.2 speed=26.3

After the screen unmounts, the LocationCompassEngine sensor registration is removed (dumpsys sensorservice).

Component to reproduce the issue you're fixing

import React, { useState } from 'react';
import { Text, View } from 'react-native';
import { MapView, Camera, UserLocation } from '@rnmapbox/maps';

const BugReportExample = () => {
  const [last, setLast] = useState('');
  return (
    <View style={{ flex: 1 }}>
      <MapView style={{ flex: 1 }}>
        <Camera followUserLocation followZoomLevel={14} />
        <UserLocation
          showsUserHeadingIndicator
          visible
          onUpdate={(location) => {
            console.log(`[REPRO onUpdate] ${JSON.stringify(location.coords)}`);
            setLast(JSON.stringify(location.coords));
          }}
        />
      </MapView>
      <Text>{last}</Text>
    </View>
  );
};

export default BugReportExample;

Android filled both heading and course from the GPS bearing, so stationary
fixes had no heading and moving ones reported the course as heading. Send
course from the location bearing and heading from the Mapbox location
plugin's compass (DefaultLocationProvider with PuckBearing.HEADING), only
while location updates are subscribed.

Fixes #4063
@mfazekas
mfazekas merged commit 4b99fbd into main Oct 13, 2026
9 checks passed
@mfazekas
mfazekas deleted the fix/android-location-heading branch October 13, 2026 03:09

This branch was successfully deployed

1 active deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: [ANDROID] onUpdate in <UserLocation/> is not coming "heading" value

1 participant