Skip to content

Commit 097290f

Browse files
dzinadgithub-actions[bot]
authored andcommitted
NAVAND-5894: use camera animation hints
GitOrigin-RevId: 015c5f04ac0542eff68e03540cb7a4e660251181
1 parent f47c99f commit 097290f

File tree

10 files changed

+154
-5
lines changed

10 files changed

+154
-5
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Optimized camera animations that involve significant zoom change.

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/camera/NavigationCamera.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ internal constructor(
182182
viewportDataSource,
183183
SimplifiedFrameAnimatorsCreator(
184184
cameraPlugin,
185+
mapboxMap,
185186
stateTransition,
186187
simplifiedUpdateFrameTransitionProvider,
187188
),
@@ -212,12 +213,13 @@ internal constructor(
212213
true -> {
213214
SimplifiedFrameAnimatorsCreator(
214215
cameraPlugin,
216+
mapboxMap,
215217
stateTransition,
216218
DefaultSimplifiedUpdateFrameTransitionProvider(mapboxMap, cameraPlugin),
217219
)
218220
}
219221
false -> {
220-
FullFrameAnimatorsCreator(stateTransition, cameraPlugin)
222+
FullFrameAnimatorsCreator(stateTransition, cameraPlugin, mapboxMap)
221223
}
222224
}
223225
}

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/camera/transition/FullAnimatorSet.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,22 @@ import android.animation.Animator
44
import android.animation.Animator.AnimatorListener
55
import android.animation.AnimatorSet
66
import android.animation.ValueAnimator
7+
import com.mapbox.maps.MapboxExperimental
8+
import com.mapbox.maps.MapboxMap
79
import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin
10+
import com.mapbox.maps.plugin.animation.calculateCameraAnimationHint
811
import java.util.concurrent.CopyOnWriteArrayList
912

