Skip to content

fix(android): defer startup camera change events - #4355

Open
RobJacobson wants to merge 5 commits into
rnmapbox:mainfrom
RobJacobson:codex/fix-4213-camera-event-tests
Open

RobJacobson wants to merge 5 commits into
rnmapbox:mainfrom
RobJacobson:codex/fix-4213-camera-event-tests

Conversation

@RobJacobson

@RobJacobson RobJacobson commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Description

Fixes #4213

Android may report a camera change before the map's attachment callbacks apply Camera.defaultSettings. Buffer startup notifications and dispatch one event from the current camera state after those callbacks complete. Subsequent camera changes continue to emit normally. The buffering state lives in a private startupCameraEvents object inside RNMBXMapView.

Reproducer evidence

Using the issue's configured center [-93.265, 44.9778]:

  • Before: startup events reported [0, 0], then [-93.265, 44.9778].
  • After: the startup event reported [-93.26500000000003, 44.9778]; no [0, 0] event was emitted.

Validation

The original PR head (edb1099) and the refactored implementation (aa3161ff) passed the same ten-scenario Android emulator harness. Both APKs produced identical center/zoom event sequences. Verification used React Native 0.84.1, Mapbox Maps SDK 11.23.1, Fabric, and the Android example app with an empty style.

  • Four map mounts each emitted one startup event at the configured center [-93.265, 44.9778] and zoom 6, without an initial [0, 0] event.
  • Six further scenarios passed: valid defaults at [0, 0], no Camera, Camera without defaults, controlled camera props alongside defaults, later moves to [0, 0] and Tokyo, and delayed Camera mounting.
  • A temporary Kotlin check compared the original helper with the anonymous object extracted from RNMBXMapView. All 4,096 twelve-operation sequences of camera-change notifications and readiness calls matched.
  • ./gradlew :app:assembleDebug :rnmapbox_maps:testDebugUnitTest -PreactNativeArchitectures=arm64-v8a passed, including all 11 remaining native unit tests.
  • node node_modules/jest/bin/jest.js --runInBand passed all 164 tests across 25 suites.
  • ESLint completed without errors; existing warnings remain.

The issue report's React Native 0.83.6 and Mapbox Maps SDK 11.20.1 were not rerun. Temporary verification code and configuration are excluded from the commit.

Checklist

  • I've read CONTRIBUTING.md.
  • I updated the doc/other generated code with running yarn generate in the root folder (not applicable to this native-only change).
  • 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 (bug fix; no sample API added).

Screenshot OR Video

This is a native event timing fix; emulator logs above show the before/after behavior.

Component to reproduce the issue

<Mapbox.MapView
  style={{ flex: 1 }}
  onCameraChanged={(event) => {
    const [longitude, latitude] = event.properties.center;
    console.log(`COORDS ->> lng: ${longitude} lat: ${latitude}`);
  }}
>
  <Mapbox.Camera
    defaultSettings={{ centerCoordinate: [-93.265, 44.9778] }}
  />
</Mapbox.MapView>

- Hold startup camera notifications until attachment callbacks finish applying the initial camera
- Emit the current camera once after initialization and preserve subsequent camera events
- Keep maps without a Camera and valid zero-coordinate camera positions working
- Buffer startup camera notifications until camera setup is ready
- Coalesce startup notifications and preserve later camera changes
- Route native camera notifications through a focused readiness gate
- Dispatch the latest camera once attachment callbacks finish
- Verify startup notifications coalesce until camera setup is ready
- Verify subsequent notifications and empty startup behave correctly

@mfazekas mfazekas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this fixes #4213; we verified it on an emulator, including no-Camera, delayed Camera, re-attach and pans during startup. Splitting this out of RNMBXMapView makes sense, but a separate file and test for two flags is more than it needs; please make it a private anonymous object in RNMBXMapView (private val startupCameraEvents = object { … } calling sendCameraChangedEvents() directly) and drop CameraChangeEventGate.kt and its test. Please also shorten the attach comment to one line, e.g. // Camera.addToMap applies defaultSettings in the attach callbacks (#4213).

- Keep startup camera buffering in a private anonymous MapView object
- Remove the standalone event gate and its unit test
- Dispatch camera events directly and shorten the attachment comment

This branch was successfully deployed

1 active (outdated) 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: onCameraChanged fires with [0,0] on launch

2 participants