Repository navigation
fix(android): preserve camera updates during long presses - #4358
Open
RobJacobson wants to merge 3 commits into
Open
RobJacobson wants to merge 3 commits into
RobJacobson wants to merge 3 commits into
Conversation
- Cancel native long-press gestures before queued camera updates - Consume remaining touch events until release and restore panning on new touches - Add regression tests for gesture ownership and camera-update ordering
- Cancel active map long presses before moveBy and scaleBy - Add a native touch regression covering camera motion and gesture cleanup - Add the long-press camera example and regenerate its documentation links
- Add a permanent native UI suite for all five long-press camera modes - Verify relative camera destinations, zoom, release stability, and the next pan - Add the LongPressCamera Xcode scheme and contributor run instructions
RobJacobson
marked this pull request as ready for review
October 15, 2026 03:32
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Addresses the Android camera behavior reported in #2738.
Finger movement after a long press can override a camera command started by
onLongPress. Before a queued camera update,moveBy, orscaleBy, the wrapper cancels the active native map long press and consumes its remaining touch events until release. A fresh touch pans normally, and long presses without camera commands keep normal panning.The relative camera methods use the same cancellation helper as the shared camera queue. Existing callers work without changes. The unchanged iOS implementation passes the held-finger drift scenario on the current SDK.
Validation
Validated on 2026-10-14 with Mapbox Maps SDK 11.23.1, React Native 0.84.1, and the New Architecture:
MapViewexample link.flyTo, eased and immediatesetCameramoves,moveBy,scaleBy, panning on the next touch, and long presses without camera commands.super.dispatchTouchEvent(cancel)omitted fails the integration test:gestureActiveremains true through the animated camera move. That build still consumes the remaining touches.flyTo, eased and immediatesetCamera,moveBy, andscaleBy. Each case checks held-finger drift, camera readings after release, and panning on the next touch. Relative cases also compare against a stationary run;scaleBymust reach zoom 17 from zoom 16.moveBy, and a scale factor of one failsscaleBy.The Android regression holds a touch for four seconds while moving 24 physical pixels. It samples the camera before release and compares it again after release. Relative commands must retain their completed position;
scaleBymust reach zoom 17 from zoom 16.moveBy0.0000344degrees after the held samplescaleByThe iOS test holds for 1.5 seconds, drifts eight screen points at eight points per second, then holds for another three seconds. Both held and released positions must be within
0.000001degrees per coordinate component of the expected destination. The relative cases compare against a stationary run of the same command;scaleBymust reach zoom 17. All five cases also verify panning on the next touch.Simulator runs opened the committed example through a temporary entry and isolated dependency/Babel configuration. Android packaging reused unchanged Reanimated and Worklets native binaries from the baseline app while rebuilding the map code. The iOS 27 run reused the temporary scene bootstrap from the original validation. These temporary setup changes are absent from the PR.
Physical devices and repository-wide TypeScript checks were not run.
Checklist
CONTRIBUTING.md.scripts/autogenerate.mjsentry point behindyarn generate.LongPressCameraXcode UI test scheme.Evidence
The original queue-fix screenshots remain available: before and after.
Component to reproduce the issue
Build and run the example app, then open Camera > Long Press Camera. Select a camera mode, long press away from the center, and keep moving the held finger slightly. The camera command should finish and retain its position. Lift and pan again to verify that the next touch works. Select none to verify normal long-press panning without a camera command.
The self-contained component is committed at example/src/examples/Camera/LongPress.js. Run the Android regression separately against a running example app, with
adbonPATH:The serial argument is optional when only one Android device is connected. The runner uses Python's standard library and Android's native input and UI automation tools, with no added dependencies.
Run the permanent iOS suite against an installed example app using the instructions in CONTRIBUTING.md. The
LongPressCamerascheme builds the native UI test runner and uses real simulator touch events. It runs separately fromyarn testand Detox screenshots.