1013
internal class FullAnimatorSet(
1114
private val cameraPlugin: CameraAnimationsPlugin,
15+
private val mapboxMap: MapboxMap,
1216
private val animatorSet: AnimatorSet,
1317
) : MapboxAnimatorSet {
1418

19+
// Calculate camera animation hints for the specified fractions to pre-download tiles.
20+
// These values are totally based on heuristics and can be changed in the future.
21+
private val fractions = listOf(0.25f, 0.5f, 0.75f, 1f)
22+
1523
private val children = animatorSet.childAnimations.map { it as ValueAnimator }.toTypedArray()
1624
private val externalEndListeners = CopyOnWriteArrayList<MapboxAnimatorSetEndListener>()
1725

@@ -70,8 +78,12 @@ internal class FullAnimatorSet(
7078
animatorSet.duration = 0
7179
}
7280

81+
@OptIn(MapboxExperimental::class)
7382
override fun start() {
7483
cameraPlugin.registerAnimators(*children)
84+
animatorSet.calculateCameraAnimationHint(fractions, mapboxMap.cameraState)?.let {
85+
mapboxMap.setCameraAnimationHint(it)
86+
}
7587
animatorSet.start()
7688
}
7789

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/camera/transition/FullFrameAnimatorsCreator.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.mapbox.navigation.ui.maps.camera.transition
22

33
import com.mapbox.maps.CameraOptions
4+
import com.mapbox.maps.MapboxMap
45
import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin
56

67
internal class FullFrameAnimatorsCreator(
78
private val stateTransition: NavigationCameraStateTransition,
89
private val cameraAnimationsPlugin: CameraAnimationsPlugin,
10+
private val mapboxMap: MapboxMap,
911
) : AnimatorsCreator {
1012

1113
override fun transitionToFollowing(
@@ -14,6 +16,7 @@ internal class FullFrameAnimatorsCreator(
1416
): FullAnimatorSet {
1517
return FullAnimatorSet(
1618
cameraAnimationsPlugin,
19+
mapboxMap,
1720
stateTransition.transitionToFollowing(cameraOptions, transitionOptions),
1821
)
1922
}
@@ -24,6 +27,7 @@ internal class FullFrameAnimatorsCreator(
2427
): FullAnimatorSet {
2528
return FullAnimatorSet(
2629
cameraAnimationsPlugin,
30+
mapboxMap,
2731
stateTransition.transitionToOverview(cameraOptions, transitionOptions),
2832
)
2933
}
@@ -34,6 +38,7 @@ internal class FullFrameAnimatorsCreator(
3438
): MapboxAnimatorSet {
3539
return FullAnimatorSet(
3640
cameraAnimationsPlugin,
41+
mapboxMap,
3742
stateTransition.updateFrameForFollowing(cameraOptions, transitionOptions),
3843
)
3944
}
@@ -44,6 +49,7 @@ internal class FullFrameAnimatorsCreator(
4449
): MapboxAnimatorSet {
4550
return FullAnimatorSet(
4651
cameraAnimationsPlugin,
52+
mapboxMap,
4753
stateTransition.updateFrameForOverview(cameraOptions, transitionOptions),
4854
)
4955
}

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/camera/transition/SimplifiedAnimatorSet.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ package com.mapbox.navigation.ui.maps.camera.transition
22

33
import android.animation.Animator
44
import android.animation.ValueAnimator
5+
import com.mapbox.maps.MapboxExperimental
6+
import com.mapbox.maps.MapboxMap
57
import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin
8+
import com.mapbox.maps.plugin.animation.animator.CameraAnimator
9+
import com.mapbox.maps.plugin.animation.calculateCameraAnimationHint
610
import java.util.concurrent.CopyOnWriteArrayList
711

812
/**
@@ -13,10 +17,15 @@ import java.util.concurrent.CopyOnWriteArrayList
1317
* Used internal to avoid using [AnimatorSet.start] to make starting animations more performant.
1418
*/
1519
internal class SimplifiedAnimatorSet(
16-
val cameraPlugin: CameraAnimationsPlugin,
20+
private val cameraPlugin: CameraAnimationsPlugin,
21+
private val mapboxMap: MapboxMap,
1722
children: List<ValueAnimator>,
1823
) : MapboxAnimatorSet {
1924

25+
// Calculate camera animation hints for the specified fractions to pre-download tiles.
26+
// These values are totally based on heuristics and can be changed in the future.
27+
private val fractions = listOf(0.25f, 0.5f, 0.75f, 1f)
28+
2029
private val children = children.toTypedArray()
2130
private val externalEndListeners = CopyOnWriteArrayList<MapboxAnimatorSetEndListener>()
2231

@@ -29,7 +38,7 @@ internal class SimplifiedAnimatorSet(
2938
}
3039
},
3140
)
32-
children.forEach { it.addListener(simplifiedAnimatorSetListener) }
41+
this.children.forEach { it.addListener(simplifiedAnimatorSetListener) }
3342
}
3443

3544
override fun addAnimationEndListener(listener: MapboxAnimatorSetEndListener) {
@@ -40,8 +49,15 @@ internal class SimplifiedAnimatorSet(
4049
children.forEach { it.duration = 0 }
4150
}
4251

52+
@OptIn(MapboxExperimental::class)
4353
override fun start() {
4454
cameraPlugin.registerAnimators(*children)
55+
val cameraChildren = children.filterIsInstance<CameraAnimator<*>>()
56+
if (cameraChildren.size == children.size) {
57+
cameraChildren.calculateCameraAnimationHint(fractions, mapboxMap.cameraState)?.let {
58+
mapboxMap.setCameraAnimationHint(it)
59+
}
60+
}
4561
children.forEach { it.start() }
4662
}
4763

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/camera/transition/SimplifiedFrameAnimatorsCreator.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.mapbox.navigation.ui.maps.camera.transition
22

33
import com.mapbox.maps.CameraOptions
4+
import com.mapbox.maps.MapboxMap
45
import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin
56
import com.mapbox.navigation.ui.maps.internal.camera.SimplifiedUpdateFrameTransitionProvider
67

78
internal class SimplifiedFrameAnimatorsCreator(
89
private val cameraAnimationsPlugin: CameraAnimationsPlugin,
10+
private val mapboxMap: MapboxMap,
911
private val stateTransition: NavigationCameraStateTransition,
1012
private val simplifiedUpdateFrameTransition: SimplifiedUpdateFrameTransitionProvider,
1113
) : AnimatorsCreator {
@@ -16,6 +18,7 @@ internal class SimplifiedFrameAnimatorsCreator(
1618
): FullAnimatorSet {
1719
return FullAnimatorSet(
1820
cameraAnimationsPlugin,
21+
mapboxMap,
1922
stateTransition.transitionToFollowing(cameraOptions, transitionOptions),
2023
)
2124
}
@@ -26,6 +29,7 @@ internal class SimplifiedFrameAnimatorsCreator(
2629
): FullAnimatorSet {
2730
return FullAnimatorSet(
2831
cameraAnimationsPlugin,
32+
mapboxMap,
2933
stateTransition.transitionToOverview(cameraOptions, transitionOptions),
3034
)
3135
}
@@ -36,6 +40,7 @@ internal class SimplifiedFrameAnimatorsCreator(
3640
): MapboxAnimatorSet {
3741
return SimplifiedAnimatorSet(
3842
cameraAnimationsPlugin,
43+
mapboxMap,
3944
simplifiedUpdateFrameTransition.updateFollowingFrame(cameraOptions, transitionOptions),
4045
)
4146
}
@@ -46,6 +51,7 @@ internal class SimplifiedFrameAnimatorsCreator(
4651
): MapboxAnimatorSet {
4752
return SimplifiedAnimatorSet(
4853
cameraAnimationsPlugin,
54+
mapboxMap,
4955
simplifiedUpdateFrameTransition.updateOverviewFrame(cameraOptions, transitionOptions),
5056
)
5157
}

ui-maps/src/test/java/com/mapbox/navigation/ui/maps/camera/transition/FullAnimatorSetTest.kt

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,43 @@ import android.animation.Animator
44
import android.animation.Animator.AnimatorListener
55
import android.animation.AnimatorSet
66
import android.animation.ValueAnimator
7+
import com.mapbox.maps.CameraAnimationHint
8+
import com.mapbox.maps.CameraState
9+
import com.mapbox.maps.MapboxMap
710
import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin
11+
import com.mapbox.maps.plugin.animation.calculateCameraAnimationHint
812
import io.mockk.clearMocks
913
import io.mockk.every
1014
import io.mockk.mockk
15+
import io.mockk.mockkStatic
1116
import io.mockk.slot
17+
import io.mockk.unmockkStatic
1218
import io.mockk.verify
1319
import io.mockk.verifyOrder
20+
import org.junit.After
21+
import org.junit.Before
1422
import org.junit.Test
1523

1624
internal class FullAnimatorSetTest {
1725

1826
private val cameraPlugin = mockk<CameraAnimationsPlugin>(relaxed = true)
27+
private val mapboxMap = mockk<MapboxMap>(relaxed = true)
1928
private val children = arrayListOf<Animator>(mockk<ValueAnimator>(), mockk<ValueAnimator>())
2029
private val originalAnimatorSet = mockk<AnimatorSet>(relaxed = true) {
2130
every { childAnimations } returns children
2231
}
2332

24-
private val fullAnimatorSet = FullAnimatorSet(cameraPlugin, originalAnimatorSet)
33+
private val fullAnimatorSet = FullAnimatorSet(cameraPlugin, mapboxMap, originalAnimatorSet)
34+
35+
@Before
36+
fun setUp() {
37+
mockkStatic("com.mapbox.maps.plugin.animation.CameraAnimationsUtils")
38+
}
39+
40+
@After
41+
fun tearDown() {
42+
unmockkStatic("com.mapbox.maps.plugin.animation.CameraAnimationsUtils")
43+
}
2544

2645
@Test
2746
fun addListener() {
@@ -109,10 +128,24 @@ internal class FullAnimatorSetTest {
109128

110129
@Test
111130
fun start() {
131+
val fractions = listOf(0.25f, 0.5f, 0.75f, 1f)
132+
val cameraState = mockk<CameraState>()
133+
every { mapboxMap.cameraState } returns cameraState
134+
135+
val mockHint = mockk<CameraAnimationHint>()
136+
every {
137+
originalAnimatorSet.calculateCameraAnimationHint(
138+
fractions,
139+
cameraState,
140+
)
141+
} returns mockHint
142+
112143
fullAnimatorSet.start()
113144

114145
verifyOrder {
115146
cameraPlugin.registerAnimators(*children.map { it as ValueAnimator }.toTypedArray())
147+
originalAnimatorSet.calculateCameraAnimationHint(fractions, cameraState)
148+
mapboxMap.setCameraAnimationHint(mockHint)
116149
originalAnimatorSet.start()
117150
}
118151
}

ui-maps/src/test/java/com/mapbox/navigation/ui/maps/camera/transition/FullFrameAnimatorsCreatorTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ internal class FullFrameAnimatorsCreatorTest {
2525
private val animatorsCreator = FullFrameAnimatorsCreator(
2626
stateTransition,
2727
cameraAnimationsPlugin,
28+
mockk(relaxed = true),
2829
)
2930

3031
@Test

ui-maps/src/test/java/com/mapbox/navigation/ui/maps/camera/transition/SimplifiedAnimatorSetTest.kt

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,21 @@ package com.mapbox.navigation.ui.maps.camera.transition
22

33
import android.animation.Animator.AnimatorListener
44
import android.animation.ValueAnimator
5+
import com.mapbox.maps.CameraAnimationHint
6+
import com.mapbox.maps.CameraState
7+
import com.mapbox.maps.MapboxMap
58
import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin
9+
import com.mapbox.maps.plugin.animation.animator.CameraAnimator
10+
import com.mapbox.maps.plugin.animation.calculateCameraAnimationHint
11+
import io.mockk.every
612
import io.mockk.mockk
13+
import io.mockk.mockkStatic
714
import io.mockk.slot
15+
import io.mockk.unmockkStatic
816
import io.mockk.verify
917
import io.mockk.verifyOrder
18+
import org.junit.After
19+
import org.junit.Before
1020
import org.junit.Test
1121

1222
internal class SimplifiedAnimatorSetTest {
@@ -15,7 +25,18 @@ internal class SimplifiedAnimatorSetTest {
1525
private val child1 = mockk<ValueAnimator>(relaxed = true)
1626
private val child2 = mockk<ValueAnimator>(relaxed = true)
1727
private val children = arrayListOf(child1, child2)
18-
private val animatorSet = SimplifiedAnimatorSet(cameraPlugin, children)
28+
private val mapboxMap = mockk<MapboxMap>(relaxed = true)
29+
private val animatorSet = SimplifiedAnimatorSet(cameraPlugin, mapboxMap, children)
30+
31+
@Before
32+
fun setUp() {
33+
mockkStatic("com.mapbox.maps.plugin.animation.CameraAnimationsUtils")
34+
}
35+
36+
@After
37+
fun tearDown() {
38+
unmockkStatic("com.mapbox.maps.plugin.animation.CameraAnimationsUtils")
39+
}
1940

2041
@Test
2142
fun addAnimationEndListener() {
@@ -68,6 +89,56 @@ internal class SimplifiedAnimatorSetTest {
6889
}
6990
}
7091

92+
@Test
93+
fun startWithCameraAnimators() {
94+
val fractions = listOf(0.25f, 0.5f, 0.75f, 1f)
95+
val cameraAnimator1 = mockk<CameraAnimator<*>>(relaxed = true)
96+
val cameraAnimator2 = mockk<CameraAnimator<*>>(relaxed = true)
97+
val cameraAnimators = listOf(cameraAnimator1, cameraAnimator2)
98+
val cameraChildren = arrayListOf<ValueAnimator>(cameraAnimator1, cameraAnimator2)
99+
val cameraAnimatorSet = SimplifiedAnimatorSet(cameraPlugin, mapboxMap, cameraChildren)
100+
101+
val cameraState = mockk<CameraState>()
102+
every { mapboxMap.cameraState } returns cameraState
103+
104+
val mockHint = mockk<CameraAnimationHint>()
105+
every {
106+
cameraAnimators.calculateCameraAnimationHint(
107+
fractions,
108+
cameraState,
109+
)
110+
} returns mockHint
111+
112+
cameraAnimatorSet.start()
113+
114+
verifyOrder {
115+
cameraPlugin.registerAnimators(*cameraChildren.toTypedArray())
116+
cameraAnimators.calculateCameraAnimationHint(fractions, cameraState)
117+
mapboxMap.setCameraAnimationHint(mockHint)
118+
cameraAnimator1.start()
119+
cameraAnimator2.start()
120+
}
121+
}
122+
123+
@Test
124+
fun startWithMixedAnimators() {
125+
val cameraAnimator = mockk<CameraAnimator<*>>(relaxed = true)
126+
val valueAnimator = mockk<ValueAnimator>(relaxed = true)
127+
val mixedChildren = arrayListOf<ValueAnimator>(cameraAnimator, valueAnimator)
128+
val mixedAnimatorSet = SimplifiedAnimatorSet(cameraPlugin, mapboxMap, mixedChildren)
129+
130+
mixedAnimatorSet.start()
131+
132+
verifyOrder {
133+
cameraPlugin.registerAnimators(*mixedChildren.toTypedArray())
134+
cameraAnimator.start()
135+
valueAnimator.start()
136+
}
137+
138+
// Should not call setCameraAnimationHint when not all children are CameraAnimators
139+
verify(exactly = 0) { mapboxMap.setCameraAnimationHint(any()) }
140+
}
141+
71142
@Test
72143
fun onFinishedWithoutExternalListeners() {
73144
val originalListenerSlot = slot<AnimatorListener>()

ui-maps/src/test/java/com/mapbox/navigation/ui/maps/camera/transition/SimplifiedFrameAnimatorsCreatorTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ internal class SimplifiedFrameAnimatorsCreatorTest {
3030

3131
private val animatorsCreator = SimplifiedFrameAnimatorsCreator(
3232
cameraAnimationsPlugin,
33+
mockk(relaxed = true),
3334
stateTransition,
3435
simplifiedUpdateFrameTransition,
3536
)

0 commit comments

Comments
 (0)