mapbox / mapbox/mapbox-maps-android
Unexpected Camera Shift After Disabling Location Tracking
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 578
- Forks
- 161
- PR merge metrics
- No merged PRs in 30d
Description
Environment
- Devices affected: Various Android devices, including Poco M6 Pro (Android 14)
- Maps SDK Version: Mainly 11.2.1, but also reproduced on 11.7.2
Observed behavior and steps to reproduce
There is an unexpected camera behavior when using location tracking
val followPuckViewportState = viewport.makeFollowPuckViewportState(
FollowPuckViewportStateOptions.Builder()
.pitch(45.0)
.bearing(FollowPuckViewportStateBearing.SyncWithLocationPuck)
.zoom(17.0)
.build()
)
viewport.transitionTo(
followPuckViewportState,
viewport.makeDefaultViewportTransition(
DefaultViewportTransitionOptions.Builder().maxDurationMs(500).build()
)
)
Steps to reproduce:
- Enable location tracking with the code above (camera will move to user's last coordinate).
- Do not receive any coordinate updates.
- Disable location tracking by manually moving the camera.
- Get new coordinate.
Observed behavior:
The camera returns to the previous location as if location tracking was still active (but with the previous coordinate, not the new coordinate). After this, if we receive new coordinates, then everything is as expected: location tracking is disabled.
Expected behavior
If we disable location tracking (either by moving the camera or by calling viewport.idle()), then it no longer affects the camera in any way, all internal deferred actions are cancelled in ViewportPlugin.
Notes / preliminary analysis
In the debug I saw that FollowPuckViewportStateImpl.stopUpdatingCamera() is called, in which removeIndicatorListenerIfNeeded() is called. In removeIndicatorListenerIfNeeded() there is such code
private fun removeIndicatorListenerIfNeeded() {
if (isObservingLocationUpdates && dataSourceUpdateObservers.isEmpty() && !isFollowingStateRunning) {
locationComponent.removeOnIndicatorPositionChangedListener(indicatorPositionChangedListener)
locationComponent.removeOnIndicatorBearingChangedListener(indicatorBearingChangedListener)
isObservingLocationUpdates = false
// when unsubscribed from the location updates, we don't want to keep an outdated location, so
// when user transition to the FollowPuckViewportState, there wouldn't be any unintentional jump.
lastBearing = null
lastLocation = null
}
}
dataSourceUpdateObservers is not empty.
If replace
viewport.makeDefaultViewportTransition(
DefaultViewportTransitionOptions.Builder().maxDurationMs(500).build()
)
with
viewport.makeImmediateViewportTransition()
then there is no such problem. And dataSourceUpdateObservers is empty on stopUpdatingCamera().
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with FollowPuckViewportStateImpl.stopUpdatingCamera() and removeIndicatorListenerIfNeeded(), then inspect how DefaultViewportTransition handles deferred actions in ViewportPlugin. Reproduce the sequence with a 500 ms transition and compare it with makeImmediateViewportTransition(); done means disabling tracking prevents the camera from returning to the previous location when a later coordinate arrives.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100