set default move gesture threshold to a small non-zero value (#3573)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Tobias Zwick
2025-06-23 18:36:33 +02:00
committed by GitHub
parent 1899cde3bd
commit 2e0b464849
5 changed files with 42 additions and 52 deletions

View File

@@ -31,6 +31,8 @@
- [core] Fix memory access violation exception in vector_tile_data.cpp [#632](https://github.com/maplibre/maplibre-native/pull/632)
- [iOS] Fix a bug where the compass was determined to be misplaced when hidden [#498](https://github.com/maplibre/maplibre-native/pull/498).
- [core] `MaptilerFileSource` renamed to `MBTilesFileSource` [#198](https://github.com/maplibre/maplibre-native/pull/198).
- [android] Fix `OnMoveListener::onMoveBegin` was always called even on a simple tap. [#2792](https://github.com/maplibre/maplibre-native/issues/2792)
In case you rely on the old behavior, call `maplibreMap.getGesturesManager().getMoveGestureDetector().setMoveThreshold(0f)` to restore it
## maps-v1.6.0

View File

@@ -314,7 +314,8 @@ final class LocationCameraController {
if (isLocationTracking()) {
moveGestureDetector.setMoveThreshold(options.trackingInitialMoveThreshold());
} else {
moveGestureDetector.setMoveThreshold(0f);
float initialMoveThreshold = initialGesturesManager.getMoveGestureDetector().getMoveThreshold();
moveGestureDetector.setMoveThreshold(initialMoveThreshold);
moveGestureDetector.setMoveThresholdRect(null);
}
}

View File

@@ -169,8 +169,15 @@ final class MapGestureDetector {
androidGesturesManager.setMutuallyExclusiveGestures(shoveScaleSet, shoveRotateSet, ScaleLongPressSet);
}
// If this was 0°, every shove gesture (for tilting the map) would be detected as also a rotate
androidGesturesManager.getRotateGestureDetector().setAngleThreshold(3f);
// If this was 0 (the default), a simple tap would also be detected as a move. A (very) small
// move threshold solves this issue, while not making the map feel "sticky". (See #2792)
androidGesturesManager.getMoveGestureDetector().setMoveThresholdResource(R.dimen.maplibre_minimum_move_threshold);
gesturesManager = androidGesturesManager;
gesturesManager.getRotateGestureDetector().setAngleThreshold(3f);
}
/**

View File

@@ -24,6 +24,10 @@
<!--Screen density constant to adjust gesture's velocityXY thresholds-->
<dimen name="maplibre_density_constant">0.29dp</dimen>
<!--Threshold until a move is detected as such-->
<dimen name="maplibre_minimum_move_threshold">4dp</dimen>
<!--Threshold until a move is detected as such during camera location tracking -->
<dimen name="maplibre_locationComponentTrackingInitialMoveThreshold">25dp</dimen>
<dimen name="maplibre_locationComponentTrackingMultiFingerMoveThreshold">400dp</dimen>
</resources>

View File

@@ -94,7 +94,7 @@ class LocationCameraControllerTest {
camera.initializeOptions(options)
camera.cameraMode = CameraMode.NONE
Mockito.verify(moveGestureDetector, Mockito.times(2)).moveThreshold =
0f // one for initialization
MOVEMENT_THRESHOLD // one for initialization
Mockito.verify(moveGestureDetector, Mockito.times(2)).moveThresholdRect =
null // one for initialization
}
@@ -698,9 +698,7 @@ class LocationCameraControllerTest {
@Test
fun gesturesManagement_enabled() {
val maplibreMap = Mockito.mock(MapLibreMap::class.java)
val initialGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
val initialGesturesManager = buildInitialGesturesManager()
val internalGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
@@ -717,9 +715,7 @@ class LocationCameraControllerTest {
@Test
fun gesturesManagement_disabled() {
val maplibreMap = Mockito.mock(MapLibreMap::class.java)
val initialGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
val initialGesturesManager = buildInitialGesturesManager()
val internalGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
@@ -736,9 +732,7 @@ class LocationCameraControllerTest {
@Test
fun gesturesManagement_optionNotChangedInitial() {
val maplibreMap = Mockito.mock(MapLibreMap::class.java)
val initialGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
val initialGesturesManager = buildInitialGesturesManager()
val internalGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
@@ -756,9 +750,7 @@ class LocationCameraControllerTest {
@Test
fun gesturesManagement_optionNotChangedInternal() {
val maplibreMap = Mockito.mock(MapLibreMap::class.java)
val initialGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
val initialGesturesManager = buildInitialGesturesManager()
val internalGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
@@ -792,7 +784,7 @@ class LocationCameraControllerTest {
Mockito.`when`(options.trackingMultiFingerProtectedMoveArea()).thenReturn(multiFingerArea)
camera.initializeOptions(options)
camera.onMoveListener.onMoveBegin(moveGestureDetector)
Mockito.verify(moveGestureDetector, Mockito.times(2)).moveThreshold = 0f
Mockito.verify(moveGestureDetector, Mockito.times(2)).moveThreshold = MOVEMENT_THRESHOLD
Mockito.verify(moveGestureDetector, Mockito.times(2)).moveThresholdRect = null
}
@@ -876,12 +868,8 @@ class LocationCameraControllerTest {
Mockito.verify(moveGestureDetector, Mockito.times(2)).interrupt()
// verify that threshold are reset
val moveThresholdCaptor = ArgumentCaptor.forClass(
Float::class.java
)
Mockito.verify(moveGestureDetector, Mockito.atLeastOnce()).moveThreshold =
moveThresholdCaptor.capture()
org.junit.Assert.assertEquals(java.lang.Float.valueOf(0f), moveThresholdCaptor.value)
MOVEMENT_THRESHOLD
}
@Test
@@ -973,18 +961,9 @@ class LocationCameraControllerTest {
Mockito.verify(moveGestureDetector, Mockito.times(2)).interrupt()
// verify that threshold are reset
val moveThresholdCaptor = ArgumentCaptor.forClass(
Float::class.java
)
Mockito.verify(moveGestureDetector, Mockito.atLeastOnce()).moveThreshold =
moveThresholdCaptor.capture()
org.junit.Assert.assertEquals(java.lang.Float.valueOf(0f), moveThresholdCaptor.value)
val areaCaptor = ArgumentCaptor.forClass(
RectF::class.java
)
Mockito.verify(moveGestureDetector, Mockito.atLeastOnce()).moveThresholdRect =
areaCaptor.capture()
org.junit.Assert.assertNull(areaCaptor.value)
MOVEMENT_THRESHOLD
Mockito.verify(moveGestureDetector, Mockito.atLeastOnce()).moveThresholdRect = null
}
@Test
@@ -1911,9 +1890,6 @@ class LocationCameraControllerTest {
val onCameraMoveInvalidateListener = Mockito.mock(
OnCameraMoveInvalidateListener::class.java
)
val initialGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
val internalGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
@@ -1923,7 +1899,7 @@ class LocationCameraControllerTest {
moveGestureDetector,
onCameraTrackingChangedListener,
onCameraMoveInvalidateListener,
initialGesturesManager,
buildInitialGesturesManager(),
internalGesturesManager
)
}
@@ -1955,9 +1931,6 @@ class LocationCameraControllerTest {
val onCameraMoveInvalidateListener = Mockito.mock(
OnCameraMoveInvalidateListener::class.java
)
val initialGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
val internalGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
@@ -1967,7 +1940,7 @@ class LocationCameraControllerTest {
moveGestureDetector,
onCameraTrackingChangedListener,
onCameraMoveInvalidateListener,
initialGesturesManager,
buildInitialGesturesManager(),
internalGesturesManager
)
}
@@ -1985,9 +1958,6 @@ class LocationCameraControllerTest {
val onCameraMoveInvalidateListener = Mockito.mock(
OnCameraMoveInvalidateListener::class.java
)
val initialGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
val internalGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
@@ -1997,7 +1967,7 @@ class LocationCameraControllerTest {
moveGestureDetector,
onCameraTrackingChangedListener,
onCameraMoveInvalidateListener,
initialGesturesManager,
buildInitialGesturesManager(),
internalGesturesManager
)
}
@@ -2034,9 +2004,6 @@ class LocationCameraControllerTest {
val onCameraMoveInvalidateListener = Mockito.mock(
OnCameraMoveInvalidateListener::class.java
)
val initialGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
val internalGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
@@ -2046,7 +2013,7 @@ class LocationCameraControllerTest {
moveGestureDetector,
onCameraTrackingChangedListener,
onCameraMoveInvalidateListener,
initialGesturesManager,
buildInitialGesturesManager(),
internalGesturesManager
)
}
@@ -2066,9 +2033,6 @@ class LocationCameraControllerTest {
val onCameraMoveInvalidateListener = Mockito.mock(
OnCameraMoveInvalidateListener::class.java
)
val initialGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
val internalGesturesManager = Mockito.mock(
AndroidGesturesManager::class.java
)
@@ -2078,7 +2042,7 @@ class LocationCameraControllerTest {
moveGestureDetector,
onCameraTrackingChangedListener,
onCameraMoveInvalidateListener,
initialGesturesManager,
buildInitialGesturesManager(),
internalGesturesManager
)
locationCameraController.setEnabled(true)
@@ -2113,6 +2077,18 @@ class LocationCameraControllerTest {
)
}
private fun buildInitialGesturesManager(): AndroidGesturesManager {
val moveGestureDetector = Mockito.mock<MoveGestureDetector>()
// return just "some" value
Mockito.`when`(moveGestureDetector.moveThreshold).thenReturn(MOVEMENT_THRESHOLD)
val manager = Mockito.mock<AndroidGesturesManager>()
Mockito.`when`(manager.moveGestureDetector).thenReturn(moveGestureDetector)
return manager
}
private val MOVEMENT_THRESHOLD = 10f
private fun <T> getAnimationListener(
@MapLibreAnimator.Type animatorType: Int,
holders: Set<AnimatorListenerHolder>