Skip to content

Fix Android issue with isUserInteraction always returning true when location puck is pulsing#4222

Open
KijongHan wants to merge 3 commits into
rnmapbox:mainfrom
KijongHan:fix/issue-with-isUserInteraction-always-returning-true-when-location-puck-is-pulsing
Open

Fix Android issue with isUserInteraction always returning true when location puck is pulsing#4222
KijongHan wants to merge 3 commits into
rnmapbox:mainfrom
KijongHan:fix/issue-with-isUserInteraction-always-returning-true-when-location-puck-is-pulsing

Conversation

@KijongHan
Copy link
Copy Markdown
Contributor

Description

Fixes #3805

Fixes Android bug where onRegionIsChanging's properties.isUserInteraction was stuck true whenever <LocationPuck pulsing="default" /> was mounted, even if there were no user action. Root cause: the LocationComponent's pulsing animator keeps the map perpetually non-idle (as reported here), so Mapbox's MapIdle event never fires.

This means that CameraChangeTracker never cleared user gesture state as addOnMapIdleListener never fired if that <LocationPuck /> component was mounted. Fix was to use the new custom MapSteady event already introduced here #4074

Changes

  • Update CameraChangeTracker and replace single reason: CameraChangeReason field with reasonByGesture: Map<MapGestureType, CameraChangeReason> so concurrent move/scale/rotate gestures don't cause race conditions.
  • Decouple MapSteadyDetector from RNMBXCameraGestureObserver and use this custom event from RNMBXMapView to drive clearing the CameraChangeTracker state which corrects the downstream propagation to properties.isUserInteraction
  • Minor refactor so MapGestureType is promoted to shared enum

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 (no, but shouldn't be affected)
    • In New Architecture mode/ios (no, but shouldn't be affected)
    • In V11 mode/android
    • In New Architecture mode/android
  • I added/updated a sample - if a new feature was implemented (/example)

Component to reproduce the issue you're fixing

Just pasting the same repro code snippet provided by the original issue

import { useEffect, useRef } from 'react';
import {
    MapView,
    ShapeSource,
    LineLayer,
    Camera,
    LocationPuck,
} from '@rnmapbox/maps';
import type { CameraRef } from '../../../src/components/Camera';

const aLine = {
    type: 'LineString',
    coordinates: [
        [-74.00597, 40.71427],
        [-74.00697, 40.71527],
    ],
}

const BugReportExample = () => {

    const mapCameraRef = useRef<CameraRef>(null)
    const locationPuck = true // Set this to false to hide the location puck. The issue only presents itself when the locationPuck is shown (and more specifically when this is set pulsing={"default"})

    useEffect(() => {
        // Re-center the map every 5 seconds. When this is done, isUserInteraction should log as false (but it doesn't when locationPuck is true)
        const interval = setInterval(() => {
            mapCameraRef.current?.setCamera({
                centerCoordinate: [-74.00597, 40.71427],
                animationDuration: 1000,
                animationMode: 'linearTo',
            })
        }, 5_000)

        return () => {
            clearInterval(interval)
        }

    }, [])

    const regionIsChanging = (region: any) => {
        console.log("isUserInteraction:", region.properties.isUserInteraction)
    }

    return (
        <MapView style={{ flex: 1 }} onRegionIsChanging={regionIsChanging}>
            <Camera ref={mapCameraRef} centerCoordinate={[-74.00597, 40.71427]} zoomLevel={14} />
            <ShapeSource id="idStreetLayer" shape={aLine as any}>
                <LineLayer id="idStreetLayer" />
            </ShapeSource>
            {locationPuck ? <LocationPuck puckBearingEnabled={true} puckBearing="heading" pulsing={"default"} /> : null}
        </MapView>
    )
}

export default BugReportExample;

KijongHan added 3 commits June 2, 2026 10:03
… gestures being tracked that could lead to race conditions
…t map steady event detection is decoupled and can be minimally reused from RNMBXMapView
…ent kotlin components

- refactor MapSteadyDetector so that it uses enum instead of magic strings
@KijongHan KijongHan requested a deployment to CI with Mapbox Tokens June 1, 2026 22:36 — with GitHub Actions Waiting
@KijongHan KijongHan requested a deployment to CI with Mapbox Tokens June 1, 2026 22:36 — with GitHub Actions Waiting
@KijongHan KijongHan requested a deployment to CI with Mapbox Tokens June 1, 2026 22:36 — with GitHub Actions Waiting
@KijongHan KijongHan changed the title Fix issue with isUserInteraction always returning true when location puck is pulsing Fix Android issue with isUserInteraction always returning true when location puck is pulsing Jun 1, 2026
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]: isUserInteraction is always true when locationPuck is shown on Android

1 participant