[android] fixing ktlint issues

This commit is contained in:
Petr Pokorny
2020-12-21 11:35:43 +01:00
parent 68be84e32f
commit c5b645a02f
81 changed files with 9248 additions and 8961 deletions

View File

@@ -18,310 +18,310 @@ import org.junit.Test
class IndicatorLocationLayerRendererTest {
private val style: Style = mockk(relaxUnitFun = true)
private val layerSourceProvider: LayerSourceProvider = mockk(relaxUnitFun = true)
private val layer: Layer = mockk(relaxUnitFun = true)
private val style: Style = mockk(relaxUnitFun = true)
private val layerSourceProvider: LayerSourceProvider = mockk(relaxUnitFun = true)
private val layer: Layer = mockk(relaxUnitFun = true)
private lateinit var locationLayerRenderer: IndicatorLocationLayerRenderer
private lateinit var locationLayerRenderer: IndicatorLocationLayerRenderer
@Before
fun setup() {
every { style.removeLayer(any<Layer>()) } returns true
locationLayerRenderer = IndicatorLocationLayerRenderer(layerSourceProvider)
every { layerSourceProvider.generateLocationComponentLayer() } returns layer
locationLayerRenderer.initializeComponents(style)
}
@Test
fun sanity() {
Assert.assertNotNull(locationLayerRenderer)
}
@Test
fun initializeComponents_withLocation() {
val newLayer: Layer = mockk(relaxUnitFun = true)
every { layerSourceProvider.generateLocationComponentLayer() } returns newLayer
val latLng = LatLng(10.0, 20.0)
val bearing = 11f
val accuracy = 65f
locationLayerRenderer.setLatLng(latLng)
locationLayerRenderer.setGpsBearing(bearing)
locationLayerRenderer.setAccuracyRadius(accuracy)
locationLayerRenderer.initializeComponents(mockk())
verify { newLayer.setProperties(LocationPropertyFactory.location(latLng.toLocationArray())) }
verify { newLayer.setProperties(LocationPropertyFactory.bearing(bearing.toDouble())) }
verify { newLayer.setProperties(LocationPropertyFactory.accuracyRadius(accuracy)) }
}
@Test
fun addLayers() {
val positionManager: LocationComponentPositionManager = mockk(relaxUnitFun = true)
locationLayerRenderer.addLayers(positionManager)
verify { positionManager.addLayerToMap(layer) }
}
@Test
fun removeLayers() {
locationLayerRenderer.removeLayers()
verify { style.removeLayer(layer) }
}
@Test
fun hide() {
locationLayerRenderer.hide()
verify { layer.setProperties(LocationPropertyFactory.visibility(Property.NONE)) }
}
@Test
fun show() {
locationLayerRenderer.show(RenderMode.NORMAL, false)
verify { layer.setProperties(LocationPropertyFactory.visibility(Property.VISIBLE)) }
}
@Test
fun show_normal_notStale() {
locationLayerRenderer.show(RenderMode.NORMAL, false)
verify {
layer.setProperties(
LocationPropertyFactory.topImage(FOREGROUND_ICON),
LocationPropertyFactory.bearingImage(BACKGROUND_ICON),
LocationPropertyFactory.shadowImage(SHADOW_ICON)
)
@Before
fun setup() {
every { style.removeLayer(any<Layer>()) } returns true
locationLayerRenderer = IndicatorLocationLayerRenderer(layerSourceProvider)
every { layerSourceProvider.generateLocationComponentLayer() } returns layer
locationLayerRenderer.initializeComponents(style)
}
}
@Test
fun show_compass_notStale() {
locationLayerRenderer.show(RenderMode.COMPASS, false)
verify {
layer.setProperties(
LocationPropertyFactory.topImage(FOREGROUND_ICON),
LocationPropertyFactory.bearingImage(BEARING_ICON),
LocationPropertyFactory.shadowImage(SHADOW_ICON)
)
@Test
fun sanity() {
Assert.assertNotNull(locationLayerRenderer)
}
}
@Test
fun show_gps_notStale() {
locationLayerRenderer.show(RenderMode.GPS, false)
@Test
fun initializeComponents_withLocation() {
val newLayer: Layer = mockk(relaxUnitFun = true)
every { layerSourceProvider.generateLocationComponentLayer() } returns newLayer
val latLng = LatLng(10.0, 20.0)
val bearing = 11f
val accuracy = 65f
locationLayerRenderer.setLatLng(latLng)
locationLayerRenderer.setGpsBearing(bearing)
locationLayerRenderer.setAccuracyRadius(accuracy)
verify {
layer.setProperties(
LocationPropertyFactory.topImage(""),
LocationPropertyFactory.bearingImage(FOREGROUND_ICON),
LocationPropertyFactory.shadowImage(BACKGROUND_ICON)
)
locationLayerRenderer.initializeComponents(mockk())
verify { newLayer.setProperties(LocationPropertyFactory.location(latLng.toLocationArray())) }
verify { newLayer.setProperties(LocationPropertyFactory.bearing(bearing.toDouble())) }
verify { newLayer.setProperties(LocationPropertyFactory.accuracyRadius(accuracy)) }
}
verify { layer.setProperties(LocationPropertyFactory.accuracyRadius(0f)) }
}
@Test
fun show_normal_stale() {
locationLayerRenderer.show(RenderMode.NORMAL, true)
@Test
fun addLayers() {
val positionManager: LocationComponentPositionManager = mockk(relaxUnitFun = true)
verify {
layer.setProperties(
LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON),
LocationPropertyFactory.bearingImage(BACKGROUND_STALE_ICON),
LocationPropertyFactory.shadowImage(SHADOW_ICON)
)
locationLayerRenderer.addLayers(positionManager)
verify { positionManager.addLayerToMap(layer) }
}
}
@Test
fun show_compass_stale() {
locationLayerRenderer.show(RenderMode.COMPASS, true)
@Test
fun removeLayers() {
locationLayerRenderer.removeLayers()
verify {
layer.setProperties(
LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON),
LocationPropertyFactory.bearingImage(BEARING_STALE_ICON),
LocationPropertyFactory.shadowImage(SHADOW_ICON)
)
verify { style.removeLayer(layer) }
}
}
@Test
fun show_gps_stale() {
locationLayerRenderer.show(RenderMode.GPS, true)
@Test
fun hide() {
locationLayerRenderer.hide()
verify {
layer.setProperties(
LocationPropertyFactory.topImage(""),
LocationPropertyFactory.bearingImage(FOREGROUND_STALE_ICON),
LocationPropertyFactory.shadowImage(BACKGROUND_STALE_ICON)
)
verify { layer.setProperties(LocationPropertyFactory.visibility(Property.NONE)) }
}
verify { layer.setProperties(LocationPropertyFactory.accuracyRadius(0f)) }
}
@Test
fun styleAccuracy() {
val colorArray = ColorUtils.colorToRgbaArray(Color.RED)
val exp = Expression.rgba(colorArray[0], colorArray[1], colorArray[2], 0.7f)
@Test
fun show() {
locationLayerRenderer.show(RenderMode.NORMAL, false)
locationLayerRenderer.styleAccuracy(0.7f, Color.RED)
verify {
layer.setProperties(
LocationPropertyFactory.accuracyRadiusColor(exp),
LocationPropertyFactory.accuracyRadiusBorderColor(exp)
)
verify { layer.setProperties(LocationPropertyFactory.visibility(Property.VISIBLE)) }
}
}
@Test
fun setLatLng() {
val latLng = LatLng(10.0, 20.0)
locationLayerRenderer.setLatLng(latLng)
@Test
fun show_normal_notStale() {
locationLayerRenderer.show(RenderMode.NORMAL, false)
verify { layer.setProperties(LocationPropertyFactory.location(latLng.toLocationArray())) }
}
@Test
fun setGpsBearing() {
val bearing = 30.0
locationLayerRenderer.setGpsBearing(bearing.toFloat())
verify { layer.setProperties(LocationPropertyFactory.bearing(bearing)) }
}
@Test
fun setCompassBearing() {
val bearing = 30.0
locationLayerRenderer.setCompassBearing(bearing.toFloat())
verify { layer.setProperties(LocationPropertyFactory.bearing(bearing)) }
}
@Test
fun setAccuracyRadius() {
val radius = 40f
locationLayerRenderer.setAccuracyRadius(radius)
verify { layer.setProperties(LocationPropertyFactory.accuracyRadius(radius)) }
}
@Test
fun styleScaling() {
val exp = Expression.literal("")
locationLayerRenderer.styleScaling(exp)
verify {
layer.setProperties(
LocationPropertyFactory.shadowImageSize(exp),
LocationPropertyFactory.bearingImageSize(exp),
LocationPropertyFactory.topImageSize(exp)
)
verify {
layer.setProperties(
LocationPropertyFactory.topImage(FOREGROUND_ICON),
LocationPropertyFactory.bearingImage(BACKGROUND_ICON),
LocationPropertyFactory.shadowImage(SHADOW_ICON)
)
}
}
}
@Test
fun setLocationStale() {
locationLayerRenderer.setLocationStale(true, RenderMode.NORMAL)
@Test
fun show_compass_notStale() {
locationLayerRenderer.show(RenderMode.COMPASS, false)
verify {
layer.setProperties(
LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON),
LocationPropertyFactory.bearingImage(BACKGROUND_STALE_ICON),
LocationPropertyFactory.shadowImage(SHADOW_ICON)
)
verify {
layer.setProperties(
LocationPropertyFactory.topImage(FOREGROUND_ICON),
LocationPropertyFactory.bearingImage(BEARING_ICON),
LocationPropertyFactory.shadowImage(SHADOW_ICON)
)
}
}
}
@Test
fun addBitmaps_shadow() {
addBitmaps(withShadow = true, renderMode = RenderMode.NORMAL)
@Test
fun show_gps_notStale() {
locationLayerRenderer.show(RenderMode.GPS, false)
verify { style.addImage(SHADOW_ICON, shadowBitmap) }
}
verify {
layer.setProperties(
LocationPropertyFactory.topImage(""),
LocationPropertyFactory.bearingImage(FOREGROUND_ICON),
LocationPropertyFactory.shadowImage(BACKGROUND_ICON)
)
}
verify { layer.setProperties(LocationPropertyFactory.accuracyRadius(0f)) }
}
@Test
fun addBitmaps_noShadow() {
addBitmaps(withShadow = false, renderMode = RenderMode.NORMAL)
@Test
fun show_normal_stale() {
locationLayerRenderer.show(RenderMode.NORMAL, true)
verify { style.removeImage(SHADOW_ICON) }
}
verify {
layer.setProperties(
LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON),
LocationPropertyFactory.bearingImage(BACKGROUND_STALE_ICON),
LocationPropertyFactory.shadowImage(SHADOW_ICON)
)
}
}
@Test
fun addBitmaps_normal() {
addBitmaps(withShadow = true, renderMode = RenderMode.NORMAL)
@Test
fun show_compass_stale() {
locationLayerRenderer.show(RenderMode.COMPASS, true)
verify { style.addImage(FOREGROUND_ICON, foregroundBitmap) }
verify { style.addImage(FOREGROUND_STALE_ICON, foregroundStaleBitmap) }
verify { style.addImage(BACKGROUND_ICON, backgroundBitmap) }
verify { style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap) }
verify { style.addImage(BEARING_ICON, bearingBitmap) }
}
verify {
layer.setProperties(
LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON),
LocationPropertyFactory.bearingImage(BEARING_STALE_ICON),
LocationPropertyFactory.shadowImage(SHADOW_ICON)
)
}
}
@Test
fun addBitmaps_compass() {
every { bearingBitmap.width } returns 40
every { bearingBitmap.height } returns 40
every { bearingBitmap.config } returns mockk()
every { backgroundBitmap.width } returns 20
every { backgroundBitmap.height } returns 10
@Test
fun show_gps_stale() {
locationLayerRenderer.show(RenderMode.GPS, true)
val mergedBitmap = mockk<Bitmap>()
mockkStatic(BitmapUtils::class)
every { BitmapUtils.mergeBitmap(bearingBitmap, backgroundBitmap, 10f, 15f) } returns mergedBitmap
verify {
layer.setProperties(
LocationPropertyFactory.topImage(""),
LocationPropertyFactory.bearingImage(FOREGROUND_STALE_ICON),
LocationPropertyFactory.shadowImage(BACKGROUND_STALE_ICON)
)
}
verify { layer.setProperties(LocationPropertyFactory.accuracyRadius(0f)) }
}
every { bearingBitmap.width } returns 40
every { bearingBitmap.height } returns 40
every { bearingBitmap.config } returns mockk()
every { backgroundStaleBitmap.width } returns 30
every { backgroundStaleBitmap.height } returns 10
@Test
fun styleAccuracy() {
val colorArray = ColorUtils.colorToRgbaArray(Color.RED)
val exp = Expression.rgba(colorArray[0], colorArray[1], colorArray[2], 0.7f)
val mergedStaleBitmap = mockk<Bitmap>()
every { BitmapUtils.mergeBitmap(bearingBitmap, backgroundStaleBitmap, 5f, 15f) } returns mergedStaleBitmap
locationLayerRenderer.styleAccuracy(0.7f, Color.RED)
addBitmaps(withShadow = true, renderMode = RenderMode.COMPASS)
verify {
layer.setProperties(
LocationPropertyFactory.accuracyRadiusColor(exp),
LocationPropertyFactory.accuracyRadiusBorderColor(exp)
)
}
}
verify { style.addImage(BEARING_ICON, mergedBitmap) }
verify { style.addImage(BEARING_STALE_ICON, mergedStaleBitmap) }
@Test
fun setLatLng() {
val latLng = LatLng(10.0, 20.0)
locationLayerRenderer.setLatLng(latLng)
unmockkStatic(BitmapUtils::class)
}
verify { layer.setProperties(LocationPropertyFactory.location(latLng.toLocationArray())) }
}
@Test
fun addBitmaps_gps() {
addBitmaps(withShadow = true, renderMode = RenderMode.GPS)
@Test
fun setGpsBearing() {
val bearing = 30.0
locationLayerRenderer.setGpsBearing(bearing.toFloat())
verify { style.addImage(FOREGROUND_ICON, foregroundBitmap) }
verify { style.addImage(FOREGROUND_STALE_ICON, foregroundStaleBitmap) }
verify { style.addImage(BACKGROUND_ICON, backgroundBitmap) }
verify { style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap) }
verify { style.addImage(BEARING_ICON, bearingBitmap) }
}
verify { layer.setProperties(LocationPropertyFactory.bearing(bearing)) }
}
private val shadowBitmap = mockk<Bitmap>()
private val backgroundBitmap = mockk<Bitmap>()
private val backgroundStaleBitmap = mockk<Bitmap>()
private val bearingBitmap = mockk<Bitmap>()
private val foregroundBitmap = mockk<Bitmap>()
private val foregroundStaleBitmap = mockk<Bitmap>()
@Test
fun setCompassBearing() {
val bearing = 30.0
locationLayerRenderer.setCompassBearing(bearing.toFloat())
private fun addBitmaps(withShadow: Boolean, @RenderMode.Mode renderMode: Int) {
locationLayerRenderer.addBitmaps(
renderMode,
if (withShadow) shadowBitmap else null,
backgroundBitmap,
backgroundStaleBitmap,
bearingBitmap,
foregroundBitmap,
foregroundStaleBitmap
)
}
verify { layer.setProperties(LocationPropertyFactory.bearing(bearing)) }
}
private fun LatLng.toLocationArray() = arrayOf(latitude, longitude, 0.0)
}
@Test
fun setAccuracyRadius() {
val radius = 40f
locationLayerRenderer.setAccuracyRadius(radius)
verify { layer.setProperties(LocationPropertyFactory.accuracyRadius(radius)) }
}
@Test
fun styleScaling() {
val exp = Expression.literal("")
locationLayerRenderer.styleScaling(exp)
verify {
layer.setProperties(
LocationPropertyFactory.shadowImageSize(exp),
LocationPropertyFactory.bearingImageSize(exp),
LocationPropertyFactory.topImageSize(exp)
)
}
}
@Test
fun setLocationStale() {
locationLayerRenderer.setLocationStale(true, RenderMode.NORMAL)
verify {
layer.setProperties(
LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON),
LocationPropertyFactory.bearingImage(BACKGROUND_STALE_ICON),
LocationPropertyFactory.shadowImage(SHADOW_ICON)
)
}
}
@Test
fun addBitmaps_shadow() {
addBitmaps(withShadow = true, renderMode = RenderMode.NORMAL)
verify { style.addImage(SHADOW_ICON, shadowBitmap) }
}
@Test
fun addBitmaps_noShadow() {
addBitmaps(withShadow = false, renderMode = RenderMode.NORMAL)
verify { style.removeImage(SHADOW_ICON) }
}
@Test
fun addBitmaps_normal() {
addBitmaps(withShadow = true, renderMode = RenderMode.NORMAL)
verify { style.addImage(FOREGROUND_ICON, foregroundBitmap) }
verify { style.addImage(FOREGROUND_STALE_ICON, foregroundStaleBitmap) }
verify { style.addImage(BACKGROUND_ICON, backgroundBitmap) }
verify { style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap) }
verify { style.addImage(BEARING_ICON, bearingBitmap) }
}
@Test
fun addBitmaps_compass() {
every { bearingBitmap.width } returns 40
every { bearingBitmap.height } returns 40
every { bearingBitmap.config } returns mockk()
every { backgroundBitmap.width } returns 20
every { backgroundBitmap.height } returns 10
val mergedBitmap = mockk<Bitmap>()
mockkStatic(BitmapUtils::class)
every { BitmapUtils.mergeBitmap(bearingBitmap, backgroundBitmap, 10f, 15f) } returns mergedBitmap
every { bearingBitmap.width } returns 40
every { bearingBitmap.height } returns 40
every { bearingBitmap.config } returns mockk()
every { backgroundStaleBitmap.width } returns 30
every { backgroundStaleBitmap.height } returns 10
val mergedStaleBitmap = mockk<Bitmap>()
every { BitmapUtils.mergeBitmap(bearingBitmap, backgroundStaleBitmap, 5f, 15f) } returns mergedStaleBitmap
addBitmaps(withShadow = true, renderMode = RenderMode.COMPASS)
verify { style.addImage(BEARING_ICON, mergedBitmap) }
verify { style.addImage(BEARING_STALE_ICON, mergedStaleBitmap) }
unmockkStatic(BitmapUtils::class)
}
@Test
fun addBitmaps_gps() {
addBitmaps(withShadow = true, renderMode = RenderMode.GPS)
verify { style.addImage(FOREGROUND_ICON, foregroundBitmap) }
verify { style.addImage(FOREGROUND_STALE_ICON, foregroundStaleBitmap) }
verify { style.addImage(BACKGROUND_ICON, backgroundBitmap) }
verify { style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap) }
verify { style.addImage(BEARING_ICON, bearingBitmap) }
}
private val shadowBitmap = mockk<Bitmap>()
private val backgroundBitmap = mockk<Bitmap>()
private val backgroundStaleBitmap = mockk<Bitmap>()
private val bearingBitmap = mockk<Bitmap>()
private val foregroundBitmap = mockk<Bitmap>()
private val foregroundStaleBitmap = mockk<Bitmap>()
private fun addBitmaps(withShadow: Boolean, @RenderMode.Mode renderMode: Int) {
locationLayerRenderer.addBitmaps(
renderMode,
if (withShadow) shadowBitmap else null,
backgroundBitmap,
backgroundStaleBitmap,
bearingBitmap,
foregroundBitmap,
foregroundStaleBitmap
)
}
private fun LatLng.toLocationArray() = arrayOf(latitude, longitude, 0.0)
}

View File

@@ -14,117 +14,117 @@ import org.mockito.junit.MockitoJUnitRunner
@RunWith(MockitoJUnitRunner::class)
class LocationComponentPositionManagerTest {
private lateinit var style: Style
private lateinit var layer: Layer
private lateinit var style: Style
private lateinit var layer: Layer
@Before
fun setup() {
style = mockk(relaxed = true)
layer = mockk(relaxed = true)
}
@Before
fun setup() {
style = mockk(relaxed = true)
layer = mockk(relaxed = true)
}
@Test
fun update_noChange_null() {
val positionManager = LocationComponentPositionManager(style, null, null)
val requiresUpdate = positionManager.update(null, null)
assertFalse(requiresUpdate)
}
@Test
fun update_noChange_null() {
val positionManager = LocationComponentPositionManager(style, null, null)
val requiresUpdate = positionManager.update(null, null)
assertFalse(requiresUpdate)
}
@Test
fun update_noChange_above() {
val positionManager = LocationComponentPositionManager(style, "above", null)
val requiresUpdate = positionManager.update("above", null)
assertFalse(requiresUpdate)
}
@Test
fun update_noChange_above() {
val positionManager = LocationComponentPositionManager(style, "above", null)
val requiresUpdate = positionManager.update("above", null)
assertFalse(requiresUpdate)
}
@Test
fun update_noChange_below() {
val positionManager = LocationComponentPositionManager(style, null, "below")
val requiresUpdate = positionManager.update(null, "below")
assertFalse(requiresUpdate)
}
@Test
fun update_noChange_below() {
val positionManager = LocationComponentPositionManager(style, null, "below")
val requiresUpdate = positionManager.update(null, "below")
assertFalse(requiresUpdate)
}
@Test
fun update_fromNull_above() {
val positionManager = LocationComponentPositionManager(style, null, null)
val requiresUpdate = positionManager.update("above", null)
assertTrue(requiresUpdate)
}
@Test
fun update_fromNull_above() {
val positionManager = LocationComponentPositionManager(style, null, null)
val requiresUpdate = positionManager.update("above", null)
assertTrue(requiresUpdate)
}
@Test
fun update_fromNull_below() {
val positionManager = LocationComponentPositionManager(style, null, null)
val requiresUpdate = positionManager.update(null, "below")
assertTrue(requiresUpdate)
}
@Test
fun update_fromNull_below() {
val positionManager = LocationComponentPositionManager(style, null, null)
val requiresUpdate = positionManager.update(null, "below")
assertTrue(requiresUpdate)
}
@Test
fun update_toNull_above() {
val positionManager = LocationComponentPositionManager(style, "above", null)
val requiresUpdate = positionManager.update(null, null)
assertTrue(requiresUpdate)
}
@Test
fun update_toNull_above() {
val positionManager = LocationComponentPositionManager(style, "above", null)
val requiresUpdate = positionManager.update(null, null)
assertTrue(requiresUpdate)
}
@Test
fun update_toNull_below() {
val positionManager = LocationComponentPositionManager(style, null, "below")
val requiresUpdate = positionManager.update(null, null)
assertTrue(requiresUpdate)
}
@Test
fun update_toNull_below() {
val positionManager = LocationComponentPositionManager(style, null, "below")
val requiresUpdate = positionManager.update(null, null)
assertTrue(requiresUpdate)
}
@Test
fun update_fromValue_above() {
val positionManager = LocationComponentPositionManager(style, "above1", null)
val requiresUpdate = positionManager.update("above2", null)
assertTrue(requiresUpdate)
}
@Test
fun update_fromValue_above() {
val positionManager = LocationComponentPositionManager(style, "above1", null)
val requiresUpdate = positionManager.update("above2", null)
assertTrue(requiresUpdate)
}
@Test
fun update_fromValue_below() {
val positionManager = LocationComponentPositionManager(style, null, "below1")
val requiresUpdate = positionManager.update(null, "below2")
assertTrue(requiresUpdate)
}
@Test
fun update_fromValue_below() {
val positionManager = LocationComponentPositionManager(style, null, "below1")
val requiresUpdate = positionManager.update(null, "below2")
assertTrue(requiresUpdate)
}
@Test
fun addLayer_noModifier() {
val positionManager = LocationComponentPositionManager(style, null, null)
positionManager.addLayerToMap(layer)
@Test
fun addLayer_noModifier() {
val positionManager = LocationComponentPositionManager(style, null, null)
positionManager.addLayerToMap(layer)
verify { style.addLayer(layer) }
}
verify { style.addLayer(layer) }
}
@Test
fun addLayer_above() {
val positionManager = LocationComponentPositionManager(style, "above", null)
positionManager.addLayerToMap(layer)
@Test
fun addLayer_above() {
val positionManager = LocationComponentPositionManager(style, "above", null)
positionManager.addLayerToMap(layer)
verify { style.addLayerAbove(layer, "above") }
}
verify { style.addLayerAbove(layer, "above") }
}
@Test
fun addLayer_below() {
val positionManager = LocationComponentPositionManager(style, null, "below")
positionManager.addLayerToMap(layer)
@Test
fun addLayer_below() {
val positionManager = LocationComponentPositionManager(style, null, "below")
positionManager.addLayerToMap(layer)
verify { style.addLayerBelow(layer, "below") }
}
verify { style.addLayerBelow(layer, "below") }
}
@Test
fun addLayer_afterUpdate_above() {
val positionManager = LocationComponentPositionManager(style, null, null)
positionManager.update("above", null)
positionManager.addLayerToMap(layer)
@Test
fun addLayer_afterUpdate_above() {
val positionManager = LocationComponentPositionManager(style, null, null)
positionManager.update("above", null)
positionManager.addLayerToMap(layer)
verify { style.addLayerAbove(layer, "above") }
}
verify { style.addLayerAbove(layer, "above") }
}
@Test
fun addLayer_afterUpdate_below() {
val positionManager = LocationComponentPositionManager(style, null, null)
positionManager.update(null, "below")
positionManager.addLayerToMap(layer)
@Test
fun addLayer_afterUpdate_below() {
val positionManager = LocationComponentPositionManager(style, null, null)
positionManager.update(null, "below")
positionManager.addLayerToMap(layer)
verify { style.addLayerBelow(layer, "below") }
}
}
verify { style.addLayerBelow(layer, "below") }
}
}

View File

@@ -11,33 +11,33 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class MapboxAnimatorTest {
@Test
fun fps_unlimited() {
val valueAnimator = mockk<ValueAnimator>()
every { valueAnimator.animatedValue } answers { 5f }
val listener = mockk<MapboxAnimator.AnimationsValueChangeListener<Float>>()
every { listener.onNewAnimationValue(any()) } answers {}
val mapboxAnimator = MapboxFloatAnimator(floatArrayOf(0f, 10f).toTypedArray(), listener, Int.MAX_VALUE)
@Test
fun fps_unlimited() {
val valueAnimator = mockk<ValueAnimator>()
every { valueAnimator.animatedValue } answers { 5f }
val listener = mockk<MapboxAnimator.AnimationsValueChangeListener<Float>>()
every { listener.onNewAnimationValue(any()) } answers {}
val mapboxAnimator = MapboxFloatAnimator(floatArrayOf(0f, 10f).toTypedArray(), listener, Int.MAX_VALUE)
for (i in 0 until 5)
mapboxAnimator.onAnimationUpdate(valueAnimator)
for (i in 0 until 5)
mapboxAnimator.onAnimationUpdate(valueAnimator)
verify(exactly = 5) { listener.onNewAnimationValue(5f) }
}
@Test
fun fps_limited() {
val valueAnimator = mockk<ValueAnimator>()
every { valueAnimator.animatedValue } answers { 5f }
val listener = mockk<MapboxAnimator.AnimationsValueChangeListener<Float>>()
every { listener.onNewAnimationValue(any()) } answers {}
val mapboxAnimator = MapboxFloatAnimator(floatArrayOf(0f, 10f).toTypedArray(), listener, 5)
for (i in 0 until 5) {
mapboxAnimator.onAnimationUpdate(valueAnimator)
Thread.sleep(150)
verify(exactly = 5) { listener.onNewAnimationValue(5f) }
}
verify(exactly = 3) { listener.onNewAnimationValue(5f) }
}
}
@Test
fun fps_limited() {
val valueAnimator = mockk<ValueAnimator>()
every { valueAnimator.animatedValue } answers { 5f }
val listener = mockk<MapboxAnimator.AnimationsValueChangeListener<Float>>()
every { listener.onNewAnimationValue(any()) } answers {}
val mapboxAnimator = MapboxFloatAnimator(floatArrayOf(0f, 10f).toTypedArray(), listener, 5)
for (i in 0 until 5) {
mapboxAnimator.onAnimationUpdate(valueAnimator)
Thread.sleep(150)
}
verify(exactly = 3) { listener.onNewAnimationValue(5f) }
}
}

View File

@@ -10,84 +10,84 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class LoggerTest {
private val logger: LoggerDefinition = mockk(relaxed = true)
private val logger: LoggerDefinition = mockk(relaxed = true)
@Before
fun setUp() {
Logger.setLoggerDefinition(logger)
}
@Before
fun setUp() {
Logger.setLoggerDefinition(logger)
}
@Test
fun verbosityLogLevel() {
Logger.setVerbosity(Logger.VERBOSE)
Logger.v(TAG, MESSAGE)
verify { logger.v(TAG, MESSAGE) }
}
@Test
fun verbosityLogLevel() {
Logger.setVerbosity(Logger.VERBOSE)
Logger.v(TAG, MESSAGE)
verify { logger.v(TAG, MESSAGE) }
}
@Test
fun verbosityLogLevelIgnore() {
Logger.setVerbosity(Logger.DEBUG)
Logger.v(TAG, MESSAGE)
verify(exactly = 0) { logger.v(TAG, MESSAGE) }
}
@Test
fun verbosityLogLevelIgnore() {
Logger.setVerbosity(Logger.DEBUG)
Logger.v(TAG, MESSAGE)
verify(exactly = 0) { logger.v(TAG, MESSAGE) }
}
@Test
fun debugLogLevel() {
Logger.setVerbosity(Logger.VERBOSE)
Logger.d(TAG, MESSAGE)
verify { logger.d(TAG, MESSAGE) }
}
@Test
fun debugLogLevel() {
Logger.setVerbosity(Logger.VERBOSE)
Logger.d(TAG, MESSAGE)
verify { logger.d(TAG, MESSAGE) }
}
@Test
fun debugLogLevelIgnore() {
Logger.setVerbosity(Logger.WARN)
Logger.d(TAG, MESSAGE)
verify(exactly = 0) { logger.d(TAG, MESSAGE) }
}
@Test
fun debugLogLevelIgnore() {
Logger.setVerbosity(Logger.WARN)
Logger.d(TAG, MESSAGE)
verify(exactly = 0) { logger.d(TAG, MESSAGE) }
}
@Test
fun warnLogLevel() {
Logger.setVerbosity(Logger.WARN)
Logger.w(TAG, MESSAGE)
verify { logger.w(TAG, MESSAGE) }
}
@Test
fun warnLogLevel() {
Logger.setVerbosity(Logger.WARN)
Logger.w(TAG, MESSAGE)
verify { logger.w(TAG, MESSAGE) }
}
@Test
fun warnLogLevelIgnore() {
Logger.setVerbosity(Logger.ERROR)
Logger.w(TAG, MESSAGE)
verify(exactly = 0) { logger.w(TAG, MESSAGE) }
}
@Test
fun warnLogLevelIgnore() {
Logger.setVerbosity(Logger.ERROR)
Logger.w(TAG, MESSAGE)
verify(exactly = 0) { logger.w(TAG, MESSAGE) }
}
@Test
fun errorLogLevel() {
Logger.setVerbosity(Logger.ERROR)
Logger.e(TAG, MESSAGE)
verify { logger.e(TAG, MESSAGE) }
}
@Test
fun errorLogLevel() {
Logger.setVerbosity(Logger.ERROR)
Logger.e(TAG, MESSAGE)
verify { logger.e(TAG, MESSAGE) }
}
@Test
fun errorLogLevelIgnore() {
Logger.setVerbosity(Logger.NONE)
Logger.e(TAG, MESSAGE)
verify(exactly = 0) { logger.e(TAG, MESSAGE) }
}
@Test
fun errorLogLevelIgnore() {
Logger.setVerbosity(Logger.NONE)
Logger.e(TAG, MESSAGE)
verify(exactly = 0) { logger.e(TAG, MESSAGE) }
}
@Test
fun noneLogLevelIgnore() {
Logger.setVerbosity(Logger.NONE)
Logger.v(TAG, MESSAGE)
Logger.d(TAG, MESSAGE)
Logger.w(TAG, MESSAGE)
Logger.e(TAG, MESSAGE)
verify(exactly = 0) { logger.v(TAG, MESSAGE) }
verify(exactly = 0) { logger.d(TAG, MESSAGE) }
verify(exactly = 0) { logger.w(TAG, MESSAGE) }
verify(exactly = 0) { logger.e(TAG, MESSAGE) }
}
@Test
fun noneLogLevelIgnore() {
Logger.setVerbosity(Logger.NONE)
Logger.v(TAG, MESSAGE)
Logger.d(TAG, MESSAGE)
Logger.w(TAG, MESSAGE)
Logger.e(TAG, MESSAGE)
verify(exactly = 0) { logger.v(TAG, MESSAGE) }
verify(exactly = 0) { logger.d(TAG, MESSAGE) }
verify(exactly = 0) { logger.w(TAG, MESSAGE) }
verify(exactly = 0) { logger.e(TAG, MESSAGE) }
}
companion object {
const val TAG: String = "TAG"
const val MESSAGE: String = "message"
}
}
companion object {
const val TAG: String = "TAG"
const val MESSAGE: String = "message"
}
}

View File

@@ -16,86 +16,86 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class MapboxMapOptionsAttrsTest {
@RelaxedMockK
private lateinit var options: MapboxMapOptions
@RelaxedMockK
private lateinit var options: MapboxMapOptions
@RelaxedMockK
private lateinit var typedArray: TypedArray
@RelaxedMockK
private lateinit var typedArray: TypedArray
@RelaxedMockK
private lateinit var context: Context
@RelaxedMockK
private lateinit var context: Context
@RelaxedMockK
private lateinit var resources: Resources
@RelaxedMockK
private lateinit var resources: Resources
@Before
fun setUp() {
MockKAnnotations.init(this)
every {
context.resources
}.returns(resources)
}
@Test
fun enabledLocalIdeographFontFamily() {
mockEnableLocalIdeograph(enabled = true)
val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
verify(exactly = 1) {
options.localIdeographFontFamily(any())
@Before
fun setUp() {
MockKAnnotations.init(this)
every {
context.resources
}.returns(resources)
}
}
@Test
fun localIdeographFontFamily() {
mockEnableLocalIdeograph(enabled = true)
@Test
fun enabledLocalIdeographFontFamily() {
mockEnableLocalIdeograph(enabled = true)
val font = "foo"
mockLocalIdeographString(font)
val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
verify(exactly = 1) {
options.localIdeographFontFamily(font)
verify(exactly = 1) {
options.localIdeographFontFamily(any())
}
}
}
@Test
fun localIdeographFontFamilies() {
mockEnableLocalIdeograph(enabled = true)
@Test
fun localIdeographFontFamily() {
mockEnableLocalIdeograph(enabled = true)
val fonts = arrayOf("foo", "bar")
mockLocalIdeographStringArray(fonts)
val font = "foo"
mockLocalIdeographString(font)
val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
verify(exactly = 1) {
options.localIdeographFontFamily(*fonts)
verify(exactly = 1) {
options.localIdeographFontFamily(font)
}
}
}
private fun mockEnableLocalIdeograph(enabled: Boolean) {
every {
typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_localIdeographEnabled, true)
}.returns(enabled)
}
@Test
fun localIdeographFontFamilies() {
mockEnableLocalIdeograph(enabled = true)
private fun mockLocalIdeographString(font: String) {
every {
typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily)
}.returns(font)
}
val fonts = arrayOf("foo", "bar")
mockLocalIdeographStringArray(fonts)
private fun mockLocalIdeographStringArray(fonts: Array<String>) {
val resId = 9000
val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
every {
typedArray.getResourceId(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamilies, 0)
}.returns(resId)
verify(exactly = 1) {
options.localIdeographFontFamily(*fonts)
}
}
every {
resources.getStringArray(resId)
}.returns(fonts)
}
}
private fun mockEnableLocalIdeograph(enabled: Boolean) {
every {
typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_localIdeographEnabled, true)
}.returns(enabled)
}
private fun mockLocalIdeographString(font: String) {
every {
typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily)
}.returns(font)
}
private fun mockLocalIdeographStringArray(fonts: Array<String>) {
val resId = 9000
every {
typedArray.getResourceId(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamilies, 0)
}.returns(resId)
every {
resources.getStringArray(resId)
}.returns(fonts)
}
}

View File

@@ -16,211 +16,211 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class MapboxMapTest {
private lateinit var mapboxMap: MapboxMap
private lateinit var mapboxMap: MapboxMap
private lateinit var nativeMapView: NativeMap
private lateinit var nativeMapView: NativeMap
private lateinit var transform: Transform
private lateinit var transform: Transform
private lateinit var cameraChangeDispatcher: CameraChangeDispatcher
private lateinit var cameraChangeDispatcher: CameraChangeDispatcher
private lateinit var developerAnimationListener: MapboxMap.OnDeveloperAnimationListener
private lateinit var developerAnimationListener: MapboxMap.OnDeveloperAnimationListener
@Before
fun setup() {
cameraChangeDispatcher = spyk()
developerAnimationListener = mockk(relaxed = true)
nativeMapView = mockk(relaxed = true)
transform = mockk(relaxed = true)
mapboxMap = MapboxMap(nativeMapView, transform, mockk(relaxed = true), null, null, cameraChangeDispatcher, listOf(developerAnimationListener))
every { nativeMapView.isDestroyed } returns false
every { nativeMapView.nativePtr } returns 5
mapboxMap.injectLocationComponent(spyk())
mapboxMap.setStyle(Style.MAPBOX_STREETS)
mapboxMap.onFinishLoadingStyle()
}
@Before
fun setup() {
cameraChangeDispatcher = spyk()
developerAnimationListener = mockk(relaxed = true)
nativeMapView = mockk(relaxed = true)
transform = mockk(relaxed = true)
mapboxMap = MapboxMap(nativeMapView, transform, mockk(relaxed = true), null, null, cameraChangeDispatcher, listOf(developerAnimationListener))
every { nativeMapView.isDestroyed } returns false
every { nativeMapView.nativePtr } returns 5
mapboxMap.injectLocationComponent(spyk())
mapboxMap.setStyle(Style.MAPBOX_STREETS)
mapboxMap.onFinishLoadingStyle()
}
@Test
fun testTransitionOptions() {
val expected = TransitionOptions(100, 200)
mapboxMap.style?.transition = expected
verify { nativeMapView.transitionOptions = expected }
}
@Test
fun testTransitionOptions() {
val expected = TransitionOptions(100, 200)
mapboxMap.style?.transition = expected
verify { nativeMapView.transitionOptions = expected }
}
@Test
fun testMoveCamera() {
val callback = mockk<MapboxMap.CancelableCallback>()
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
mapboxMap.moveCamera(update, callback)
verify { transform.moveCamera(mapboxMap, update, callback) }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testMoveCamera() {
val callback = mockk<MapboxMap.CancelableCallback>()
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
mapboxMap.moveCamera(update, callback)
verify { transform.moveCamera(mapboxMap, update, callback) }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testEaseCamera() {
val callback = mockk<MapboxMap.CancelableCallback>()
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
mapboxMap.easeCamera(update, callback)
verify { transform.easeCamera(mapboxMap, update, MapboxConstants.ANIMATION_DURATION, true, callback) }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testEaseCamera() {
val callback = mockk<MapboxMap.CancelableCallback>()
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
mapboxMap.easeCamera(update, callback)
verify { transform.easeCamera(mapboxMap, update, MapboxConstants.ANIMATION_DURATION, true, callback) }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testAnimateCamera() {
val callback = mockk<MapboxMap.CancelableCallback>()
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
mapboxMap.animateCamera(update, callback)
verify { transform.animateCamera(mapboxMap, update, MapboxConstants.ANIMATION_DURATION, callback) }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testAnimateCamera() {
val callback = mockk<MapboxMap.CancelableCallback>()
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
mapboxMap.animateCamera(update, callback)
verify { transform.animateCamera(mapboxMap, update, MapboxConstants.ANIMATION_DURATION, callback) }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testScrollBy() {
mapboxMap.scrollBy(100f, 200f)
verify { nativeMapView.moveBy(100.0, 200.0, 0) }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testScrollBy() {
mapboxMap.scrollBy(100f, 200f)
verify { nativeMapView.moveBy(100.0, 200.0, 0) }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testResetNorth() {
mapboxMap.resetNorth()
verify { transform.resetNorth() }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testResetNorth() {
mapboxMap.resetNorth()
verify { transform.resetNorth() }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testFocalBearing() {
mapboxMap.setFocalBearing(35.0, 100f, 200f, 1000)
verify { transform.setBearing(35.0, 100f, 200f, 1000) }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testFocalBearing() {
mapboxMap.setFocalBearing(35.0, 100f, 200f, 1000)
verify { transform.setBearing(35.0, 100f, 200f, 1000) }
verify { developerAnimationListener.onDeveloperAnimationStarted() }
}
@Test
fun testMinZoom() {
mapboxMap.setMinZoomPreference(10.0)
verify { transform.minZoom = 10.0 }
}
@Test
fun testMinZoom() {
mapboxMap.setMinZoomPreference(10.0)
verify { transform.minZoom = 10.0 }
}
@Test
fun testMaxZoom() {
mapboxMap.setMaxZoomPreference(10.0)
verify { transform.maxZoom = 10.0 }
}
@Test
fun testMaxZoom() {
mapboxMap.setMaxZoomPreference(10.0)
verify { transform.maxZoom = 10.0 }
}
@Test
fun testMinPitch() {
mapboxMap.setMinPitchPreference(10.0)
verify { transform.minPitch = 10.0 }
}
@Test
fun testMinPitch() {
mapboxMap.setMinPitchPreference(10.0)
verify { transform.minPitch = 10.0 }
}
@Test
fun testMaxPitch() {
mapboxMap.setMaxPitchPreference(10.0)
verify { transform.maxPitch = 10.0 }
}
@Test
fun testMaxPitch() {
mapboxMap.setMaxPitchPreference(10.0)
verify { transform.maxPitch = 10.0 }
}
@Test
fun testFpsListener() {
val fpsChangedListener = mockk<MapboxMap.OnFpsChangedListener>()
mapboxMap.onFpsChangedListener = fpsChangedListener
assertEquals("Listener should match", fpsChangedListener, mapboxMap.onFpsChangedListener)
}
@Test
fun testFpsListener() {
val fpsChangedListener = mockk<MapboxMap.OnFpsChangedListener>()
mapboxMap.onFpsChangedListener = fpsChangedListener
assertEquals("Listener should match", fpsChangedListener, mapboxMap.onFpsChangedListener)
}
@Test
fun testTilePrefetch() {
mapboxMap.prefetchesTiles = true
verify { nativeMapView.prefetchTiles = true }
}
@Test
fun testTilePrefetch() {
mapboxMap.prefetchesTiles = true
verify { nativeMapView.prefetchTiles = true }
}
@Test
fun testGetPrefetchZoomDelta() {
every { nativeMapView.prefetchZoomDelta } answers { 3 }
assertEquals(3, mapboxMap.prefetchZoomDelta)
}
@Test
fun testGetPrefetchZoomDelta() {
every { nativeMapView.prefetchZoomDelta } answers { 3 }
assertEquals(3, mapboxMap.prefetchZoomDelta)
}
@Test
fun testSetPrefetchZoomDelta() {
mapboxMap.prefetchZoomDelta = 2
verify { nativeMapView.prefetchZoomDelta = 2 }
}
@Test
fun testSetPrefetchZoomDelta() {
mapboxMap.prefetchZoomDelta = 2
verify { nativeMapView.prefetchZoomDelta = 2 }
}
@Test
fun testCameraForLatLngBounds() {
val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build()
mapboxMap.setLatLngBoundsForCameraTarget(bounds)
verify { nativeMapView.setLatLngBounds(bounds) }
}
@Test
fun testCameraForLatLngBounds() {
val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build()
mapboxMap.setLatLngBoundsForCameraTarget(bounds)
verify { nativeMapView.setLatLngBounds(bounds) }
}
@Test(expected = IllegalArgumentException::class)
fun testAnimateCameraChecksDurationPositive() {
mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null)
}
@Test(expected = IllegalArgumentException::class)
fun testAnimateCameraChecksDurationPositive() {
mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null)
}
@Test(expected = IllegalArgumentException::class)
fun testEaseCameraChecksDurationPositive() {
mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null)
}
@Test(expected = IllegalArgumentException::class)
fun testEaseCameraChecksDurationPositive() {
mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null)
}
@Test
fun testGetNativeMapPtr() {
assertEquals(5, mapboxMap.nativeMapPtr)
}
@Test
fun testGetNativeMapPtr() {
assertEquals(5, mapboxMap.nativeMapPtr)
}
@Test
fun testNativeMapIsNotCalledOnStateSave() {
clearMocks(nativeMapView)
mapboxMap.onSaveInstanceState(mockk(relaxed = true))
verify { nativeMapView wasNot Called }
}
@Test
fun testNativeMapIsNotCalledOnStateSave() {
clearMocks(nativeMapView)
mapboxMap.onSaveInstanceState(mockk(relaxed = true))
verify { nativeMapView wasNot Called }
}
@Test
fun testCameraChangeDispatcherCleared() {
mapboxMap.onDestroy()
verify { cameraChangeDispatcher.onDestroy() }
}
@Test
fun testCameraChangeDispatcherCleared() {
mapboxMap.onDestroy()
verify { cameraChangeDispatcher.onDestroy() }
}
@Test
fun testStyleClearedOnDestroy() {
val style = mockk<Style>(relaxed = true)
val builder = mockk<Style.Builder>(relaxed = true)
every { builder.build(nativeMapView) } returns style
mapboxMap.setStyle(builder)
@Test
fun testStyleClearedOnDestroy() {
val style = mockk<Style>(relaxed = true)
val builder = mockk<Style.Builder>(relaxed = true)
every { builder.build(nativeMapView) } returns style
mapboxMap.setStyle(builder)
mapboxMap.onDestroy()
verify(exactly = 1) { style.clear() }
}
mapboxMap.onDestroy()
verify(exactly = 1) { style.clear() }
}
@Test
fun testStyleCallbackNotCalledWhenPreviousFailed() {
val style = mockk<Style>(relaxed = true)
val builder = mockk<Style.Builder>(relaxed = true)
every { builder.build(nativeMapView) } returns style
val onStyleLoadedListener = mockk<Style.OnStyleLoaded>(relaxed = true)
@Test
fun testStyleCallbackNotCalledWhenPreviousFailed() {
val style = mockk<Style>(relaxed = true)
val builder = mockk<Style.Builder>(relaxed = true)
every { builder.build(nativeMapView) } returns style
val onStyleLoadedListener = mockk<Style.OnStyleLoaded>(relaxed = true)
mapboxMap.setStyle(builder, onStyleLoadedListener)
mapboxMap.onFailLoadingStyle()
mapboxMap.setStyle(builder, onStyleLoadedListener)
mapboxMap.onFinishLoadingStyle()
verify(exactly = 1) { onStyleLoadedListener.onStyleLoaded(style) }
}
mapboxMap.setStyle(builder, onStyleLoadedListener)
mapboxMap.onFailLoadingStyle()
mapboxMap.setStyle(builder, onStyleLoadedListener)
mapboxMap.onFinishLoadingStyle()
verify(exactly = 1) { onStyleLoadedListener.onStyleLoaded(style) }
}
@Test
fun testStyleCallbackNotCalledWhenPreviousNotFinished() {
// regression test for #14337
val style = mockk<Style>(relaxed = true)
val builder = mockk<Style.Builder>(relaxed = true)
every { builder.build(nativeMapView) } returns style
val onStyleLoadedListener = mockk<Style.OnStyleLoaded>(relaxed = true)
@Test
fun testStyleCallbackNotCalledWhenPreviousNotFinished() {
// regression test for #14337
val style = mockk<Style>(relaxed = true)
val builder = mockk<Style.Builder>(relaxed = true)
every { builder.build(nativeMapView) } returns style
val onStyleLoadedListener = mockk<Style.OnStyleLoaded>(relaxed = true)
mapboxMap.setStyle(builder, onStyleLoadedListener)
mapboxMap.setStyle(builder, onStyleLoadedListener)
mapboxMap.onFinishLoadingStyle()
verify(exactly = 1) { onStyleLoadedListener.onStyleLoaded(style) }
}
}
mapboxMap.setStyle(builder, onStyleLoadedListener)
mapboxMap.setStyle(builder, onStyleLoadedListener)
mapboxMap.onFinishLoadingStyle()
verify(exactly = 1) { onStyleLoadedListener.onStyleLoaded(style) }
}
}

View File

@@ -155,9 +155,11 @@ class StyleBuilderTest {
drawable.intrinsicHeight = 1
val builder = Style.Builder()
builder.withImage("id", drawable)
assertTrue(BitmapUtils.equals(
assertTrue(
BitmapUtils.equals(
BitmapUtils.getBitmapFromDrawable(drawable)!!,
builder.images[0].bitmap)
builder.images[0].bitmap
)
)
assertEquals("id", builder.images[0].id)
assertEquals(false, builder.images[0].sdf)
@@ -170,9 +172,11 @@ class StyleBuilderTest {
drawable.intrinsicHeight = 1
val builder = Style.Builder()
builder.withImage("id", drawable, true)
assertTrue(BitmapUtils.equals(
assertTrue(
BitmapUtils.equals(
BitmapUtils.getBitmapFromDrawable(drawable)!!,
builder.images[0].bitmap)
builder.images[0].bitmap
)
)
assertEquals("id", builder.images[0].id)
assertEquals(true, builder.images[0].sdf)
@@ -188,15 +192,19 @@ class StyleBuilderTest {
drawable2.intrinsicHeight = 1
val builder = Style.Builder()
builder.withDrawableImages(Pair<String, Drawable>("id1", drawable1), Pair<String, Drawable>("id2", drawable2))
assertTrue(BitmapUtils.equals(
assertTrue(
BitmapUtils.equals(
BitmapUtils.getBitmapFromDrawable(drawable1)!!,
builder.images[0].bitmap)
builder.images[0].bitmap
)
)
assertEquals("id1", builder.images[0].id)
assertEquals(false, builder.images[0].sdf)
assertTrue(BitmapUtils.equals(
assertTrue(
BitmapUtils.equals(
BitmapUtils.getBitmapFromDrawable(drawable2)!!,
builder.images[1].bitmap)
builder.images[1].bitmap
)
)
assertEquals("id2", builder.images[1].id)
assertEquals(false, builder.images[1].sdf)
@@ -212,15 +220,19 @@ class StyleBuilderTest {
drawable2.intrinsicHeight = 1
val builder = Style.Builder()
builder.withDrawableImages(true, Pair<String, Drawable>("id1", drawable1), Pair<String, Drawable>("id2", drawable2))
assertTrue(BitmapUtils.equals(
assertTrue(
BitmapUtils.equals(
BitmapUtils.getBitmapFromDrawable(drawable1)!!,
builder.images[0].bitmap)
builder.images[0].bitmap
)
)
assertEquals("id1", builder.images[0].id)
assertEquals(true, builder.images[0].sdf)
assertTrue(BitmapUtils.equals(
assertTrue(
BitmapUtils.equals(
BitmapUtils.getBitmapFromDrawable(drawable2)!!,
builder.images[1].bitmap)
builder.images[1].bitmap
)
)
assertEquals("id2", builder.images[1].id)
assertEquals(true, builder.images[1].sdf)
@@ -234,4 +246,4 @@ class StyleBuilderTest {
assertEquals(100, builder.transitionOptions.duration)
assertEquals(200, builder.transitionOptions.delay)
}
}
}

View File

@@ -405,4 +405,4 @@ class StyleTest {
Assert.assertEquals("Layer that failed to be added shouldn't be cached", layer1, mapboxMap.style!!.getLayer("layer1"))
}
}
}
}

View File

@@ -12,191 +12,191 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class TransformTest {
private lateinit var mapView: MapView
private lateinit var nativeMapView: NativeMap
private lateinit var transform: Transform
private lateinit var cameraChangeDispatcher: CameraChangeDispatcher
private lateinit var mapView: MapView
private lateinit var nativeMapView: NativeMap
private lateinit var transform: Transform
private lateinit var cameraChangeDispatcher: CameraChangeDispatcher
@Before
fun setup() {
cameraChangeDispatcher = spyk()
mapView = mockk()
nativeMapView = mockk()
transform = Transform(mapView, nativeMapView, cameraChangeDispatcher)
every { nativeMapView.isDestroyed } returns false
every { nativeMapView.cameraPosition } returns CameraPosition.DEFAULT
every { nativeMapView.cancelTransitions() } answers {}
every { nativeMapView.jumpTo(any(), any(), any(), any(), any()) } answers {}
every { nativeMapView.easeTo(any(), any(), any(), any(), any(), any(), any()) } answers {}
every { nativeMapView.flyTo(any(), any(), any(), any(), any(), any()) } answers {}
every { nativeMapView.minZoom = any() } answers {}
every { nativeMapView.maxZoom = any() } answers {}
every { nativeMapView.minPitch = any() } answers {}
every { nativeMapView.maxPitch = any() } answers {}
}
@Test
fun testMoveCamera() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.cameraPosition
every { nativeMapView.cameraPosition } returns expected
transform.moveCamera(mapboxMap, update, callback)
verify { cameraChangeDispatcher.onCameraMove() }
verify { nativeMapView.jumpTo(target, -1.0, -1.0, -1.0, null) }
verify { callback.onFinish() }
}
@Test
fun testMoveCameraToSamePosition() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val expected = CameraPosition.DEFAULT
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.moveCamera(mapboxMap, update, null) // Initialize camera position
transform.moveCamera(mapboxMap, update, callback)
verify(exactly = 1, verifyBlock = { nativeMapView.jumpTo(any(), any(), any(), any(), any()) })
verify { callback.onFinish() }
}
@Test
fun testEaseCamera() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
every { mapView.addOnCameraDidChangeListener(any()) } answers { transform.onCameraDidChange(true) }
every { mapView.removeOnCameraDidChangeListener(any()) } answers {}
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.easeCamera(mapboxMap, update, 100, false, callback)
verify { nativeMapView.easeTo(target, -1.0, -1.0, -1.0, null, 100, false) }
verify { callback.onFinish() }
}
@Test
fun testEaseCameraToSamePosition() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val expected = CameraPosition.DEFAULT
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.moveCamera(mapboxMap, update, null)
transform.easeCamera(mapboxMap, update, 100, false, callback)
verify(exactly = 0, verifyBlock = { nativeMapView.easeTo(any(), any(), any(), any(), any(), any(), any()) })
verify { callback.onFinish() }
}
@Test
fun testAnimateCamera() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
every { mapView.addOnCameraDidChangeListener(any()) } answers { transform.onCameraDidChange(true) }
every { mapView.removeOnCameraDidChangeListener(any()) } answers {}
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.animateCamera(mapboxMap, update, 100, callback)
verify { nativeMapView.flyTo(target, -1.0, -1.0, -1.0, null, 100) }
verify { callback.onFinish() }
}
@Test
fun testAnimateCameraToSamePosition() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val expected = CameraPosition.DEFAULT
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.moveCamera(mapboxMap, update, null)
transform.animateCamera(mapboxMap, update, 100, callback)
verify(exactly = 0, verifyBlock = { nativeMapView.flyTo(any(), any(), any(), any(), any(), any()) })
verify { callback.onFinish() }
}
@Test
fun testMinZoom() {
transform.minZoom = 10.0
verify { nativeMapView.minZoom = 10.0 }
}
@Test
fun testMaxZoom() {
transform.maxZoom = 10.0
verify { nativeMapView.maxZoom = 10.0 }
}
@Test
fun testMinPitch() {
transform.minPitch = 10.0
verify { nativeMapView.minPitch = 10.0 }
}
@Test
fun testMaxPitch() {
transform.maxPitch = 10.0
verify { nativeMapView.maxPitch = 10.0 }
}
@Test
fun testCancelNotInvokedFromOnFinish() {
val slot = slot<MapView.OnCameraDidChangeListener>()
every { mapView.addOnCameraDidChangeListener(capture(slot)) } answers { slot.captured.onCameraDidChange(true) }
every { mapView.removeOnCameraDidChangeListener(any()) } answers {}
// regression test for https://github.com/mapbox/mapbox-gl-native/issues/13735
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val callback = object : MapboxMap.CancelableCallback {
override fun onCancel() {
throw IllegalStateException("onCancel shouldn't be called from onFinish")
}
override fun onFinish() {
transform.animateCamera(mapboxMap, CameraUpdateFactory.newCameraPosition(expected), 500, null)
}
@Before
fun setup() {
cameraChangeDispatcher = spyk()
mapView = mockk()
nativeMapView = mockk()
transform = Transform(mapView, nativeMapView, cameraChangeDispatcher)
every { nativeMapView.isDestroyed } returns false
every { nativeMapView.cameraPosition } returns CameraPosition.DEFAULT
every { nativeMapView.cancelTransitions() } answers {}
every { nativeMapView.jumpTo(any(), any(), any(), any(), any()) } answers {}
every { nativeMapView.easeTo(any(), any(), any(), any(), any(), any(), any()) } answers {}
every { nativeMapView.flyTo(any(), any(), any(), any(), any(), any()) } answers {}
every { nativeMapView.minZoom = any() } answers {}
every { nativeMapView.maxZoom = any() } answers {}
every { nativeMapView.minPitch = any() } answers {}
every { nativeMapView.maxPitch = any() } answers {}
}
transform.animateCamera(mapboxMap, CameraUpdateFactory.newCameraPosition(expected), 500, callback)
}
}
@Test
fun testMoveCamera() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.cameraPosition
every { nativeMapView.cameraPosition } returns expected
transform.moveCamera(mapboxMap, update, callback)
verify { cameraChangeDispatcher.onCameraMove() }
verify { nativeMapView.jumpTo(target, -1.0, -1.0, -1.0, null) }
verify { callback.onFinish() }
}
@Test
fun testMoveCameraToSamePosition() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val expected = CameraPosition.DEFAULT
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.moveCamera(mapboxMap, update, null) // Initialize camera position
transform.moveCamera(mapboxMap, update, callback)
verify(exactly = 1, verifyBlock = { nativeMapView.jumpTo(any(), any(), any(), any(), any()) })
verify { callback.onFinish() }
}
@Test
fun testEaseCamera() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
every { mapView.addOnCameraDidChangeListener(any()) } answers { transform.onCameraDidChange(true) }
every { mapView.removeOnCameraDidChangeListener(any()) } answers {}
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.easeCamera(mapboxMap, update, 100, false, callback)
verify { nativeMapView.easeTo(target, -1.0, -1.0, -1.0, null, 100, false) }
verify { callback.onFinish() }
}
@Test
fun testEaseCameraToSamePosition() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val expected = CameraPosition.DEFAULT
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.moveCamera(mapboxMap, update, null)
transform.easeCamera(mapboxMap, update, 100, false, callback)
verify(exactly = 0, verifyBlock = { nativeMapView.easeTo(any(), any(), any(), any(), any(), any(), any()) })
verify { callback.onFinish() }
}
@Test
fun testAnimateCamera() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
every { mapView.addOnCameraDidChangeListener(any()) } answers { transform.onCameraDidChange(true) }
every { mapView.removeOnCameraDidChangeListener(any()) } answers {}
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.animateCamera(mapboxMap, update, 100, callback)
verify { nativeMapView.flyTo(target, -1.0, -1.0, -1.0, null, 100) }
verify { callback.onFinish() }
}
@Test
fun testAnimateCameraToSamePosition() {
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
val callback = mockk<MapboxMap.CancelableCallback>()
every { callback.onFinish() } answers {}
val expected = CameraPosition.DEFAULT
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.moveCamera(mapboxMap, update, null)
transform.animateCamera(mapboxMap, update, 100, callback)
verify(exactly = 0, verifyBlock = { nativeMapView.flyTo(any(), any(), any(), any(), any(), any()) })
verify { callback.onFinish() }
}
@Test
fun testMinZoom() {
transform.minZoom = 10.0
verify { nativeMapView.minZoom = 10.0 }
}
@Test
fun testMaxZoom() {
transform.maxZoom = 10.0
verify { nativeMapView.maxZoom = 10.0 }
}
@Test
fun testMinPitch() {
transform.minPitch = 10.0
verify { nativeMapView.minPitch = 10.0 }
}
@Test
fun testMaxPitch() {
transform.maxPitch = 10.0
verify { nativeMapView.maxPitch = 10.0 }
}
@Test
fun testCancelNotInvokedFromOnFinish() {
val slot = slot<MapView.OnCameraDidChangeListener>()
every { mapView.addOnCameraDidChangeListener(capture(slot)) } answers { slot.captured.onCameraDidChange(true) }
every { mapView.removeOnCameraDidChangeListener(any()) } answers {}
// regression test for https://github.com/mapbox/mapbox-gl-native/issues/13735
val mapboxMap = mockk<MapboxMap>()
every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
val target = LatLng(1.0, 2.0)
val expected = CameraPosition.Builder().target(target).build()
val callback = object : MapboxMap.CancelableCallback {
override fun onCancel() {
throw IllegalStateException("onCancel shouldn't be called from onFinish")
}
override fun onFinish() {
transform.animateCamera(mapboxMap, CameraUpdateFactory.newCameraPosition(expected), 500, null)
}
}
transform.animateCamera(mapboxMap, CameraUpdateFactory.newCameraPosition(expected), 500, callback)
}
}

View File

@@ -13,55 +13,55 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class HttpRequestUrlTest {
@Before
fun setUp() {
MapboxInjector.inject(mockk(relaxed = true), "pk.foobar", "foobar")
}
@Before
fun setUp() {
MapboxInjector.inject(mockk(relaxed = true), "pk.foobar", "foobar")
}
@Test
fun testOfflineFlagMapboxCom() {
val expected = "http://mapbox.com/path/of/no/return.pbf?offline=true"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.com", "http://mapbox.com/path/of/no/return.pbf", 0, true)
assertEquals(expected, actual)
}
@Test
fun testOfflineFlagMapboxCom() {
val expected = "http://mapbox.com/path/of/no/return.pbf?offline=true"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.com", "http://mapbox.com/path/of/no/return.pbf", 0, true)
assertEquals(expected, actual)
}
@Test
fun testOfflineFlagMapboxCn() {
val expected = "http://mapbox.cn/path/of/no/return.pbf?offline=true"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.cn", "http://mapbox.cn/path/of/no/return.pbf", 0, true)
assertEquals(expected, actual)
}
@Test
fun testOfflineFlagMapboxCn() {
val expected = "http://mapbox.cn/path/of/no/return.pbf?offline=true"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.cn", "http://mapbox.cn/path/of/no/return.pbf", 0, true)
assertEquals(expected, actual)
}
@Test
fun testOfflineFlagInvalidHost() {
val expected = "http://foobar.com/path/of/no/return.pbf"
val actual = HttpRequestUrl.buildResourceUrl("foobar.com", "http://foobar.com/path/of/no/return.pbf", 0, true)
assertEquals(expected, actual)
}
@Test
fun testOfflineFlagInvalidHost() {
val expected = "http://foobar.com/path/of/no/return.pbf"
val actual = HttpRequestUrl.buildResourceUrl("foobar.com", "http://foobar.com/path/of/no/return.pbf", 0, true)
assertEquals(expected, actual)
}
@Test
fun testOnlineMapboxCom() {
val expected = "http://mapbox.com/path/of/no/return.pbf?sku=foobar"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.com", "http://mapbox.com/path/of/no/return.pbf", 0, false)
assertEquals(expected, actual)
}
@Test
fun testOnlineMapboxCom() {
val expected = "http://mapbox.com/path/of/no/return.pbf?sku=foobar"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.com", "http://mapbox.com/path/of/no/return.pbf", 0, false)
assertEquals(expected, actual)
}
@Test
fun testOnlineMapboxCn() {
val expected = "http://mapbox.cn/path/of/no/return.pbf?sku=foobar"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.cn", "http://mapbox.cn/path/of/no/return.pbf", 0, false)
assertEquals(expected, actual)
}
@Test
fun testOnlineMapboxCn() {
val expected = "http://mapbox.cn/path/of/no/return.pbf?sku=foobar"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.cn", "http://mapbox.cn/path/of/no/return.pbf", 0, false)
assertEquals(expected, actual)
}
@Test
fun testOnlineInvalidHost() {
val expected = "http://foobar.com/path/of/no/return.pbf"
val actual = HttpRequestUrl.buildResourceUrl("foobar.com", "http://foobar.com/path/of/no/return.pbf", 0, false)
assertEquals(expected, actual)
}
@Test
fun testOnlineInvalidHost() {
val expected = "http://foobar.com/path/of/no/return.pbf"
val actual = HttpRequestUrl.buildResourceUrl("foobar.com", "http://foobar.com/path/of/no/return.pbf", 0, false)
assertEquals(expected, actual)
}
@After
fun tearDown() {
MapboxInjector.clear()
}
}
@After
fun tearDown() {
MapboxInjector.clear()
}
}

View File

@@ -11,25 +11,27 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class HttpRequestUtilTest {
@Test
fun replaceHttpClient() {
MapboxInjector.inject(mockk(relaxed = true), "")
@Test
fun replaceHttpClient() {
MapboxInjector.inject(mockk(relaxed = true), "")
assertEquals(HttpRequestImpl.DEFAULT_CLIENT, HttpRequestImpl.client)
assertEquals(HttpRequestImpl.DEFAULT_CLIENT, HttpRequestImpl.client)
val httpMock = mockk<OkHttpClient>()
HttpRequestUtil.setOkHttpClient(httpMock)
assertEquals("Http client should have set to the mocked client",
httpMock,
HttpRequestImpl.client
)
val httpMock = mockk<OkHttpClient>()
HttpRequestUtil.setOkHttpClient(httpMock)
assertEquals(
"Http client should have set to the mocked client",
httpMock,
HttpRequestImpl.client
)
HttpRequestUtil.setOkHttpClient(null)
assertEquals("Http client should have been reset to the default client",
HttpRequestImpl.DEFAULT_CLIENT,
HttpRequestImpl.client
)
HttpRequestUtil.setOkHttpClient(null)
assertEquals(
"Http client should have been reset to the default client",
HttpRequestImpl.DEFAULT_CLIENT,
HttpRequestImpl.client
)
MapboxInjector.clear()
}
}
MapboxInjector.clear()
}
}

View File

@@ -6,17 +6,17 @@ import org.junit.Test
class ColorUtilsTest {
@Test
fun rgbaToColor_decimalComponent() {
val input = "rgba(255,128.0000952303,0,0.7)"
val result = ColorUtils.rgbaToColor(input)
Assert.assertEquals(Color.argb(255, 128, 0, (0.7 * 255).toInt()), result)
}
@Test
fun rgbaToColor_decimalComponent() {
val input = "rgba(255,128.0000952303,0,0.7)"
val result = ColorUtils.rgbaToColor(input)
Assert.assertEquals(Color.argb(255, 128, 0, (0.7 * 255).toInt()), result)
}
@Test
fun rgbaToColor_decimalComponent_floor() {
val input = "rgba(255,128.70123,0,0.7)"
val result = ColorUtils.rgbaToColor(input)
Assert.assertEquals(Color.argb(255, 128, 0, (0.7 * 255).toInt()), result)
}
}
@Test
fun rgbaToColor_decimalComponent_floor() {
val input = "rgba(255,128.70123,0,0.7)"
val result = ColorUtils.rgbaToColor(input)
Assert.assertEquals(Color.argb(255, 128, 0, (0.7 * 255).toInt()), result)
}
}

View File

@@ -7,69 +7,79 @@ import com.intellij.psi.PsiType
import org.jetbrains.uast.*
class KeepDetector : Detector(), SourceCodeScanner, FileScanner {
companion object {
private val DETECTOR_CLASS = KeepDetector::class.java
private val DETECTOR_SCOPE = Scope.JAVA_FILE_SCOPE
private val IMPLEMENTATION = Implementation(DETECTOR_CLASS, DETECTOR_SCOPE)
companion object {
private val DETECTOR_CLASS = KeepDetector::class.java
private val DETECTOR_SCOPE = Scope.JAVA_FILE_SCOPE
private val IMPLEMENTATION = Implementation(DETECTOR_CLASS, DETECTOR_SCOPE)
private const val ISSUE_ID = "KeepMissing"
private const val ISSUE_DESCRIPTION = "Element cannot be minified."
private const val ISSUE_EXPLANATION = "This class, method or field might contain native references. " +
"It has to be annotated with @Keep if it cannot be obfuscated/removed, otherwise, the warning should be suppressed. " +
"There can also be another methods/fields of this class that cannot be obfuscated/removed, " +
"look closely for any methods that are referenced from the JNI context."
private val ISSUE_CATEGORY = Category.CORRECTNESS
private const val ISSUE_PRIORITY = 9
private val ISSUE_SEVERITY = Severity.ERROR
private const val ISSUE_ID = "KeepMissing"
private const val ISSUE_DESCRIPTION = "Element cannot be minified."
private const val ISSUE_EXPLANATION = "This class, method or field might contain native references. " +
"It has to be annotated with @Keep if it cannot be obfuscated/removed, otherwise, the warning should be suppressed. " +
"There can also be another methods/fields of this class that cannot be obfuscated/removed, " +
"look closely for any methods that are referenced from the JNI context."
private val ISSUE_CATEGORY = Category.CORRECTNESS
private const val ISSUE_PRIORITY = 9
private val ISSUE_SEVERITY = Severity.ERROR
var ISSUE_NOT_KEPT = Issue.create(
ISSUE_ID,
ISSUE_DESCRIPTION,
ISSUE_EXPLANATION,
ISSUE_CATEGORY,
ISSUE_PRIORITY,
ISSUE_SEVERITY,
IMPLEMENTATION
)
}
override fun getApplicableUastTypes(): List<Class<out UElement>>? =
listOf(UMethod::class.java, UField::class.java)
override fun createUastHandler(context: JavaContext): UElementHandler? = KeepHandler(context)
class KeepHandler(private val context: JavaContext) : UElementHandler() {
override fun visitMethod(node: UMethod) {
if (node.hasModifier(JvmModifier.NATIVE) && checkKeepAnnotation(node)) {
context.report(ISSUE_NOT_KEPT, node,
context.getNameLocation(node),
"This method contains native references and will be minified.")
} else if (node.isConstructor &&
node.parameterList.parameters.find { it.type == PsiType.LONG && it.name!!.contains("native") } != null &&
checkKeepAnnotation(node)) {
context.report(ISSUE_NOT_KEPT, node,
context.getNameLocation(node as UElement),
"This constructor might contain native references and will be minified. " +
"Either suppress the warning or use @Keep.")
}
var ISSUE_NOT_KEPT = Issue.create(
ISSUE_ID,
ISSUE_DESCRIPTION,
ISSUE_EXPLANATION,
ISSUE_CATEGORY,
ISSUE_PRIORITY,
ISSUE_SEVERITY,
IMPLEMENTATION
)
}
override fun visitField(node: UField) {
if (node.type == PsiType.LONG && node.name.contains("native") && checkKeepAnnotation(node)) {
context.report(ISSUE_NOT_KEPT, node,
context.getNameLocation(node as UElement),
"This field might contain native references and will be minified. " +
"Either suppress the warning or use @Keep.")
}
}
override fun getApplicableUastTypes(): List<Class<out UElement>>? =
listOf(UMethod::class.java, UField::class.java)
private fun checkKeepAnnotation(uAnnotated: UAnnotated): Boolean {
return !hasKeepAnnotation(uAnnotated) && !hasKeepAnnotation(uAnnotated.getContainingUClass()!!)
}
override fun createUastHandler(context: JavaContext): UElementHandler? = KeepHandler(context)
private fun hasKeepAnnotation(uAnnotated: UAnnotated): Boolean {
return uAnnotated.findAnnotation("androidx.annotation.Keep") != null
class KeepHandler(private val context: JavaContext) : UElementHandler() {
override fun visitMethod(node: UMethod) {
if (node.hasModifier(JvmModifier.NATIVE) && checkKeepAnnotation(node)) {
context.report(
ISSUE_NOT_KEPT,
node,
context.getNameLocation(node),
"This method contains native references and will be minified."
)
} else if (node.isConstructor &&
node.parameterList.parameters.find { it.type == PsiType.LONG && it.name!!.contains("native") } != null &&
checkKeepAnnotation(node)
) {
context.report(
ISSUE_NOT_KEPT,
node,
context.getNameLocation(node as UElement),
"This constructor might contain native references and will be minified. " +
"Either suppress the warning or use @Keep."
)
}
}
override fun visitField(node: UField) {
if (node.type == PsiType.LONG && node.name.contains("native") && checkKeepAnnotation(node)) {
context.report(
ISSUE_NOT_KEPT,
node,
context.getNameLocation(node as UElement),
"This field might contain native references and will be minified. " +
"Either suppress the warning or use @Keep."
)
}
}
private fun checkKeepAnnotation(uAnnotated: UAnnotated): Boolean {
return !hasKeepAnnotation(uAnnotated) && !hasKeepAnnotation(uAnnotated.getContainingUClass()!!)
}
private fun hasKeepAnnotation(uAnnotated: UAnnotated): Boolean {
return uAnnotated.findAnnotation("androidx.annotation.Keep") != null
}
}
}
}
}

View File

@@ -5,9 +5,9 @@ import com.android.tools.lint.detector.api.CURRENT_API
import com.android.tools.lint.detector.api.Issue
class MapboxIssueRegistry : IssueRegistry() {
override val issues: List<Issue>
get() = listOf(KeepDetector.ISSUE_NOT_KEPT)
override val issues: List<Issue>
get() = listOf(KeepDetector.ISSUE_NOT_KEPT)
override val api: Int
get() = CURRENT_API
}
override val api: Int
get() = CURRENT_API
}

View File

@@ -9,20 +9,24 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class KeepDetectorTest {
@Test
fun correctClassName() {
lint()
.allowMissingSdk()
.files(java("""
@Test
fun correctClassName() {
lint()
.allowMissingSdk()
.files(
java(
"""
|package foo;
|
|import android.support.annotation.Keep;
|
|@Keep
|class TestClass {
|}""".trimMargin()))
.issues(KeepDetector.ISSUE_NOT_KEPT)
.run()
.expectClean()
}
}
|}""".trimMargin()
)
)
.issues(KeepDetector.ISSUE_NOT_KEPT)
.run()
.expectClean()
}
}

View File

@@ -12,4 +12,4 @@ abstract class AppCenter {
open fun afterTest() {
reportHelper.label(javaClass.simpleName)
}
}
}

View File

@@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk
import com.mapbox.mapboxsdk.testapp.MapboxApplication
class InstrumentationApplication : MapboxApplication() {
override fun initializeLeakCanary(): Boolean {
// do not initialize leak canary during instrumentation tests
return true
}
}
override fun initializeLeakCanary(): Boolean {
// do not initialize leak canary during instrumentation tests
return true
}
}

View File

@@ -5,7 +5,7 @@ import android.content.Context
import androidx.test.runner.AndroidJUnitRunner
class InstrumentationRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application {
return super.newApplication(cl, InstrumentationApplication::class.java.name, context)
}
}
override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application {
return super.newApplication(cl, InstrumentationApplication::class.java.name, context)
}
}

View File

@@ -16,171 +16,171 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class CameraUpdateFactoryTest : BaseTest() {
override fun getActivityClass(): Class<*> {
return DeviceIndependentTestActivity::class.java
}
override fun getActivityClass(): Class<*> {
return DeviceIndependentTestActivity::class.java
}
@Test
@UiThreadTest
fun testLatLngBoundsUntiltedUnrotated() {
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(60.0, 24.0))
.bearing(0.0)
.tilt(0.0)
.build()
@Test
@UiThreadTest
fun testLatLngBoundsUntiltedUnrotated() {
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(60.0, 24.0))
.bearing(0.0)
.tilt(0.0)
.build()
val bounds: LatLngBounds = LatLngBounds.Builder()
.include(LatLng(62.0, 26.0))
.include(LatLng(58.0, 22.0))
.build()
val bounds: LatLngBounds = LatLngBounds.Builder()
.include(LatLng(62.0, 26.0))
.include(LatLng(58.0, 22.0))
.build()
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
val cameraPosition = mapboxMap.cameraPosition
assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
assertEquals("zoom should match", 5.5, cameraPosition.zoom, 0.1)
assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
}
val cameraPosition = mapboxMap.cameraPosition
assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
assertEquals("zoom should match", 5.5, cameraPosition.zoom, 0.1)
assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
}
@Test
@UiThreadTest
fun testLatLngBoundsTilted() {
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(60.0, 24.0))
.bearing(0.0)
.tilt(45.0)
.build()
@Test
@UiThreadTest
fun testLatLngBoundsTilted() {
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(60.0, 24.0))
.bearing(0.0)
.tilt(45.0)
.build()
val bounds: LatLngBounds = LatLngBounds.Builder()
.include(LatLng(62.0, 26.0))
.include(LatLng(58.0, 22.0))
.build()
val bounds: LatLngBounds = LatLngBounds.Builder()
.include(LatLng(62.0, 26.0))
.include(LatLng(58.0, 22.0))
.build()
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
val cameraPosition = mapboxMap.cameraPosition
assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
assertEquals("zoom should match", 6.0, cameraPosition.zoom, 0.1)
assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
}
val cameraPosition = mapboxMap.cameraPosition
assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
assertEquals("zoom should match", 6.0, cameraPosition.zoom, 0.1)
assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
}
@Test
@UiThreadTest
fun testLatLngBoundsRotated() {
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(60.0, 24.0))
.bearing(30.0)
.tilt(0.0)
.build()
@Test
@UiThreadTest
fun testLatLngBoundsRotated() {
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(60.0, 24.0))
.bearing(30.0)
.tilt(0.0)
.build()
val bounds: LatLngBounds = LatLngBounds.Builder()
.include(LatLng(62.0, 26.0))
.include(LatLng(58.0, 22.0))
.build()
val bounds: LatLngBounds = LatLngBounds.Builder()
.include(LatLng(62.0, 26.0))
.include(LatLng(58.0, 22.0))
.build()
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
val cameraPosition = mapboxMap.cameraPosition
assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
assertEquals("zoom should match", 5.3, cameraPosition.zoom, 0.1)
assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
}
val cameraPosition = mapboxMap.cameraPosition
assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
assertEquals("zoom should match", 5.3, cameraPosition.zoom, 0.1)
assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
}
@Test
@UiThreadTest
fun testLatLngBoundsTiltedRotated() {
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(60.0, 24.0))
.bearing(30.0)
.tilt(45.0)
.build()
@Test
@UiThreadTest
fun testLatLngBoundsTiltedRotated() {
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(60.0, 24.0))
.bearing(30.0)
.tilt(45.0)
.build()
val bounds: LatLngBounds = LatLngBounds.Builder()
.include(LatLng(62.0, 26.0))
.include(LatLng(58.0, 22.0))
.build()
val bounds: LatLngBounds = LatLngBounds.Builder()
.include(LatLng(62.0, 26.0))
.include(LatLng(58.0, 22.0))
.build()
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
val cameraPosition = mapboxMap.cameraPosition
assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
}
val cameraPosition = mapboxMap.cameraPosition
assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
}
@Test
@UiThreadTest
fun testLatLngBoundsWithProvidedTiltAndRotation() {
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(60.0, 24.0))
.bearing(0.0)
.tilt(0.0)
.build()
@Test
@UiThreadTest
fun testLatLngBoundsWithProvidedTiltAndRotation() {
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(60.0, 24.0))
.bearing(0.0)
.tilt(0.0)
.build()
val bounds: LatLngBounds = LatLngBounds.Builder()
.include(LatLng(62.0, 26.0))
.include(LatLng(58.0, 22.0))
.build()
val bounds: LatLngBounds = LatLngBounds.Builder()
.include(LatLng(62.0, 26.0))
.include(LatLng(58.0, 22.0))
.build()
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30.0, 40.0, 0))
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30.0, 40.0, 0))
val cameraPosition = mapboxMap.cameraPosition
assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
assertEquals("tilt should match:", 40.0, cameraPosition.tilt, 0.1)
}
val cameraPosition = mapboxMap.cameraPosition
assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
assertEquals("tilt should match:", 40.0, cameraPosition.tilt, 0.1)
}
@Test
@UiThreadTest
fun withPadding_cameraInvalidated_paddingPersisting() {
val initialCameraPosition = mapboxMap.cameraPosition
val initialPoint = mapboxMap.projection.toScreenLocation(initialCameraPosition.target)
@Test
@UiThreadTest
fun withPadding_cameraInvalidated_paddingPersisting() {
val initialCameraPosition = mapboxMap.cameraPosition
val initialPoint = mapboxMap.projection.toScreenLocation(initialCameraPosition.target)
val bottomPadding = mapView.height / 4
val leftPadding = mapView.width / 4
val padding = doubleArrayOf(leftPadding.toDouble(), 0.0, 0.0, bottomPadding.toDouble())
mapboxMap.moveCamera(CameraUpdateFactory.paddingTo(leftPadding.toDouble(), 0.0, 0.0, bottomPadding.toDouble()))
val bottomPadding = mapView.height / 4
val leftPadding = mapView.width / 4
val padding = doubleArrayOf(leftPadding.toDouble(), 0.0, 0.0, bottomPadding.toDouble())
mapboxMap.moveCamera(CameraUpdateFactory.paddingTo(leftPadding.toDouble(), 0.0, 0.0, bottomPadding.toDouble()))
Assert.assertArrayEquals(intArrayOf(leftPadding, 0, 0, bottomPadding), mapboxMap.padding)
Assert.assertArrayEquals(intArrayOf(leftPadding, 0, 0, bottomPadding), mapboxMap.padding)
val resultingCameraPosition = mapboxMap.cameraPosition
assertEquals(initialCameraPosition.target, resultingCameraPosition.target)
assertEquals(
PointF(initialPoint.x + leftPadding / 2, initialPoint.y - bottomPadding / 2),
mapboxMap.projection.toScreenLocation(resultingCameraPosition.target)
)
Assert.assertArrayEquals(padding, resultingCameraPosition.padding, 0.0001)
}
val resultingCameraPosition = mapboxMap.cameraPosition
assertEquals(initialCameraPosition.target, resultingCameraPosition.target)
assertEquals(
PointF(initialPoint.x + leftPadding / 2, initialPoint.y - bottomPadding / 2),
mapboxMap.projection.toScreenLocation(resultingCameraPosition.target)
)
Assert.assertArrayEquals(padding, resultingCameraPosition.padding, 0.0001)
}
@Test
@UiThreadTest
fun withLatLngPadding_cameraInvalidated_paddingPersisting() {
val expectedTarget = LatLng(2.0, 2.0)
@Test
@UiThreadTest
fun withLatLngPadding_cameraInvalidated_paddingPersisting() {
val expectedTarget = LatLng(2.0, 2.0)
val topPadding = mapView.height / 4
val rightPadding = mapView.width / 4
val padding = doubleArrayOf(0.0, topPadding.toDouble(), rightPadding.toDouble(), 0.0)
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngPadding(expectedTarget, 0.0, topPadding.toDouble(), rightPadding.toDouble(), 0.0))
val topPadding = mapView.height / 4
val rightPadding = mapView.width / 4
val padding = doubleArrayOf(0.0, topPadding.toDouble(), rightPadding.toDouble(), 0.0)
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngPadding(expectedTarget, 0.0, topPadding.toDouble(), rightPadding.toDouble(), 0.0))
Assert.assertArrayEquals(intArrayOf(0, topPadding, rightPadding, 0), mapboxMap.padding)
Assert.assertArrayEquals(intArrayOf(0, topPadding, rightPadding, 0), mapboxMap.padding)
val resultingCameraPosition = mapboxMap.cameraPosition
assertEquals(expectedTarget.latitude, resultingCameraPosition.target.latitude, 0.1)
assertEquals(expectedTarget.longitude, resultingCameraPosition.target.longitude, 0.1)
val resultingCameraPosition = mapboxMap.cameraPosition
assertEquals(expectedTarget.latitude, resultingCameraPosition.target.latitude, 0.1)
assertEquals(expectedTarget.longitude, resultingCameraPosition.target.longitude, 0.1)
val centerLatLng = mapboxMap.projection.fromScreenLocation(PointF((mapView.width / 2).toFloat(), (mapView.height / 2).toFloat()))
assertTrue(centerLatLng.latitude > resultingCameraPosition.target.latitude)
assertTrue(centerLatLng.longitude > resultingCameraPosition.target.longitude)
Assert.assertArrayEquals(padding, resultingCameraPosition.padding, 0.0001)
}
}
val centerLatLng = mapboxMap.projection.fromScreenLocation(PointF((mapView.width / 2).toFloat(), (mapView.height / 2).toFloat()))
assertTrue(centerLatLng.latitude > resultingCameraPosition.target.latitude)
assertTrue(centerLatLng.longitude > resultingCameraPosition.target.longitude)
Assert.assertArrayEquals(padding, resultingCameraPosition.padding, 0.0001)
}
}

View File

@@ -12,12 +12,12 @@ const val TIMEOUT_UI_SEARCH_WAIT = 5000L
abstract class BaseIntegrationTest : AppCenter() {
protected lateinit var device: UiDevice
protected lateinit var device: UiDevice
@Before
open fun beforeTest() {
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
}
@Before
open fun beforeTest() {
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
}
}
/**
@@ -27,14 +27,14 @@ abstract class BaseIntegrationTest : AppCenter() {
* <p>
*/
fun UiDevice.launchActivity(context: Context, clazz: Class<*>) {
val applicationPackage = InstrumentationRegistry.getInstrumentation().targetContext.packageName
val intent = Intent(context, clazz)
intent.addFlags(FLAG_ACTIVITY_NEW_TASK)
InstrumentationRegistry.getInstrumentation().context.startActivity(intent)
wait(Until.hasObject(By.pkg(applicationPackage).depth(0)), TIMEOUT_UI_SEARCH_WAIT)
val applicationPackage = InstrumentationRegistry.getInstrumentation().targetContext.packageName
val intent = Intent(context, clazz)
intent.addFlags(FLAG_ACTIVITY_NEW_TASK)
InstrumentationRegistry.getInstrumentation().context.startActivity(intent)
wait(Until.hasObject(By.pkg(applicationPackage).depth(0)), TIMEOUT_UI_SEARCH_WAIT)
}
fun UiDevice.scrollRecyclerViewTo(recycleItem: String) {
val appView = UiScrollable(UiSelector().scrollable(true))
appView.scrollIntoView(UiSelector().text(recycleItem))
}
val appView = UiScrollable(UiSelector().scrollable(true))
appView.scrollIntoView(UiSelector().text(recycleItem))
}

View File

@@ -15,31 +15,31 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class FragmentBackStackTest : BaseIntegrationTest() {
@get:Rule
var activityRule: ActivityTestRule<FragmentBackStackActivity> = ActivityTestRule(FragmentBackStackActivity::class.java)
@get:Rule
var activityRule: ActivityTestRule<FragmentBackStackActivity> = ActivityTestRule(FragmentBackStackActivity::class.java)
@Test
@LargeTest
fun backPressedOnBackStackResumed() {
device.waitForIdle()
clickReplaceFragmentButton()
device.pressHome()
device.waitForIdle()
device.launchActivity(activityRule.activity.applicationContext, FragmentBackStackActivity::class.java)
backPressBackStack()
device.waitForIdle()
}
@Test
@LargeTest
fun backPressedOnBackStackResumed() {
device.waitForIdle()
clickReplaceFragmentButton()
device.pressHome()
device.waitForIdle()
device.launchActivity(activityRule.activity.applicationContext, FragmentBackStackActivity::class.java)
backPressBackStack()
device.waitForIdle()
}
private fun clickReplaceFragmentButton() {
device.findObject(UiSelector().description(textDescription)).click()
}
private fun clickReplaceFragmentButton() {
device.findObject(UiSelector().description(textDescription)).click()
}
private fun backPressBackStack() {
device.pressBack() // pops fragment, showing map
device.pressBack() // finish activity
}
private fun backPressBackStack() {
device.pressBack() // pops fragment, showing map
device.pressBack() // finish activity
}
private companion object {
const val textDescription = "btn_change_fragment"
}
}
private companion object {
const val textDescription = "btn_change_fragment"
}
}

View File

@@ -14,16 +14,16 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class GLSurfaceViewReopenTest : BaseIntegrationTest() {
@get:Rule
var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java)
@get:Rule
var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java)
@Test
@LargeTest
fun reopenSimpleMapActivity() {
device.waitForIdle()
device.pressHome()
device.waitForIdle()
device.launchActivity(activityRule.activity, SimpleMapActivity::class.java)
device.waitForIdle()
}
}
@Test
@LargeTest
fun reopenSimpleMapActivity() {
device.waitForIdle()
device.pressHome()
device.waitForIdle()
device.launchActivity(activityRule.activity, SimpleMapActivity::class.java)
device.waitForIdle()
}
}

View File

@@ -14,16 +14,16 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class GLSurfaceViewReuseTest : BaseIntegrationTest() {
@get:Rule
var activityRule: ActivityTestRule<GLSurfaceRecyclerViewActivity> = ActivityTestRule(GLSurfaceRecyclerViewActivity::class.java)
@get:Rule
var activityRule: ActivityTestRule<GLSurfaceRecyclerViewActivity> = ActivityTestRule(GLSurfaceRecyclerViewActivity::class.java)
@Test
@LargeTest
fun scrollRecyclerView() {
device.waitForIdle()
device.scrollRecyclerViewTo("Twenty-one")
device.waitForIdle()
device.scrollRecyclerViewTo("One")
device.waitForIdle()
}
}
@Test
@LargeTest
fun scrollRecyclerView() {
device.waitForIdle()
device.scrollRecyclerViewTo("Twenty-one")
device.waitForIdle()
device.scrollRecyclerViewTo("One")
device.waitForIdle()
}
}

View File

@@ -11,22 +11,22 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class OrientationChangeTest : BaseIntegrationTest() {
@get:Rule
var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java)
@get:Rule
var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java)
@Test
@LargeTest
fun rotateSimpleMap() {
device.setOrientationLeft()
device.waitForIdle()
device.setOrientationNatural()
device.waitForIdle()
device.setOrientationRight()
device.waitForIdle()
device.setOrientationNatural()
device.setOrientationLeft()
device.setOrientationNatural()
device.setOrientationRight()
device.setOrientationNatural()
}
}
@Test
@LargeTest
fun rotateSimpleMap() {
device.setOrientationLeft()
device.waitForIdle()
device.setOrientationNatural()
device.waitForIdle()
device.setOrientationRight()
device.waitForIdle()
device.setOrientationNatural()
device.setOrientationLeft()
device.setOrientationNatural()
device.setOrientationRight()
device.setOrientationNatural()
}
}

View File

@@ -14,17 +14,17 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class QueryRenderedFeaturesBoxCountTest : BaseIntegrationTest() {
@get:Rule
var activityRule: ActivityTestRule<QueryRenderedFeaturesBoxCountActivity> =
ActivityTestRule(QueryRenderedFeaturesBoxCountActivity::class.java)
@get:Rule
var activityRule: ActivityTestRule<QueryRenderedFeaturesBoxCountActivity> =
ActivityTestRule(QueryRenderedFeaturesBoxCountActivity::class.java)
@Test
@LargeTest
fun reopenQueryRendererFeaturesActivity() {
device.waitForIdle()
device.pressHome()
device.waitForIdle()
device.launchActivity(activityRule.activity, QueryRenderedFeaturesBoxCountActivity::class.java)
device.waitForIdle()
}
}
@Test
@LargeTest
fun reopenQueryRendererFeaturesActivity() {
device.waitForIdle()
device.pressHome()
device.waitForIdle()
device.launchActivity(activityRule.activity, QueryRenderedFeaturesBoxCountActivity::class.java)
device.waitForIdle()
}
}

View File

@@ -14,16 +14,16 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class TextureViewReopenTest : BaseIntegrationTest() {
@get:Rule
var activityRule: ActivityTestRule<TextureViewDebugModeActivity> = ActivityTestRule(TextureViewDebugModeActivity::class.java)
@get:Rule
var activityRule: ActivityTestRule<TextureViewDebugModeActivity> = ActivityTestRule(TextureViewDebugModeActivity::class.java)
@Test
@LargeTest
fun reopenTextureViewDebugActivity() {
device.waitForIdle()
device.pressHome()
device.waitForIdle()
device.launchActivity(activityRule.activity, TextureViewDebugModeActivity::class.java)
device.waitForIdle()
}
}
@Test
@LargeTest
fun reopenTextureViewDebugActivity() {
device.waitForIdle()
device.pressHome()
device.waitForIdle()
device.launchActivity(activityRule.activity, TextureViewDebugModeActivity::class.java)
device.waitForIdle()
}
}

View File

@@ -14,16 +14,16 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class TextureViewReuseTest : BaseIntegrationTest() {
@get:Rule
var activityRule: ActivityTestRule<TextureRecyclerViewActivity> = ActivityTestRule(TextureRecyclerViewActivity::class.java)
@get:Rule
var activityRule: ActivityTestRule<TextureRecyclerViewActivity> = ActivityTestRule(TextureRecyclerViewActivity::class.java)
@Test
@LargeTest
fun scrollRecyclerView() {
device.waitForIdle()
device.scrollRecyclerViewTo("Twenty-one")
device.waitForIdle()
device.scrollRecyclerViewTo("One")
device.waitForIdle()
}
}
@Test
@LargeTest
fun scrollRecyclerView() {
device.waitForIdle()
device.scrollRecyclerViewTo("Twenty-one")
device.waitForIdle()
device.scrollRecyclerViewTo("One")
device.waitForIdle()
}
}

View File

@@ -15,22 +15,22 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ViewPagerScrollTest : BaseIntegrationTest() {
@get:Rule
var activityRule: ActivityTestRule<ViewPagerActivity> = ActivityTestRule(ViewPagerActivity::class.java)
@get:Rule
var activityRule: ActivityTestRule<ViewPagerActivity> = ActivityTestRule(ViewPagerActivity::class.java)
@Test
@LargeTest
fun scrollViewPager() {
for (i in 1..4) {
clickTab(i)
@Test
@LargeTest
fun scrollViewPager() {
for (i in 1..4) {
clickTab(i)
}
for (i in 3 downTo 0) {
clickTab(i)
}
}
for (i in 3 downTo 0) {
clickTab(i)
private fun clickTab(index: Int) {
device.findObject(UiSelector().text("Page $index")).click()
}
}
private fun clickTab(index: Int) {
device.findObject(UiSelector().text("Page $index")).click()
}
}
}

View File

@@ -11,28 +11,29 @@ import com.mapbox.mapboxsdk.maps.Style
import org.hamcrest.Matcher
class LocationComponentAction(
private val mapboxMap: MapboxMap,
private val onPerformLocationComponentAction: OnPerformLocationComponentAction
private val mapboxMap: MapboxMap,
private val onPerformLocationComponentAction: OnPerformLocationComponentAction
) : ViewAction {
override fun getConstraints(): Matcher<View> {
return isDisplayed()
}
override fun getConstraints(): Matcher<View> {
return isDisplayed()
}
override fun getDescription(): String {
return javaClass.simpleName
}
override fun getDescription(): String {
return javaClass.simpleName
}
override fun perform(uiController: UiController, view: View) {
onPerformLocationComponentAction.onLocationComponentAction(
mapboxMap.locationComponent,
mapboxMap,
mapboxMap.style!!,
uiController,
view.context)
}
override fun perform(uiController: UiController, view: View) {
onPerformLocationComponentAction.onLocationComponentAction(
mapboxMap.locationComponent,
mapboxMap,
mapboxMap.style!!,
uiController,
view.context
)
}
interface OnPerformLocationComponentAction {
fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap, style: Style, uiController: UiController, context: Context)
}
}
interface OnPerformLocationComponentAction {
fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap, style: Style, uiController: UiController, context: Context)
}
}

View File

@@ -14,66 +14,69 @@ import com.mapbox.mapboxsdk.style.layers.Property
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
fun MapboxMap.querySourceFeatures(sourceId: String): List<Feature> {
return this.style!!.getSourceAs<GeoJsonSource>(sourceId)?.querySourceFeatures(null) ?: emptyList()
return this.style!!.getSourceAs<GeoJsonSource>(sourceId)?.querySourceFeatures(null) ?: emptyList()
}
fun MapboxMap.queryRenderedFeatures(location: Location, layerId: String): List<Feature> {
val latLng = LatLng(location.latitude, location.longitude)
val point = this.projection.toScreenLocation(latLng)
return this.queryRenderedFeatures(point, layerId)
val latLng = LatLng(location.latitude, location.longitude)
val point = this.projection.toScreenLocation(latLng)
return this.queryRenderedFeatures(point, layerId)
}
fun MapboxMap.isLayerVisible(layerId: String): Boolean {
return this.style!!.getLayer(layerId)?.visibility?.value?.equals(Property.VISIBLE)!!
return this.style!!.getLayer(layerId)?.visibility?.value?.equals(Property.VISIBLE)!!
}
class MapboxTestingUtils {
companion object {
companion object {
/**
* Used to increase style load time for stress testing.
*/
const val MAPBOX_HEAVY_STYLE = "asset://heavy_style.json"
/**
* Used to increase style load time for stress testing.
*/
const val MAPBOX_HEAVY_STYLE = "asset://heavy_style.json"
private const val DATA_PUSH_INTERVAL = 1L
private const val DATA_PUSH_INTERVAL = 1L
/**
* Pushes data updates every [DATA_PUSH_INTERVAL] milliseconds until the style has been loaded,
* checked with [StyleChangeIdlingResource].
*/
fun pushSourceUpdates(styleChangeIdlingResource: StyleChangeIdlingResource, update: () -> Unit) {
val mainHandler = Handler(Looper.getMainLooper())
val runnable = object : Runnable {
override fun run() {
update.invoke()
if (!styleChangeIdlingResource.isIdleNow) {
mainHandler.postDelayed(this, DATA_PUSH_INTERVAL)
}
/**
* Pushes data updates every [DATA_PUSH_INTERVAL] milliseconds until the style has been loaded,
* checked with [StyleChangeIdlingResource].
*/
fun pushSourceUpdates(styleChangeIdlingResource: StyleChangeIdlingResource, update: () -> Unit) {
val mainHandler = Handler(Looper.getMainLooper())
val runnable = object : Runnable {
override fun run() {
update.invoke()
if (!styleChangeIdlingResource.isIdleNow) {
mainHandler.postDelayed(this, DATA_PUSH_INTERVAL)
}
}
}
if (!styleChangeIdlingResource.isIdleNow) {
if (Looper.myLooper() == Looper.getMainLooper()) {
runnable.run()
} else {
mainHandler.post(runnable)
}
}
}
}
if (!styleChangeIdlingResource.isIdleNow) {
if (Looper.myLooper() == Looper.getMainLooper()) {
runnable.run()
} else {
mainHandler.post(runnable)
}
}
}
}
}
fun MapboxMap.addImageFromDrawable(string: String, drawable: Drawable) {
val bitmapFromDrawable = getBitmapFromDrawable(drawable)
this.style!!.addImage(string, bitmapFromDrawable)
val bitmapFromDrawable = getBitmapFromDrawable(drawable)
this.style!!.addImage(string, bitmapFromDrawable)
}
private fun getBitmapFromDrawable(drawable: Drawable): Bitmap {
if (drawable is BitmapDrawable) return drawable.bitmap
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth,
drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
if (drawable is BitmapDrawable) return drawable.bitmap
val bitmap = Bitmap.createBitmap(
drawable.intrinsicWidth,
drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}

View File

@@ -11,30 +11,30 @@ import com.mapbox.mapboxsdk.maps.Style
*/
class StyleChangeIdlingResource : IdlingResource {
private var callback: IdlingResource.ResourceCallback? = null
private var isIdle = true
private var callback: IdlingResource.ResourceCallback? = null
private var isIdle = true
override fun getName(): String {
return javaClass.simpleName
}
override fun isIdleNow(): Boolean {
return isIdle
}
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
this.callback = callback
}
private fun setIdle() {
isIdle = true
callback?.onTransitionToIdle()
}
fun waitForStyle(mapboxMap: MapboxMap, styleUrl: String) {
isIdle = false
mapboxMap.setStyle(Style.Builder().fromUri(styleUrl)) {
setIdle()
override fun getName(): String {
return javaClass.simpleName
}
}
}
override fun isIdleNow(): Boolean {
return isIdle
}
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
this.callback = callback
}
private fun setIdle() {
isIdle = true
callback?.onTransitionToIdle()
}
fun waitForStyle(mapboxMap: MapboxMap, styleUrl: String) {
isIdle = false
mapboxMap.setStyle(Style.Builder().fromUri(styleUrl)) {
setIdle()
}
}
}

View File

@@ -24,4 +24,4 @@ abstract class BaseLayerTest : AppCenter() {
fun setupLayer(layer: Layer) {
nativeMapView.addLayer(layer)
}
}
}

View File

@@ -13,143 +13,143 @@ import org.hamcrest.Matcher
object GesturesUiTestUtils {
private const val DEFAULT_GESTURE_DURATION = 500L
private const val DEFAULT_GESTURE_DURATION = 500L
fun pinch(
startSpan: Float,
endSpan: Float,
center: PointF? = null,
duration: Long = DEFAULT_GESTURE_DURATION
): ViewAction {
return object : ViewAction {
override fun getConstraints(): Matcher<View> {
return ViewMatchers.isEnabled()
}
fun pinch(
startSpan: Float,
endSpan: Float,
center: PointF? = null,
duration: Long = DEFAULT_GESTURE_DURATION
): ViewAction {
return object : ViewAction {
override fun getConstraints(): Matcher<View> {
return ViewMatchers.isEnabled()
}
override fun getDescription(): String = "Pinch $startSpan -> $endSpan"
override fun getDescription(): String = "Pinch $startSpan -> $endSpan"
override fun perform(uiController: UiController, view: View) {
var middlePosition = center
if (middlePosition == null) {
middlePosition = getCenterPointF(view)
override fun perform(uiController: UiController, view: View) {
var middlePosition = center
if (middlePosition == null) {
middlePosition = getCenterPointF(view)
}
val startPoint1 = PointF(middlePosition.x - startSpan / 2f, middlePosition.y)
val startPoint2 = PointF(middlePosition.x + startSpan / 2f, middlePosition.y)
val endPoint1 = PointF(middlePosition.x - endSpan / 2f, middlePosition.y)
val endPoint2 = PointF(middlePosition.x + endSpan / 2f, middlePosition.y)
performPinch(uiController, startPoint1, startPoint2, endPoint1, endPoint2, duration)
}
}
val startPoint1 = PointF(middlePosition.x - startSpan / 2f, middlePosition.y)
val startPoint2 = PointF(middlePosition.x + startSpan / 2f, middlePosition.y)
val endPoint1 = PointF(middlePosition.x - endSpan / 2f, middlePosition.y)
val endPoint2 = PointF(middlePosition.x + endSpan / 2f, middlePosition.y)
performPinch(uiController, startPoint1, startPoint2, endPoint1, endPoint2, duration)
}
}
}
fun quickScale(
deltaY: Float,
startPoint: PointF? = null,
withVelocity: Boolean = true,
duration: Long = DEFAULT_GESTURE_DURATION,
interrupt: Boolean = false
): ViewAction {
return object : ViewAction {
override fun getConstraints(): Matcher<View> = ViewMatchers.isEnabled()
fun quickScale(
deltaY: Float,
startPoint: PointF? = null,
withVelocity: Boolean = true,
duration: Long = DEFAULT_GESTURE_DURATION,
interrupt: Boolean = false
): ViewAction {
return object : ViewAction {
override fun getConstraints(): Matcher<View> = ViewMatchers.isEnabled()
override fun getDescription(): String = "quick scale ${deltaY}Y"
override fun getDescription(): String = "quick scale ${deltaY}Y"
override fun perform(uiController: UiController, view: View) {
var middlePosition = startPoint
if (middlePosition == null) {
middlePosition = getCenterPointF(view)
override fun perform(uiController: UiController, view: View) {
var middlePosition = startPoint
if (middlePosition == null) {
middlePosition = getCenterPointF(view)
}
val endPoint = PointF(middlePosition.x, middlePosition.y + deltaY)
performQuickScale(uiController, middlePosition, endPoint, withVelocity, duration, interrupt)
}
}
val endPoint = PointF(middlePosition.x, middlePosition.y + deltaY)
performQuickScale(uiController, middlePosition, endPoint, withVelocity, duration, interrupt)
}
}
}
fun move(
deltaX: Float,
deltaY: Float,
startPoint: PointF? = null,
withVelocity: Boolean = true,
duration: Long = DEFAULT_GESTURE_DURATION
): ViewAction {
return object : ViewAction {
override fun getConstraints(): Matcher<View> = ViewMatchers.isEnabled()
fun move(
deltaX: Float,
deltaY: Float,
startPoint: PointF? = null,
withVelocity: Boolean = true,
duration: Long = DEFAULT_GESTURE_DURATION
): ViewAction {
return object : ViewAction {
override fun getConstraints(): Matcher<View> = ViewMatchers.isEnabled()
override fun getDescription(): String = "move ${deltaX}X, ${deltaY}Y"
override fun getDescription(): String = "move ${deltaX}X, ${deltaY}Y"
override fun perform(uiController: UiController, view: View) {
var middlePosition = startPoint
if (middlePosition == null) {
middlePosition = getCenterPointF(view)
override fun perform(uiController: UiController, view: View) {
var middlePosition = startPoint
if (middlePosition == null) {
middlePosition = getCenterPointF(view)
}
val endPoint = PointF(middlePosition.x + deltaX, middlePosition.y + deltaY)
performMove(uiController, middlePosition, endPoint, withVelocity, duration)
}
}
val endPoint = PointF(middlePosition.x + deltaX, middlePosition.y + deltaY)
performMove(uiController, middlePosition, endPoint, withVelocity, duration)
}
}
}
private fun getCenterPointF(view: View): PointF {
val locationOnScreen = IntArray(2)
view.getLocationOnScreen(locationOnScreen)
val viewHeight = view.height * view.scaleY
val viewWidth = view.width * view.scaleX
return PointF(
(locationOnScreen[0] + viewWidth / 2).toInt().toFloat(),
(locationOnScreen[1] + viewHeight / 2).toInt().toFloat()
)
}
private fun getCenterPointF(view: View): PointF {
val locationOnScreen = IntArray(2)
view.getLocationOnScreen(locationOnScreen)
val viewHeight = view.height * view.scaleY
val viewWidth = view.width * view.scaleX
return PointF(
(locationOnScreen[0] + viewWidth / 2).toInt().toFloat(),
(locationOnScreen[1] + viewHeight / 2).toInt().toFloat()
)
}
// https://stackoverflow.com/a/46443628/9126211
private fun performPinch(
uiController: UiController,
startPoint1: PointF,
startPoint2: PointF,
endPoint1: PointF,
endPoint2: PointF,
duration: Long
) {
val eventMinInterval: Long = 10
val startTime = SystemClock.uptimeMillis()
var eventTime = startTime
var event: MotionEvent
var eventX1: Float = startPoint1.x
var eventY1: Float = startPoint1.y
var eventX2: Float = startPoint2.x
var eventY2: Float = startPoint2.y
// https://stackoverflow.com/a/46443628/9126211
private fun performPinch(
uiController: UiController,
startPoint1: PointF,
startPoint2: PointF,
endPoint1: PointF,
endPoint2: PointF,
duration: Long
) {
val eventMinInterval: Long = 10
val startTime = SystemClock.uptimeMillis()
var eventTime = startTime
var event: MotionEvent
var eventX1: Float = startPoint1.x
var eventY1: Float = startPoint1.y
var eventX2: Float = startPoint2.x
var eventY2: Float = startPoint2.y
// Specify the property for the two touch points
val properties = arrayOfNulls<MotionEvent.PointerProperties>(2)
val pp1 = MotionEvent.PointerProperties()
pp1.id = 0
pp1.toolType = MotionEvent.TOOL_TYPE_FINGER
val pp2 = MotionEvent.PointerProperties()
pp2.id = 1
pp2.toolType = MotionEvent.TOOL_TYPE_FINGER
// Specify the property for the two touch points
val properties = arrayOfNulls<MotionEvent.PointerProperties>(2)
val pp1 = MotionEvent.PointerProperties()
pp1.id = 0
pp1.toolType = MotionEvent.TOOL_TYPE_FINGER
val pp2 = MotionEvent.PointerProperties()
pp2.id = 1
pp2.toolType = MotionEvent.TOOL_TYPE_FINGER
properties[0] = pp1
properties[1] = pp2
properties[0] = pp1
properties[1] = pp2
// Specify the coordinations of the two touch points
// NOTE: you MUST set the pressure and size value, or it doesn't work
val pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(2)
val pc1 = MotionEvent.PointerCoords()
pc1.x = eventX1
pc1.y = eventY1
pc1.pressure = 1f
pc1.size = 1f
val pc2 = MotionEvent.PointerCoords()
pc2.x = eventX2
pc2.y = eventY2
pc2.pressure = 1f
pc2.size = 1f
pointerCoords[0] = pc1
pointerCoords[1] = pc2
// Specify the coordinations of the two touch points
// NOTE: you MUST set the pressure and size value, or it doesn't work
val pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(2)
val pc1 = MotionEvent.PointerCoords()
pc1.x = eventX1
pc1.y = eventY1
pc1.pressure = 1f
pc1.size = 1f
val pc2 = MotionEvent.PointerCoords()
pc2.x = eventX2
pc2.y = eventY2
pc2.pressure = 1f
pc2.size = 1f
pointerCoords[0] = pc1
pointerCoords[1] = pc2
/*
* Events sequence of zoom gesture:
@@ -162,118 +162,119 @@ object GesturesUiTestUtils {
* 6. Send ACTION_UP of one end point
*/
try {
// Step 1
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_DOWN, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
try {
// Step 1
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_DOWN, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 2
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_POINTER_DOWN + (pp2.id shl MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2,
properties, pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 2
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_POINTER_DOWN + (pp2.id shl MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2,
properties, pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 3, 4
val moveEventNumber = duration / eventMinInterval
// Step 3, 4
val moveEventNumber = duration / eventMinInterval
val stepX1: Float
val stepY1: Float
val stepX2: Float
val stepY2: Float
val stepX1: Float
val stepY1: Float
val stepX2: Float
val stepY2: Float
stepX1 = (endPoint1.x - startPoint1.x) / moveEventNumber
stepY1 = (endPoint1.y - startPoint1.y) / moveEventNumber
stepX2 = (endPoint2.x - startPoint2.x) / moveEventNumber
stepY2 = (endPoint2.y - startPoint2.y) / moveEventNumber
stepX1 = (endPoint1.x - startPoint1.x) / moveEventNumber
stepY1 = (endPoint1.y - startPoint1.y) / moveEventNumber
stepX2 = (endPoint2.x - startPoint2.x) / moveEventNumber
stepY2 = (endPoint2.y - startPoint2.y) / moveEventNumber
for (i in 0 until moveEventNumber) {
// Update the move events
eventTime += eventMinInterval
eventX1 += stepX1
eventY1 += stepY1
eventX2 += stepX2
eventY2 += stepY2
for (i in 0 until moveEventNumber) {
// Update the move events
eventTime += eventMinInterval
eventX1 += stepX1
eventY1 += stepY1
eventX2 += stepX2
eventY2 += stepY2
pc1.x = eventX1
pc1.y = eventY1
pc2.x = eventX2
pc2.y = eventY2
pointerCoords[0] = pc1
pointerCoords[1] = pc2
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_MOVE, 2, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
}
// Step 5
pc1.x = endPoint1.x
pc1.y = endPoint1.y
pc2.x = endPoint2.x
pc2.y = endPoint2.y
pointerCoords[0] = pc1
pointerCoords[1] = pc2
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_POINTER_UP + (pp2.id shl MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 6
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_UP, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
} catch (ex: InjectEventSecurityException) {
throw RuntimeException("Could not perform pinch", ex)
}
}
private fun performQuickScale(
uiController: UiController,
startPoint: PointF,
endPoint: PointF,
withVelocity: Boolean,
duration: Long,
interrupt: Boolean
) {
val eventMinInterval: Long = 10
val tapDownMinInterval: Long = 40 // ViewConfiguration#DOUBLE_TAP_MIN_TIME = 40
val startTime = SystemClock.uptimeMillis()
var eventTime = startTime
var event: MotionEvent
var eventX1: Float = startPoint.x
var eventY1: Float = startPoint.y
var properties = arrayOfNulls<MotionEvent.PointerProperties>(1)
val pp1 = MotionEvent.PointerProperties()
pp1.id = 0
pp1.toolType = MotionEvent.TOOL_TYPE_FINGER
properties[0] = pp1
var pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(1)
val pc1 = MotionEvent.PointerCoords()
pc1.x = eventX1
pc1.y = eventY1
pc2.x = eventX2
pc2.y = eventY2
pc1.pressure = 1f
pc1.size = 1f
pointerCoords[0] = pc1
pointerCoords[1] = pc2
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_MOVE, 2, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
}
// Step 5
pc1.x = endPoint1.x
pc1.y = endPoint1.y
pc2.x = endPoint2.x
pc2.y = endPoint2.y
pointerCoords[0] = pc1
pointerCoords[1] = pc2
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_POINTER_UP + (pp2.id shl MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 6
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_UP, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
} catch (ex: InjectEventSecurityException) {
throw RuntimeException("Could not perform pinch", ex)
}
}
private fun performQuickScale(
uiController: UiController,
startPoint: PointF,
endPoint: PointF,
withVelocity: Boolean,
duration: Long,
interrupt: Boolean
) {
val eventMinInterval: Long = 10
val tapDownMinInterval: Long = 40 // ViewConfiguration#DOUBLE_TAP_MIN_TIME = 40
val startTime = SystemClock.uptimeMillis()
var eventTime = startTime
var event: MotionEvent
var eventX1: Float = startPoint.x
var eventY1: Float = startPoint.y
var properties = arrayOfNulls<MotionEvent.PointerProperties>(1)
val pp1 = MotionEvent.PointerProperties()
pp1.id = 0
pp1.toolType = MotionEvent.TOOL_TYPE_FINGER
properties[0] = pp1
var pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(1)
val pc1 = MotionEvent.PointerCoords()
pc1.x = eventX1
pc1.y = eventY1
pc1.pressure = 1f
pc1.size = 1f
pointerCoords[0] = pc1
/*
* Events sequence of quick scale gesture:
@@ -284,145 +285,145 @@ object GesturesUiTestUtils {
* 4. Send ACTION_MOVE with updated middle points (x,y), until reach the end points
* 5. Send ACTION_UP of one end point
*/
try {
// Step 1
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_DOWN, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
try {
// Step 1
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_DOWN, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 2
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_UP, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 2
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_UP, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 3
eventTime += tapDownMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_DOWN, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 3
eventTime += tapDownMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_DOWN, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 4
val moveEventNumber = duration / eventMinInterval
// Step 4
val moveEventNumber = duration / eventMinInterval
val stepX1: Float
val stepY1: Float
val stepX1: Float
val stepY1: Float
stepX1 = (endPoint.x - startPoint.x) / moveEventNumber
stepY1 = (endPoint.y - startPoint.y) / moveEventNumber
stepX1 = (endPoint.x - startPoint.x) / moveEventNumber
stepY1 = (endPoint.y - startPoint.y) / moveEventNumber
var interrupted = false
var interrupted = false
for (i in 0 until moveEventNumber) {
// Update the move events
eventTime += eventMinInterval
eventX1 += stepX1
eventY1 += stepY1
for (i in 0 until moveEventNumber) {
// Update the move events
eventTime += eventMinInterval
eventX1 += stepX1
eventY1 += stepY1
pc1.x = eventX1
pc1.y = eventY1
pointerCoords[0] = pc1
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_MOVE, if (interrupted) 2 else 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
if (interrupt && i == moveEventNumber / 2) {
// Specify the property for the two touch points
properties = arrayOfNulls<MotionEvent.PointerProperties>(2)
val pp2 = MotionEvent.PointerProperties()
pp2.id = 1
pp2.toolType = MotionEvent.TOOL_TYPE_FINGER
properties[0] = pp1
properties[1] = pp2
// Specify the coordinations of the two touch points
// NOTE: you MUST set the pressure and size value, or it doesn't work
pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(2)
val pc2 = MotionEvent.PointerCoords()
pc2.x = startPoint.x
pc2.y = startPoint.y
pc2.pressure = 1f
pc2.size = 1f
pointerCoords[0] = pc1
pointerCoords[1] = pc2
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_POINTER_DOWN + (pp2.id shl MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2,
properties, pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
interrupted = true
}
}
if (!withVelocity) {
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_MOVE, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
}
// Step 5
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_UP, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
} catch (ex: InjectEventSecurityException) {
throw RuntimeException("Could not perform quick scale", ex)
}
}
private fun performMove(
uiController: UiController,
startPoint: PointF,
endPoint: PointF,
withVelocity: Boolean,
duration: Long
) {
val eventMinInterval: Long = 10
val startTime = SystemClock.uptimeMillis()
var eventTime = startTime
var event: MotionEvent
var eventX1: Float = startPoint.x
var eventY1: Float = startPoint.y
val properties = arrayOfNulls<MotionEvent.PointerProperties>(1)
val pp1 = MotionEvent.PointerProperties()
pp1.id = 0
pp1.toolType = MotionEvent.TOOL_TYPE_FINGER
properties[0] = pp1
val pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(1)
val pc1 = MotionEvent.PointerCoords()
pc1.x = eventX1
pc1.y = eventY1
pc1.pressure = 1f
pc1.size = 1f
pointerCoords[0] = pc1
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_MOVE, if (interrupted) 2 else 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
if (interrupt && i == moveEventNumber / 2) {
// Specify the property for the two touch points
properties = arrayOfNulls<MotionEvent.PointerProperties>(2)
val pp2 = MotionEvent.PointerProperties()
pp2.id = 1
pp2.toolType = MotionEvent.TOOL_TYPE_FINGER
properties[0] = pp1
properties[1] = pp2
// Specify the coordinations of the two touch points
// NOTE: you MUST set the pressure and size value, or it doesn't work
pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(2)
val pc2 = MotionEvent.PointerCoords()
pc2.x = startPoint.x
pc2.y = startPoint.y
pc2.pressure = 1f
pc2.size = 1f
pointerCoords[0] = pc1
pointerCoords[1] = pc2
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_POINTER_DOWN + (pp2.id shl MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2,
properties, pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
interrupted = true
}
}
if (!withVelocity) {
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_MOVE, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
}
// Step 5
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_UP, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
} catch (ex: InjectEventSecurityException) {
throw RuntimeException("Could not perform quick scale", ex)
}
}
private fun performMove(
uiController: UiController,
startPoint: PointF,
endPoint: PointF,
withVelocity: Boolean,
duration: Long
) {
val eventMinInterval: Long = 10
val startTime = SystemClock.uptimeMillis()
var eventTime = startTime
var event: MotionEvent
var eventX1: Float = startPoint.x
var eventY1: Float = startPoint.y
val properties = arrayOfNulls<MotionEvent.PointerProperties>(1)
val pp1 = MotionEvent.PointerProperties()
pp1.id = 0
pp1.toolType = MotionEvent.TOOL_TYPE_FINGER
properties[0] = pp1
val pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(1)
val pc1 = MotionEvent.PointerCoords()
pc1.x = eventX1
pc1.y = eventY1
pc1.pressure = 1f
pc1.size = 1f
pointerCoords[0] = pc1
/*
* Events sequence of move gesture:
*
@@ -430,87 +431,87 @@ object GesturesUiTestUtils {
* 2. Send ACTION_MOVE with updated middle points (x,y), until reach the end points
* 3. Send ACTION_UP
*/
try {
// Step 1
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_DOWN, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
try {
// Step 1
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_DOWN, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
// Step 2
val moveEventNumber = duration / eventMinInterval
// Step 2
val moveEventNumber = duration / eventMinInterval
val stepX1: Float
val stepY1: Float
val stepX1: Float
val stepY1: Float
stepX1 = (endPoint.x - startPoint.x) / moveEventNumber
stepY1 = (endPoint.y - startPoint.y) / moveEventNumber
stepX1 = (endPoint.x - startPoint.x) / moveEventNumber
stepY1 = (endPoint.y - startPoint.y) / moveEventNumber
for (i in 0 until moveEventNumber) {
// Update the move events
eventTime += eventMinInterval
eventX1 += stepX1
eventY1 += stepY1
for (i in 0 until moveEventNumber) {
// Update the move events
eventTime += eventMinInterval
eventX1 += stepX1
eventY1 += stepY1
pc1.x = eventX1
pc1.y = eventY1
pc1.x = eventX1
pc1.y = eventY1
pointerCoords[0] = pc1
pointerCoords[0] = pc1
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_MOVE, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
}
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_MOVE, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
}
if (!withVelocity) {
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_MOVE, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
}
if (!withVelocity) {
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_MOVE, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
}
// Step 3
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_UP, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
} catch (ex: InjectEventSecurityException) {
throw RuntimeException("Could not perform quick scale", ex)
// Step 3
eventTime += eventMinInterval
event = MotionEvent.obtain(
startTime, eventTime,
MotionEvent.ACTION_UP, 1, properties,
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
)
injectMotionEventToUiController(uiController, event)
} catch (ex: InjectEventSecurityException) {
throw RuntimeException("Could not perform quick scale", ex)
}
}
}
/**
* Safely call uiController.injectMotionEvent(event): Detect any error and "convert" it to an
* IllegalStateException
*/
@Throws(InjectEventSecurityException::class)
private fun injectMotionEventToUiController(uiController: UiController, event: MotionEvent) {
val injectEventSucceeded = uiController.injectMotionEvent(event)
if (!injectEventSucceeded) {
throw IllegalStateException("Error performing event $event")
/**
* Safely call uiController.injectMotionEvent(event): Detect any error and "convert" it to an
* IllegalStateException
*/
@Throws(InjectEventSecurityException::class)
private fun injectMotionEventToUiController(uiController: UiController, event: MotionEvent) {
val injectEventSucceeded = uiController.injectMotionEvent(event)
if (!injectEventSucceeded) {
throw IllegalStateException("Error performing event $event")
}
}
}
}
fun Int.loopFor(millis: Long) {
Espresso.onView(ViewMatchers.withId(this)).perform(object : ViewAction {
override fun getDescription(): String = "waiting for $millis"
Espresso.onView(ViewMatchers.withId(this)).perform(object : ViewAction {
override fun getDescription(): String = "waiting for $millis"
override fun getConstraints(): Matcher<View> = ViewMatchers.isEnabled()
override fun getConstraints(): Matcher<View> = ViewMatchers.isEnabled()
override fun perform(uiController: UiController?, view: View?) {
uiController?.loopMainThreadForAtLeast(millis)
}
})
}
override fun perform(uiController: UiController?, view: View?) {
uiController?.loopMainThreadForAtLeast(millis)
}
})
}

View File

@@ -16,178 +16,178 @@ import org.junit.Before
import org.junit.Test
class MapGestureDetectorTest : BaseTest() {
override fun getActivityClass() = SimpleMapActivity::class.java
override fun getActivityClass() = SimpleMapActivity::class.java
private var maxWidth: Int = 0
private var maxHeight: Int = 0
private var maxWidth: Int = 0
private var maxHeight: Int = 0
@Before
fun setup() {
maxWidth = mapView.width
maxHeight = mapView.height
}
@Test
fun sanity_quickZoom() {
validateTestSetup()
var initialZoom: Double? = null
rule.runOnUiThread {
initialZoom = mapboxMap.cameraPosition.zoom
}
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f, withVelocity = false))
rule.runOnUiThread {
Assert.assertTrue(mapboxMap.cameraPosition.zoom > initialZoom!!)
}
}
@Test
fun quickZoomDisabled_phantomQuickZoom_moveStillEnabled_15091() {
// regression test for https://github.com/mapbox/mapbox-gl-native/issues/15091
validateTestSetup()
var initialCameraPosition: CameraPosition? = null
rule.runOnUiThread {
// zoom in so we can move vertically
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
initialCameraPosition = mapboxMap.cameraPosition
mapboxMap.uiSettings.isQuickZoomGesturesEnabled = false
@Before
fun setup() {
maxWidth = mapView.width
maxHeight = mapView.height
}
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f))
rule.runOnUiThread {
// camera did not move
Assert.assertEquals(initialCameraPosition!!, mapboxMap.cameraPosition)
@Test
fun sanity_quickZoom() {
validateTestSetup()
var initialZoom: Double? = null
rule.runOnUiThread {
initialZoom = mapboxMap.cameraPosition.zoom
}
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f, withVelocity = false))
rule.runOnUiThread {
Assert.assertTrue(mapboxMap.cameraPosition.zoom > initialZoom!!)
}
}
// move to expected target
onView(withId(R.id.mapView)).perform(move(-maxWidth / 2f, -maxHeight / 2f, withVelocity = false))
rule.runOnUiThread {
Assert.assertNotEquals(initialCameraPosition!!.target.latitude, mapboxMap.cameraPosition.target.latitude, 1.0)
Assert.assertNotEquals(initialCameraPosition!!.target.longitude, mapboxMap.cameraPosition.target.longitude, 1.0)
}
}
@Test
fun quickZoomDisabled_phantomQuickZoom_moveStillEnabled_15091() {
// regression test for https://github.com/mapbox/mapbox-gl-native/issues/15091
validateTestSetup()
var initialCameraPosition: CameraPosition? = null
rule.runOnUiThread {
// zoom in so we can move vertically
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
initialCameraPosition = mapboxMap.cameraPosition
mapboxMap.uiSettings.isQuickZoomGesturesEnabled = false
}
@Test
fun quickZoom_doNotMove_14227() {
// test for https://github.com/mapbox/mapbox-gl-native/issues/14227
validateTestSetup()
var initialTarget: LatLng? = null
rule.runOnUiThread {
initialTarget = mapboxMap.cameraPosition.target
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f))
rule.runOnUiThread {
// camera did not move
Assert.assertEquals(initialCameraPosition!!, mapboxMap.cameraPosition)
}
// move to expected target
onView(withId(R.id.mapView)).perform(move(-maxWidth / 2f, -maxHeight / 2f, withVelocity = false))
rule.runOnUiThread {
Assert.assertNotEquals(initialCameraPosition!!.target.latitude, mapboxMap.cameraPosition.target.latitude, 1.0)
Assert.assertNotEquals(initialCameraPosition!!.target.longitude, mapboxMap.cameraPosition.target.longitude, 1.0)
}
}
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f))
rule.runOnUiThread {
// camera did not move
Assert.assertEquals(initialTarget!!.latitude, mapboxMap.cameraPosition.target.latitude, 1.0)
Assert.assertEquals(initialTarget!!.longitude, mapboxMap.cameraPosition.target.longitude, 1.0)
}
}
@Test
fun quickZoom_doNotMove_14227() {
// test for https://github.com/mapbox/mapbox-gl-native/issues/14227
validateTestSetup()
var initialTarget: LatLng? = null
rule.runOnUiThread {
initialTarget = mapboxMap.cameraPosition.target
}
@Test
fun quickZoom_interrupted_moveStillEnabled_14598() {
// test for https://github.com/mapbox/mapbox-gl-native/issues/14598
validateTestSetup()
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f, interrupt = true))
var initialCameraPosition: CameraPosition? = null
rule.runOnUiThread {
// zoom in so we can move vertically
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
initialCameraPosition = mapboxMap.cameraPosition
mapboxMap.uiSettings.isQuickZoomGesturesEnabled = false
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f))
rule.runOnUiThread {
// camera did not move
Assert.assertEquals(initialTarget!!.latitude, mapboxMap.cameraPosition.target.latitude, 1.0)
Assert.assertEquals(initialTarget!!.longitude, mapboxMap.cameraPosition.target.longitude, 1.0)
}
}
// move to expected target
onView(withId(R.id.mapView)).perform(move(-maxWidth / 2f, -maxHeight / 2f, withVelocity = false))
rule.runOnUiThread {
Assert.assertNotEquals(initialCameraPosition!!.target.latitude, mapboxMap.cameraPosition.target.latitude, 1.0)
Assert.assertNotEquals(initialCameraPosition!!.target.longitude, mapboxMap.cameraPosition.target.longitude, 1.0)
}
}
@Test
fun quickZoom_interrupted_moveStillEnabled_14598() {
// test for https://github.com/mapbox/mapbox-gl-native/issues/14598
validateTestSetup()
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f, interrupt = true))
@Test
fun quickZoom_ignoreDoubleTap() {
// test for https://github.com/mapbox/mapbox-gl-native/issues/14013
validateTestSetup()
var initialZoom: Double? = null
rule.runOnUiThread {
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(2.0))
initialZoom = mapboxMap.cameraPosition.zoom
}
onView(withId(R.id.mapView)).perform(quickScale(-(mapboxMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold * 2), withVelocity = false, duration = 1000L))
R.id.mapView.loopFor(MapboxConstants.ANIMATION_DURATION.toLong())
rule.runOnUiThread {
Assert.assertTrue(mapboxMap.cameraPosition.zoom < initialZoom!!)
}
}
var initialCameraPosition: CameraPosition? = null
rule.runOnUiThread {
// zoom in so we can move vertically
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
initialCameraPosition = mapboxMap.cameraPosition
mapboxMap.uiSettings.isQuickZoomGesturesEnabled = false
}
@Test
fun doubleTap_minimalMovement() {
validateTestSetup()
var initialZoom: Double? = null
rule.runOnUiThread {
initialZoom = mapboxMap.cameraPosition.zoom
}
onView(withId(R.id.mapView)).perform(quickScale(mapboxMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold / 2, withVelocity = false, duration = 50L))
R.id.mapView.loopFor(MapboxConstants.ANIMATION_DURATION.toLong())
rule.runOnUiThread {
Assert.assertEquals(initialZoom!! + 1, mapboxMap.cameraPosition.zoom, 0.1)
}
}
@Test
fun doubleTap_overMaxThreshold_ignore_14013() {
// test for https://github.com/mapbox/mapbox-gl-native/issues/14013
validateTestSetup()
var initialZoom: Double? = null
rule.runOnUiThread {
initialZoom = mapboxMap.cameraPosition.zoom
mapboxMap.uiSettings.isQuickZoomGesturesEnabled = false
}
onView(withId(R.id.mapView)).perform(quickScale(mapboxMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold * 2, withVelocity = false, duration = 50L))
R.id.mapView.loopFor(MapboxConstants.ANIMATION_DURATION.toLong())
rule.runOnUiThread {
Assert.assertEquals(initialZoom!!, mapboxMap.cameraPosition.zoom, 0.01)
}
}
@Test
fun doubleTap_interrupted_moveStillEnabled() {
validateTestSetup()
rule.runOnUiThread {
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
// move to expected target
onView(withId(R.id.mapView)).perform(move(-maxWidth / 2f, -maxHeight / 2f, withVelocity = false))
rule.runOnUiThread {
Assert.assertNotEquals(initialCameraPosition!!.target.latitude, mapboxMap.cameraPosition.target.latitude, 1.0)
Assert.assertNotEquals(initialCameraPosition!!.target.longitude, mapboxMap.cameraPosition.target.longitude, 1.0)
}
}
onView(withId(R.id.mapView)).perform(quickScale(mapboxMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold / 2, withVelocity = false, duration = 50L, interrupt = true))
var initialCameraPosition: CameraPosition? = null
rule.runOnUiThread {
// zoom in so we can move vertically
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
initialCameraPosition = mapboxMap.cameraPosition
mapboxMap.uiSettings.isQuickZoomGesturesEnabled = false
@Test
fun quickZoom_ignoreDoubleTap() {
// test for https://github.com/mapbox/mapbox-gl-native/issues/14013
validateTestSetup()
var initialZoom: Double? = null
rule.runOnUiThread {
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(2.0))
initialZoom = mapboxMap.cameraPosition.zoom
}
onView(withId(R.id.mapView)).perform(quickScale(-(mapboxMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold * 2), withVelocity = false, duration = 1000L))
R.id.mapView.loopFor(MapboxConstants.ANIMATION_DURATION.toLong())
rule.runOnUiThread {
Assert.assertTrue(mapboxMap.cameraPosition.zoom < initialZoom!!)
}
}
// move to expected target
onView(withId(R.id.mapView)).perform(move(-maxWidth / 2f, -maxHeight / 2f, withVelocity = false))
rule.runOnUiThread {
Assert.assertNotEquals(initialCameraPosition!!.target.latitude, mapboxMap.cameraPosition.target.latitude, 1.0)
Assert.assertNotEquals(initialCameraPosition!!.target.longitude, mapboxMap.cameraPosition.target.longitude, 1.0)
@Test
fun doubleTap_minimalMovement() {
validateTestSetup()
var initialZoom: Double? = null
rule.runOnUiThread {
initialZoom = mapboxMap.cameraPosition.zoom
}
onView(withId(R.id.mapView)).perform(quickScale(mapboxMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold / 2, withVelocity = false, duration = 50L))
R.id.mapView.loopFor(MapboxConstants.ANIMATION_DURATION.toLong())
rule.runOnUiThread {
Assert.assertEquals(initialZoom!! + 1, mapboxMap.cameraPosition.zoom, 0.1)
}
}
}
@Test
fun quickZoom_roundTripping() {
validateTestSetup()
rule.runOnUiThread {
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(51.0, 16.0), 3.0))
@Test
fun doubleTap_overMaxThreshold_ignore_14013() {
// test for https://github.com/mapbox/mapbox-gl-native/issues/14013
validateTestSetup()
var initialZoom: Double? = null
rule.runOnUiThread {
initialZoom = mapboxMap.cameraPosition.zoom
mapboxMap.uiSettings.isQuickZoomGesturesEnabled = false
}
onView(withId(R.id.mapView)).perform(quickScale(mapboxMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold * 2, withVelocity = false, duration = 50L))
R.id.mapView.loopFor(MapboxConstants.ANIMATION_DURATION.toLong())
rule.runOnUiThread {
Assert.assertEquals(initialZoom!!, mapboxMap.cameraPosition.zoom, 0.01)
}
}
onView(withId(R.id.mapView)).perform(quickScale(300f, withVelocity = false, duration = 750L))
onView(withId(R.id.mapView)).perform(quickScale(-300f, withVelocity = false, duration = 750L))
rule.runOnUiThread {
Assert.assertEquals(3.0, mapboxMap.cameraPosition.zoom, 0.0001)
@Test
fun doubleTap_interrupted_moveStillEnabled() {
validateTestSetup()
rule.runOnUiThread {
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
}
onView(withId(R.id.mapView)).perform(quickScale(mapboxMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold / 2, withVelocity = false, duration = 50L, interrupt = true))
var initialCameraPosition: CameraPosition? = null
rule.runOnUiThread {
// zoom in so we can move vertically
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
initialCameraPosition = mapboxMap.cameraPosition
mapboxMap.uiSettings.isQuickZoomGesturesEnabled = false
}
// move to expected target
onView(withId(R.id.mapView)).perform(move(-maxWidth / 2f, -maxHeight / 2f, withVelocity = false))
rule.runOnUiThread {
Assert.assertNotEquals(initialCameraPosition!!.target.latitude, mapboxMap.cameraPosition.target.latitude, 1.0)
Assert.assertNotEquals(initialCameraPosition!!.target.longitude, mapboxMap.cameraPosition.target.longitude, 1.0)
}
}
}
}
@Test
fun quickZoom_roundTripping() {
validateTestSetup()
rule.runOnUiThread {
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(51.0, 16.0), 3.0))
}
onView(withId(R.id.mapView)).perform(quickScale(300f, withVelocity = false, duration = 750L))
onView(withId(R.id.mapView)).perform(quickScale(-300f, withVelocity = false, duration = 750L))
rule.runOnUiThread {
Assert.assertEquals(3.0, mapboxMap.cameraPosition.zoom, 0.0001)
}
}
}

View File

@@ -155,12 +155,12 @@ class NativeMapViewTest : AppCenter() {
@UiThreadTest
fun testJumpTo() {
val expected = CameraPosition.Builder()
.bearing(BEARING_TEST)
.target(LATLNG_TEST)
.tilt(PITCH_TEST)
.zoom(ZOOM_TEST)
.padding(PADDING_TEST)
.build()
.bearing(BEARING_TEST)
.target(LATLNG_TEST)
.tilt(PITCH_TEST)
.zoom(ZOOM_TEST)
.padding(PADDING_TEST)
.build()
// verify that the lazily set padding is ignored when a value is provided with the camera
nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
nativeMapView.jumpTo(LATLNG_TEST, ZOOM_TEST, PITCH_TEST, BEARING_TEST, PADDING_TEST)
@@ -179,7 +179,7 @@ class NativeMapViewTest : AppCenter() {
val expected = LATLNG_TEST
nativeMapView.setLatLng(LATLNG_TEST, 0)
val actual = nativeMapView.latLngForPixel(
PointF((WIDTH / 2).toFloat(), (HEIGHT / 2).toFloat())
PointF((WIDTH / 2).toFloat(), (HEIGHT / 2).toFloat())
)
assertEquals("Latitude should match", expected.latitude, actual.latitude, DELTA_BIG)
assertEquals("Longitude should match", expected.longitude, actual.longitude, DELTA_BIG)
@@ -224,18 +224,18 @@ class NativeMapViewTest : AppCenter() {
@Test
@UiThreadTest
fun testPrefetchZoomDelta() {
val expected = 2
nativeMapView.prefetchZoomDelta = 2
val actual = nativeMapView.prefetchZoomDelta
assertEquals("Prefetch zoom delta should match", expected, actual)
val expected = 2
nativeMapView.prefetchZoomDelta = 2
val actual = nativeMapView.prefetchZoomDelta
assertEquals("Prefetch zoom delta should match", expected, actual)
}
@Test
@UiThreadTest
fun testPrefetchZoomDeltaDefault() {
val expected = 4
val actual = nativeMapView.prefetchZoomDelta
assertEquals("Prefetch zoom delta should match", expected, actual)
val expected = 4
val actual = nativeMapView.prefetchZoomDelta
assertEquals("Prefetch zoom delta should match", expected, actual)
}
@Test
@@ -268,23 +268,23 @@ class NativeMapViewTest : AppCenter() {
assertEquals("Max zoom should match", expected, actual)
}
@Test
@UiThreadTest
fun testSetMinPitch() {
val expected = 60.0
nativeMapView.minPitch = expected
val actual = nativeMapView.minPitch
assertEquals("Min Pitch should match", expected, actual, 0.01)
}
@Test
@UiThreadTest
fun testSetMinPitch() {
val expected = 60.0
nativeMapView.minPitch = expected
val actual = nativeMapView.minPitch
assertEquals("Min Pitch should match", expected, actual, 0.01)
}
@Test
@UiThreadTest
fun testSetMaxPitch() {
val expected = 60.0
nativeMapView.maxPitch = expected
val actual = nativeMapView.maxPitch
assertEquals("Max Pitch should match", expected, actual, 0.01)
}
@Test
@UiThreadTest
fun testSetMaxPitch() {
val expected = 60.0
nativeMapView.maxPitch = expected
val actual = nativeMapView.maxPitch
assertEquals("Max Pitch should match", expected, actual, 0.01)
}
@Test
@UiThreadTest
@@ -307,12 +307,12 @@ class NativeMapViewTest : AppCenter() {
@UiThreadTest
fun testFlyTo() {
val expected = CameraPosition.Builder()
.zoom(12.0)
.tilt(30.0)
.target(LatLng(12.0, 14.0))
.bearing(20.0)
.padding(PADDING_TEST)
.build()
.zoom(12.0)
.tilt(30.0)
.target(LatLng(12.0, 14.0))
.bearing(20.0)
.padding(PADDING_TEST)
.build()
// verify that the lazily set padding is ignored when a value is provided with the camera
nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
nativeMapView.flyTo(expected.target, expected.zoom, expected.bearing, expected.tilt, PADDING_TEST, 0)
@@ -329,12 +329,12 @@ class NativeMapViewTest : AppCenter() {
@UiThreadTest
fun testEaseTo() {
val expected = CameraPosition.Builder()
.zoom(12.0)
.tilt(30.0)
.target(LatLng(12.0, 14.0))
.bearing(20.0)
.padding(PADDING_TEST)
.build()
.zoom(12.0)
.tilt(30.0)
.target(LatLng(12.0, 14.0))
.bearing(20.0)
.padding(PADDING_TEST)
.build()
// verify that the lazily set padding is ignored when a value is provided with the camera
nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
nativeMapView.easeTo(expected.target, expected.zoom, expected.bearing, expected.tilt, PADDING_TEST, 0, false)
@@ -351,12 +351,12 @@ class NativeMapViewTest : AppCenter() {
@UiThreadTest
fun testResetPosition() {
val expected = CameraPosition.Builder()
.zoom(0.0)
.tilt(0.0)
.target(LatLng(0.0, 0.0))
.bearing(0.0)
.padding(PADDING_TEST)
.build()
.zoom(0.0)
.tilt(0.0)
.target(LatLng(0.0, 0.0))
.bearing(0.0)
.padding(PADDING_TEST)
.build()
nativeMapView.jumpTo(LatLng(1.0, 2.0), 12.0, 23.0, 1.0, PADDING_TEST)
nativeMapView.resetPosition()
val actual = nativeMapView.cameraPosition
@@ -372,16 +372,16 @@ class NativeMapViewTest : AppCenter() {
@UiThreadTest
fun testGetCameraForLatLngBounds() {
val expected = CameraPosition.Builder()
.zoom(3.5258764777024005)
.tilt(0.0)
.target(LatLng(23.182767623652808, 13.999999999994088))
.bearing(0.0)
.build()
.zoom(3.5258764777024005)
.tilt(0.0)
.target(LatLng(23.182767623652808, 13.999999999994088))
.bearing(0.0)
.build()
val actual = nativeMapView.getCameraForLatLngBounds(
LatLngBounds.from(30.0, 16.0, 16.0, 12.0),
intArrayOf(0, 0, 0, 0),
0.0,
0.0
LatLngBounds.from(30.0, 16.0, 16.0, 12.0),
intArrayOf(0, 0, 0, 0),
0.0,
0.0
)
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
assertEquals("Latitude should match", expected.target.latitude, actual.target.latitude, TestConstants.LAT_LNG_DELTA)
@@ -394,11 +394,11 @@ class NativeMapViewTest : AppCenter() {
@UiThreadTest
fun testMoveBy() {
val expected = CameraPosition.Builder()
.zoom(0.0)
.tilt(0.0)
.target(LatLng(4.21494310024160, -4.218749958739409))
.bearing(0.0)
.build()
.zoom(0.0)
.tilt(0.0)
.target(LatLng(4.21494310024160, -4.218749958739409))
.bearing(0.0)
.build()
nativeMapView.moveBy(12.0, 12.0, 0)
val actual = nativeMapView.cameraPosition
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
@@ -436,4 +436,4 @@ class NativeMapViewTest : AppCenter() {
// no-op
}
}
}
}

View File

@@ -30,4 +30,4 @@ class TransformTest : EspressoTest() {
assertEquals("Camera position should match", expectedCameraPosition, actualCameraPosition)
}
}
}
}

View File

@@ -14,505 +14,507 @@ import org.junit.Test
class VisibleRegionTest : BaseTest() {
override fun getActivityClass(): Class<*> {
return PixelTestActivity::class.java
}
override
fun beforeTest() {
super.beforeTest()
mapView = (rule.activity as PixelTestActivity).mapView
}
@Test
fun visibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
override fun getActivityClass(): Class<*> {
return PixelTestActivity::class.java
}
}
@Test
fun paddedVisibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(
mapView.width / 4,
mapView.height / 4,
mapView.width / 4,
mapView.height / 4)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 1)
assertTrue(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)))
override
fun beforeTest() {
super.beforeTest()
mapView = (rule.activity as PixelTestActivity).mapView
}
}
@Test
fun paddedLeftVisibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(mapView.width / 4, 0, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f)))
@Test
fun visibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
}
}
}
@Test
fun paddedTopVisibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
@Test
fun paddedVisibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, mapView.height / 4, 0, 0)
mapboxMap.setPadding(
mapView.width / 4,
mapView.height / 4,
mapView.width / 4,
mapView.height / 4
)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f)))
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 1)
assertTrue(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)))
}
}
}
@Test
fun paddedRightVisibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
@Test
fun paddedLeftVisibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, mapView.width / 4, 0)
mapboxMap.setPadding(mapView.width / 4, 0, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)))
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f)))
}
}
}
@Test
fun paddedBottomVisibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
@Test
fun paddedTopVisibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, 0, mapView.height / 4)
mapboxMap.setPadding(0, mapView.height / 4, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat())))
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f)))
}
}
}
@Test
fun visibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
@Test
fun paddedRightVisibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, mapView.width / 4, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)))
}
}
}
@Test
fun paddedVisibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
@Test
fun paddedBottomVisibleRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(
mapView.width / 4,
mapView.height / 4,
mapView.width / 4,
mapView.height / 4)
mapboxMap.setPadding(0, 0, 0, mapView.height / 4)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 1)
assertTrue(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)))
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat())))
}
}
}
@Test
fun paddedLeftVisibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(mapView.width / 4, 0, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f)))
@Test
fun visibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
}
}
}
@Test
fun paddedTopVisibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { ui: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
ui.loopMainThreadForAtLeast(5000)
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
@Test
fun paddedVisibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, mapView.height / 4, 0, 0)
mapboxMap.setPadding(
mapView.width / 4,
mapView.height / 4,
mapView.width / 4,
mapView.height / 4
)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f)))
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 1)
assertTrue(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)))
}
}
}
@Test
fun paddedRightVisibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
@Test
fun paddedLeftVisibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, mapView.width / 4, 0)
mapboxMap.setPadding(mapView.width / 4, 0, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)))
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f)))
}
}
}
@Test
fun paddedBottomVisibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
@Test
fun paddedTopVisibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { ui: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
ui.loopMainThreadForAtLeast(5000)
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, 0, mapView.height / 4)
mapboxMap.setPadding(0, mapView.height / 4, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat())))
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f)))
}
}
}
@Test
fun visibleRotatedRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val d = Math.min(mapboxMap.width, mapboxMap.height) / 4
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
)
@Test
fun paddedRightVisibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
for (bearing in 45 until 360 step 45) {
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
}
mapboxMap.setPadding(0, 0, mapView.width / 4, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)))
}
}
}
@Test
fun visibleRotatedRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val d = Math.min(mapboxMap.width, mapboxMap.height) / 4
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
)
@Test
fun paddedBottomVisibleRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
for (bearing in 45 until 360 step 45) {
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
}
mapboxMap.setPadding(0, 0, 0, mapView.height / 4)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat())))
}
}
}
@Test
fun visibleRegionWithBoundsEqualTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapboxMap.projection.getVisibleCoordinateBounds(bounds)
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngBounds == visibleRegion.latLngBounds)
assertTrue(latLngs.all { latLngBounds.contains(it) })
@Test
fun visibleRotatedRegionTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val d = Math.min(mapboxMap.width, mapboxMap.height) / 4
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
)
for (bearing in 45 until 360 step 45) {
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
}
}
}
}
@Test
fun visibleRegionBoundsOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapboxMap.projection.getVisibleCoordinateBounds(bounds)
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
assertTrue(latLngs.all { latLngBounds.contains(it) })
@Test
fun visibleRotatedRegionOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val d = Math.min(mapboxMap.width, mapboxMap.height) / 4
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
)
for (bearing in 45 until 360 step 45) {
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
}
}
}
}
@Test
fun visibleRegionBoundsOverDatelineLatitudeZeroTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val shift = mapboxMap.getLatLngFromScreenCoords(0f, 0f)
mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(0.0, 180.0 - shift.longitude)))
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapboxMap.projection.getVisibleCoordinateBounds(bounds)
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngBounds == visibleRegion.latLngBounds)
@Test
fun visibleRegionWithBoundsEqualTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapboxMap.projection.getVisibleCoordinateBounds(bounds)
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngBounds == visibleRegion.latLngBounds)
assertTrue(latLngs.all { latLngBounds.contains(it) })
}
}
}
@Test
fun visibleRotatedRegionBoundEqualTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val d = Math.min(mapboxMap.width, mapboxMap.height) / 4
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
)
for (bearing in 45 until 360 step 45) {
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapboxMap.projection.getVisibleCoordinateBounds(bounds)
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngBounds == visibleRegion.latLngBounds)
assertTrue(latLngs.all { latLngBounds.contains(it) })
}
@Test
fun visibleRegionBoundsOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapboxMap.projection.getVisibleCoordinateBounds(bounds)
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
assertTrue(latLngs.all { latLngBounds.contains(it) })
}
}
}
@Test
fun visibleRotatedRegionBoundsOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 179.0), 8.0))
val d = Math.min(mapboxMap.width, mapboxMap.height) / 4
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
)
@Test
fun visibleRegionBoundsOverDatelineLatitudeZeroTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
val shift = mapboxMap.getLatLngFromScreenCoords(0f, 0f)
mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(0.0, 180.0 - shift.longitude)))
for (bearing in 45 until 360 step 45) {
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapboxMap.projection.getVisibleCoordinateBounds(bounds)
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
assertTrue(latLngs.all { latLngBounds.contains(it) })
}
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapboxMap.projection.getVisibleCoordinateBounds(bounds)
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngBounds == visibleRegion.latLngBounds)
}
}
}
private fun MapboxMap.getLatLngFromScreenCoords(x: Float, y: Float): LatLng {
return this.projection.fromScreenLocation(PointF(x, y))
}
}
@Test
fun visibleRotatedRegionBoundEqualTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val d = Math.min(mapboxMap.width, mapboxMap.height) / 4
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
)
for (bearing in 45 until 360 step 45) {
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapboxMap.projection.getVisibleCoordinateBounds(bounds)
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
val visibleRegion = mapboxMap.projection.visibleRegion
assertTrue(latLngBounds == visibleRegion.latLngBounds)
assertTrue(latLngs.all { latLngBounds.contains(it) })
}
}
}
@Test
fun visibleRotatedRegionBoundsOverDatelineTest() {
validateTestSetup()
invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 179.0), 8.0))
val d = Math.min(mapboxMap.width, mapboxMap.height) / 4
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
)
for (bearing in 45 until 360 step 45) {
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapboxMap.projection.getVisibleCoordinateBounds(bounds)
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
assertTrue(latLngs.all { latLngBounds.contains(it) })
}
}
}
private fun MapboxMap.getLatLngFromScreenCoords(x: Float, y: Float): LatLng {
return this.projection.fromScreenLocation(PointF(x, y))
}
}

View File

@@ -6,12 +6,12 @@ import com.mapbox.geojson.Point
import com.mapbox.mapboxsdk.log.Logger
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
/**
* Integration test that validates downloading an offline region from a point geometry at zoomlevel 17
@@ -19,67 +19,68 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class OfflineDownloadTest : OfflineRegion.OfflineRegionObserver {
@Rule
@JvmField
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
@Rule
@JvmField
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
private val countDownLatch = CountDownLatch(1)
private lateinit var offlineRegion: OfflineRegion
private val countDownLatch = CountDownLatch(1)
private lateinit var offlineRegion: OfflineRegion
@Test(timeout = 60000)
fun offlineDownload() {
rule.runOnUiThreadActivity {
OfflineManager.getInstance(rule.activity).createOfflineRegion(
createTestRegionDefinition(),
ByteArray(0),
object : OfflineManager.CreateOfflineRegionCallback {
override fun onCreate(region: OfflineRegion) {
offlineRegion = region
offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE)
offlineRegion.setObserver(this@OfflineDownloadTest)
}
@Test(timeout = 60000)
fun offlineDownload() {
rule.runOnUiThreadActivity {
OfflineManager.getInstance(rule.activity).createOfflineRegion(
createTestRegionDefinition(),
ByteArray(0),
object : OfflineManager.CreateOfflineRegionCallback {
override fun onCreate(region: OfflineRegion) {
offlineRegion = region
offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE)
offlineRegion.setObserver(this@OfflineDownloadTest)
}
override fun onError(error: String) {
Logger.e(TAG, "Error while creating offline region: $error")
}
})
override fun onError(error: String) {
Logger.e(TAG, "Error while creating offline region: $error")
}
}
)
}
if (!countDownLatch.await(60, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
if (!countDownLatch.await(60, TimeUnit.SECONDS)) {
throw TimeoutException()
override fun onStatusChanged(status: OfflineRegionStatus) {
Logger.i(TAG, "Download percentage ${100.0 * status.completedResourceCount / status.requiredResourceCount}")
if (status.isComplete) {
offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE)
countDownLatch.countDown()
}
}
}
override fun onStatusChanged(status: OfflineRegionStatus) {
Logger.i(TAG, "Download percentage ${100.0 * status.completedResourceCount / status.requiredResourceCount}")
if (status.isComplete) {
offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE)
countDownLatch.countDown()
override fun onError(error: OfflineRegionError) {
Logger.e(TAG, "Error while downloading offline region: $error")
}
}
override fun onError(error: OfflineRegionError) {
Logger.e(TAG, "Error while downloading offline region: $error")
}
override fun mapboxTileCountLimitExceeded(limit: Long) {
Logger.e(TAG, "Tile count limited exceeded: $limit")
}
override fun mapboxTileCountLimitExceeded(limit: Long) {
Logger.e(TAG, "Tile count limited exceeded: $limit")
}
private fun createTestRegionDefinition(): OfflineRegionDefinition {
return OfflineGeometryRegionDefinition(
Style.MAPBOX_STREETS,
Point.fromLngLat(50.847857, 4.360137),
17.0,
17.0,
1.0f,
false
)
}
private fun createTestRegionDefinition(): OfflineRegionDefinition {
return OfflineGeometryRegionDefinition(
Style.MAPBOX_STREETS,
Point.fromLngLat(50.847857, 4.360137),
17.0,
17.0,
1.0f,
false
)
}
companion object {
const val TAG = "OfflineDownloadTest"
}
companion object {
const val TAG = "OfflineDownloadTest"
}
}
fun ActivityTestRule<*>.runOnUiThreadActivity(runnable: () -> Unit) = activity.runOnUiThread(runnable)
fun ActivityTestRule<*>.runOnUiThreadActivity(runnable: () -> Unit) = activity.runOnUiThread(runnable)

View File

@@ -8,14 +8,14 @@ import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.style.layers.BackgroundLayer
import com.mapbox.mapboxsdk.style.layers.PropertyFactory
import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import junit.framework.Assert.assertNotNull
import org.junit.Assert
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
/**
* Integration test that validates if a snapshotter creation
@@ -23,39 +23,44 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class MapSnapshotterTest {
@Rule
@JvmField
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
@Rule
@JvmField
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
private val countDownLatch = CountDownLatch(1)
private val countDownLatch = CountDownLatch(1)
@Test
fun mapSnapshotter() {
var mapSnapshotter: MapSnapshotter?
rule.activity.runOnUiThread {
val bg = BackgroundLayer("rand_tint")
bg.setProperties(PropertyFactory.backgroundColor("rgba(255,128,0,0.7)"))
val options = MapSnapshotter.Options(512, 512)
.withPixelRatio(1.0f)
.withStyleBuilder(Style.Builder().fromUri(Style.SATELLITE_STREETS)
.withLayerAbove(bg, "country-label"))
.withCameraPosition(
CameraPosition.Builder()
.zoom(12.0)
.target(LatLng(51.145495, 5.742234))
.build()
)
mapSnapshotter = MapSnapshotter(rule.activity, options)
mapSnapshotter!!.start({
assertNotNull(it)
assertNotNull(it.bitmap)
countDownLatch.countDown()
}, {
Assert.fail(it)
})
@Test
fun mapSnapshotter() {
var mapSnapshotter: MapSnapshotter?
rule.activity.runOnUiThread {
val bg = BackgroundLayer("rand_tint")
bg.setProperties(PropertyFactory.backgroundColor("rgba(255,128,0,0.7)"))
val options = MapSnapshotter.Options(512, 512)
.withPixelRatio(1.0f)
.withStyleBuilder(
Style.Builder().fromUri(Style.SATELLITE_STREETS)
.withLayerAbove(bg, "country-label")
)
.withCameraPosition(
CameraPosition.Builder()
.zoom(12.0)
.target(LatLng(51.145495, 5.742234))
.build()
)
mapSnapshotter = MapSnapshotter(rule.activity, options)
mapSnapshotter!!.start(
{
assertNotNull(it)
assertNotNull(it.bitmap)
countDownLatch.countDown()
},
{
Assert.fail(it)
}
)
}
if (!countDownLatch.await(30, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
if (!countDownLatch.await(30, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
}
}

View File

@@ -32,4 +32,4 @@ class MapDialogFragmentTest : AppCenter() {
Thread.sleep(2500)
Espresso.pressBack()
}
}
}

View File

@@ -7,66 +7,67 @@ import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.testapp.R
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import junit.framework.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
@RunWith(AndroidJUnit4::class)
class ImageMissingTest : AppCenter() {
@Rule
@JvmField
var rule = ActivityTestRule(EspressoTestActivity::class.java)
@Rule
@JvmField
var rule = ActivityTestRule(EspressoTestActivity::class.java)
private lateinit var mapView: MapView
private lateinit var latch: CountDownLatch
private lateinit var mapView: MapView
private lateinit var latch: CountDownLatch
@Before
fun setup() {
latch = CountDownLatch(1)
}
@Test
fun testMissingImage() {
rule.runOnUiThread {
initMap(styleJson).addOnStyleImageMissingListener {
assertEquals("missing-icon", it)
latch.countDown()
}
@Before
fun setup() {
latch = CountDownLatch(1)
}
if (!latch.await(10, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
@Test
fun testMissingImage() {
rule.runOnUiThread {
initMap(styleJson).addOnStyleImageMissingListener {
assertEquals("missing-icon", it)
latch.countDown()
}
}
@Test
fun testMissingImage_invalidSprite() {
rule.runOnUiThread {
initMap(styleJsonInvalidSprite).addOnStyleImageMissingListener {
assertEquals("missing-icon", it)
latch.countDown()
}
if (!latch.await(10, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
if (!latch.await(10, TimeUnit.SECONDS)) {
throw TimeoutException()
@Test
fun testMissingImage_invalidSprite() {
rule.runOnUiThread {
initMap(styleJsonInvalidSprite).addOnStyleImageMissingListener {
assertEquals("missing-icon", it)
latch.countDown()
}
}
if (!latch.await(10, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
}
private fun initMap(style: String): MapView {
mapView = rule.activity.findViewById(R.id.mapView)
mapView.getMapAsync { it.setStyle(Style.Builder().fromJson(style)) }
return mapView
}
private fun initMap(style: String): MapView {
mapView = rule.activity.findViewById(R.id.mapView)
mapView.getMapAsync { it.setStyle(Style.Builder().fromJson(style)) }
return mapView
}
companion object {
private const val styleJson = """
companion object {
private const val styleJson =
"""
{
"version": 8,
"name": "Mapbox Streets",
@@ -109,7 +110,8 @@ class ImageMissingTest : AppCenter() {
}
"""
private const val styleJsonInvalidSprite = """
private const val styleJsonInvalidSprite =
"""
{
"version": 8,
"name": "Mapbox Streets",
@@ -151,5 +153,5 @@ class ImageMissingTest : AppCenter() {
}]
}
"""
}
}
}
}

View File

@@ -11,99 +11,100 @@ import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.testapp.R
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import org.junit.Assert.*
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
@RunWith(AndroidJUnit4::class)
class RemoveUnusedImagesTest : AppCenter() {
@Rule
@JvmField
var rule = ActivityTestRule(EspressoTestActivity::class.java)
@Rule
@JvmField
var rule = ActivityTestRule(EspressoTestActivity::class.java)
private lateinit var mapView: MapView
private lateinit var mapboxMap: MapboxMap
private val latch = CountDownLatch(1)
private lateinit var mapView: MapView
private lateinit var mapboxMap: MapboxMap
private val latch = CountDownLatch(1)
@Before
fun setup() {
rule.runOnUiThread {
mapView = rule.activity.findViewById(R.id.mapView)
mapView.getMapAsync {
mapboxMap = it
mapboxMap.setStyle(Style.Builder().fromJson(styleJson))
}
}
}
@Test
fun testRemoveUnusedImagesUserProvidedListener() {
var callbackLatch = CountDownLatch(2)
rule.runOnUiThread {
mapView.addOnStyleImageMissingListener {
mapboxMap.style!!.addImage(it, Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888))
}
// Remove layer and source, so that rendered tiles are no longer used, therefore, map must
// notify client about unused images.
mapView.addOnDidBecomeIdleListener {
mapboxMap.style!!.removeLayer("icon")
mapboxMap.style!!.removeSource("geojson")
}
mapView.addOnCanRemoveUnusedStyleImageListener {
callbackLatch.countDown()
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 120.0), 8.0))
mapView.addOnDidFinishRenderingFrameListener {
assertNotNull(mapboxMap.style!!.getImage("small"))
assertNotNull(mapboxMap.style!!.getImage("large"))
latch.countDown()
@Before
fun setup() {
rule.runOnUiThread {
mapView = rule.activity.findViewById(R.id.mapView)
mapView.getMapAsync {
mapboxMap = it
mapboxMap.setStyle(Style.Builder().fromJson(styleJson))
}
}
return@addOnCanRemoveUnusedStyleImageListener false
}
}
if (!latch.await(5, TimeUnit.SECONDS) && !callbackLatch.await(5, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
@Test
fun testRemoveUnusedImagesUserProvidedListener() {
var callbackLatch = CountDownLatch(2)
rule.runOnUiThread {
mapView.addOnStyleImageMissingListener {
mapboxMap.style!!.addImage(it, Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888))
}
@Test
fun testRemoveUnusedImagesDefaultListener() {
rule.runOnUiThread {
mapView.addOnStyleImageMissingListener {
mapboxMap.style!!.addImage(it, Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888))
}
// Remove layer and source, so that rendered tiles are no longer used, therefore, map must
// notify client about unused images.
mapView.addOnDidBecomeIdleListener {
mapboxMap.style!!.removeLayer("icon")
mapboxMap.style!!.removeSource("geojson")
}
// Remove layer and source, so that rendered tiles are no longer used, thus
// map must request removal of unused images.
mapView.addOnDidBecomeIdleListener {
mapboxMap.style!!.removeLayer("icon")
mapboxMap.style!!.removeSource("geojson")
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 120.0), 8.0))
// Wait for the next frame and check that images were removed from the style.
mapView.addOnDidFinishRenderingFrameListener {
if (mapboxMap.style!!.getImage("small") == null && mapboxMap.style!!.getImage("large") == null) {
latch.countDown()
}
mapView.addOnCanRemoveUnusedStyleImageListener {
callbackLatch.countDown()
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 120.0), 8.0))
mapView.addOnDidFinishRenderingFrameListener {
assertNotNull(mapboxMap.style!!.getImage("small"))
assertNotNull(mapboxMap.style!!.getImage("large"))
latch.countDown()
}
return@addOnCanRemoveUnusedStyleImageListener false
}
}
if (!latch.await(5, TimeUnit.SECONDS) && !callbackLatch.await(5, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
}
if (!latch.await(5, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
@Test
fun testRemoveUnusedImagesDefaultListener() {
rule.runOnUiThread {
mapView.addOnStyleImageMissingListener {
mapboxMap.style!!.addImage(it, Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888))
}
companion object {
private const val styleJson = """
// Remove layer and source, so that rendered tiles are no longer used, thus
// map must request removal of unused images.
mapView.addOnDidBecomeIdleListener {
mapboxMap.style!!.removeLayer("icon")
mapboxMap.style!!.removeSource("geojson")
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 120.0), 8.0))
// Wait for the next frame and check that images were removed from the style.
mapView.addOnDidFinishRenderingFrameListener {
if (mapboxMap.style!!.getImage("small") == null && mapboxMap.style!!.getImage("large") == null) {
latch.countDown()
}
}
}
}
if (!latch.await(5, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
companion object {
private const val styleJson =
"""
{
"version": 8,
"name": "Mapbox Streets",
@@ -159,5 +160,5 @@ class RemoveUnusedImagesTest : AppCenter() {
}]
}
"""
}
}
}
}

View File

@@ -10,42 +10,43 @@ import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.maps.MapboxMapOptions
import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.MapboxGLSurfaceView
import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity
import java.util.concurrent.CountDownLatch
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
class RenderViewGetterTest : AppCenter() {
@Rule
@JvmField
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
@Rule
@JvmField
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
private lateinit var rootView: ViewGroup
private lateinit var mapView: MapView
private val latch: CountDownLatch = CountDownLatch(1)
private lateinit var rootView: ViewGroup
private lateinit var mapView: MapView
private val latch: CountDownLatch = CountDownLatch(1)
@Test
@UiThreadTest
fun testGLSurfaceView() {
rootView = rule.activity.findViewById(android.R.id.content)
mapView = MapView(rule.activity)
assertNotNull(mapView.renderView)
assertTrue(mapView.renderView is MapboxGLSurfaceView)
}
@Test
@UiThreadTest
fun testGLSurfaceView() {
rootView = rule.activity.findViewById(android.R.id.content)
mapView = MapView(rule.activity)
assertNotNull(mapView.renderView)
assertTrue(mapView.renderView is MapboxGLSurfaceView)
}
@Test
@UiThreadTest
fun testTextureView() {
rootView = rule.activity.findViewById(android.R.id.content)
mapView = MapView(rule.activity,
MapboxMapOptions.createFromAttributes(rule.activity, null)
.textureMode(true)
)
assertNotNull(mapView.renderView)
assertTrue(mapView.renderView is TextureView)
}
}
@Test
@UiThreadTest
fun testTextureView() {
rootView = rule.activity.findViewById(android.R.id.content)
mapView = MapView(
rule.activity,
MapboxMapOptions.createFromAttributes(rule.activity, null)
.textureMode(true)
)
assertNotNull(mapView.renderView)
assertTrue(mapView.renderView is TextureView)
}
}

View File

@@ -8,105 +8,121 @@ import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.testapp.R
import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@RunWith(AndroidJUnit4::class)
class ScreenCoordinateConversion : AppCenter() {
@Rule
@JvmField
var rule = ActivityTestRule(DeviceIndependentTestActivity::class.java)
@Rule
@JvmField
var rule = ActivityTestRule(DeviceIndependentTestActivity::class.java)
private lateinit var mapView: MapView
private lateinit var latch: CountDownLatch
private lateinit var mapView: MapView
private lateinit var latch: CountDownLatch
@Before
fun setup() {
latch = CountDownLatch(1)
}
@Test
fun testToScreenCoordinates() {
rule.runOnUiThread {
mapView = rule.activity.findViewById(R.id.mapView)
val expected = doubleArrayOf(261.6888889445351, 253.15541110551123, 267.37777788907033, 247.4627648056528)
val actual = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapView.getMapAsync {
val projection = it.projection
projection.toScreenLocations(doubleArrayOf(1.0, 2.0, 3.0, 4.0), actual)
// check all values
assertTrue(expected.contentEquals(actual))
// check first coordinate value
val pointFirst = PointF(expected[0].toFloat(), expected[1].toFloat())
val convertedFirst = projection.toScreenLocation(LatLng(1.0, 2.0))
assertEquals(
pointFirst.x, convertedFirst.x, DELTA_FLOAT
)
assertEquals(
pointFirst.y, convertedFirst.y, DELTA_FLOAT
)
// check second latlng value
val pointSecond = PointF(expected[2].toFloat(), expected[3].toFloat())
val convertedSecond = projection.toScreenLocation(LatLng(3.0, 4.0))
assertEquals(
pointSecond.x, convertedSecond.x, DELTA_FLOAT
)
assertEquals(
pointSecond.y, convertedSecond.y, DELTA_FLOAT
)
latch.countDown()
}
@Before
fun setup() {
latch = CountDownLatch(1)
}
latch.await(10, TimeUnit.SECONDS)
}
@Test
fun testFromScreenCoordinates() {
rule.runOnUiThread {
mapView = rule.activity.findViewById(R.id.mapView)
val expected = doubleArrayOf(66.2314571265913, -89.64843662311537, 65.94647142295494, -88.94531162999371)
val actual = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapView.getMapAsync {
val projection = it.projection
projection.fromScreenLocations(doubleArrayOf(1.0, 2.0, 3.0, 4.0), actual)
// check all values at once
assertTrue(expected.contentEquals(actual))
@Test
fun testToScreenCoordinates() {
rule.runOnUiThread {
mapView = rule.activity.findViewById(R.id.mapView)
val expected = doubleArrayOf(261.6888889445351, 253.15541110551123, 267.37777788907033, 247.4627648056528)
val actual = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapView.getMapAsync {
val projection = it.projection
projection.toScreenLocations(doubleArrayOf(1.0, 2.0, 3.0, 4.0), actual)
// check all values
assertTrue(expected.contentEquals(actual))
// check first coordinate value
val pointFirst = PointF(expected[0].toFloat(), expected[1].toFloat())
val convertedFirst = projection.toScreenLocation(LatLng(1.0, 2.0))
assertEquals(
pointFirst.x,
convertedFirst.x,
DELTA_FLOAT
)
assertEquals(
pointFirst.y,
convertedFirst.y,
DELTA_FLOAT
)
// check first latlng value
val latLngFirst = LatLng(expected[0], expected[1])
val convertedFirst = projection.fromScreenLocation(PointF(1.0f, 2.0f))
assertEquals(
latLngFirst.latitude, convertedFirst.latitude, DELTA_DOUBLE
)
assertEquals(
latLngFirst.longitude, convertedFirst.longitude, DELTA_DOUBLE
)
// check second latlng value
val latLngSecond = LatLng(expected[2], expected[3])
val convertedSecond = projection.fromScreenLocation(PointF(3.0f, 4.0f))
assertEquals(
latLngSecond.latitude, convertedSecond.latitude, DELTA_DOUBLE
)
assertEquals(
latLngSecond.longitude, convertedSecond.longitude, DELTA_DOUBLE
)
latch.countDown()
}
// check second latlng value
val pointSecond = PointF(expected[2].toFloat(), expected[3].toFloat())
val convertedSecond = projection.toScreenLocation(LatLng(3.0, 4.0))
assertEquals(
pointSecond.x,
convertedSecond.x,
DELTA_FLOAT
)
assertEquals(
pointSecond.y,
convertedSecond.y,
DELTA_FLOAT
)
latch.countDown()
}
}
latch.await(10, TimeUnit.SECONDS)
}
latch.await(10, TimeUnit.SECONDS)
}
companion object {
const val DELTA_DOUBLE = 0.000001
const val DELTA_FLOAT = 0.000001f
}
}
@Test
fun testFromScreenCoordinates() {
rule.runOnUiThread {
mapView = rule.activity.findViewById(R.id.mapView)
val expected = doubleArrayOf(66.2314571265913, -89.64843662311537, 65.94647142295494, -88.94531162999371)
val actual = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
mapView.getMapAsync {
val projection = it.projection
projection.fromScreenLocations(doubleArrayOf(1.0, 2.0, 3.0, 4.0), actual)
// check all values at once
assertTrue(expected.contentEquals(actual))
// check first latlng value
val latLngFirst = LatLng(expected[0], expected[1])
val convertedFirst = projection.fromScreenLocation(PointF(1.0f, 2.0f))
assertEquals(
latLngFirst.latitude,
convertedFirst.latitude,
DELTA_DOUBLE
)
assertEquals(
latLngFirst.longitude,
convertedFirst.longitude,
DELTA_DOUBLE
)
// check second latlng value
val latLngSecond = LatLng(expected[2], expected[3])
val convertedSecond = projection.fromScreenLocation(PointF(3.0f, 4.0f))
assertEquals(
latLngSecond.latitude,
convertedSecond.latitude,
DELTA_DOUBLE
)
assertEquals(
latLngSecond.longitude,
convertedSecond.longitude,
DELTA_DOUBLE
)
latch.countDown()
}
}
latch.await(10, TimeUnit.SECONDS)
}
companion object {
const val DELTA_DOUBLE = 0.000001
const val DELTA_FLOAT = 0.000001f
}
}

View File

@@ -28,4 +28,4 @@ class StyleLoadTest : EspressoTest() {
source.setGeoJson("{}")
}
}
}
}

View File

@@ -5,100 +5,103 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.ActivityTestRule
import com.mapbox.mapboxsdk.offline.OfflineManager
import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity
import java.util.concurrent.CountDownLatch
import org.junit.Assert
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
class CacheTest {
@Rule
@JvmField
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
@Rule
@JvmField
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
private val context: Context by lazy { rule.activity }
private val context: Context by lazy { rule.activity }
private val countDownLatch = CountDownLatch(1)
private val countDownLatch = CountDownLatch(1)
@Test
fun testSetMaximumAmbientCacheSize() {
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).setMaximumAmbientCacheSize(10000000, object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
countDownLatch.countDown()
@Test
fun testSetMaximumAmbientCacheSize() {
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).setMaximumAmbientCacheSize(
10000000,
object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
countDownLatch.countDown()
}
override fun onError(message: String) {
Assert.assertNull("onError should not be called", message)
}
}
)
}
override fun onError(message: String) {
Assert.assertNull("onError should not be called", message)
}
})
countDownLatch.await()
}
countDownLatch.await()
}
@Test
fun testSetClearAmbientCache() {
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).clearAmbientCache(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
countDownLatch.countDown()
}
@Test
fun testSetClearAmbientCache() {
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).clearAmbientCache(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
countDownLatch.countDown()
}
override fun onError(message: String) {
Assert.assertNull("onError should not be called", message)
override fun onError(message: String) {
Assert.assertNull("onError should not be called", message)
}
})
}
})
countDownLatch.await()
}
countDownLatch.await()
}
@Test
fun testSetInvalidateAmbientCache() {
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).invalidateAmbientCache(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
countDownLatch.countDown()
}
@Test
fun testSetInvalidateAmbientCache() {
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).invalidateAmbientCache(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
countDownLatch.countDown()
}
override fun onError(message: String) {
Assert.assertNull("onError should not be called", message)
override fun onError(message: String) {
Assert.assertNull("onError should not be called", message)
}
})
}
})
countDownLatch.await()
}
countDownLatch.await()
}
@Test
fun testSetResetDatabase() {
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).resetDatabase(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
countDownLatch.countDown()
}
@Test
fun testSetResetDatabase() {
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).resetDatabase(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
countDownLatch.countDown()
}
override fun onError(message: String) {
Assert.assertNull("onError should not be called", message)
override fun onError(message: String) {
Assert.assertNull("onError should not be called", message)
}
})
}
})
countDownLatch.await()
}
countDownLatch.await()
}
@Test
fun testSetPackDatabase() {
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).packDatabase(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
countDownLatch.countDown()
}
@Test
fun testSetPackDatabase() {
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).packDatabase(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
countDownLatch.countDown()
}
override fun onError(message: String) {
Assert.assertNull("onError should not be called", message)
override fun onError(message: String) {
Assert.assertNull("onError should not be called", message)
}
})
}
})
countDownLatch.await()
}
countDownLatch.await()
}
}
}

View File

@@ -9,116 +9,120 @@ import com.mapbox.mapboxsdk.offline.OfflineRegion
import com.mapbox.mapboxsdk.storage.FileSource
import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity
import com.mapbox.mapboxsdk.testapp.utils.FileUtils
import java.io.IOException
import java.util.concurrent.CountDownLatch
import org.junit.FixMethodOrder
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.io.IOException
import java.util.concurrent.CountDownLatch
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@RunWith(AndroidJUnit4::class)
class OfflineManagerTest : AppCenter() {
companion object {
private const val TEST_DB_FILE_NAME = "offline_test.db"
private lateinit var mergedRegion: OfflineRegion
}
@Rule
@JvmField
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
private val context: Context by lazy { rule.activity }
@Test(timeout = 30_000)
fun a_copyFileFromAssets() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
FileUtils.CopyFileFromAssetsTask(rule.activity, object : FileUtils.OnFileCopiedFromAssetsListener {
override fun onFileCopiedFromAssets() {
latch.countDown()
}
override fun onError() {
throw IOException("Unable to copy DB file.")
}
}).execute(TEST_DB_FILE_NAME, FileSource.getResourcesCachePath(rule.activity))
companion object {
private const val TEST_DB_FILE_NAME = "offline_test.db"
private lateinit var mergedRegion: OfflineRegion
}
latch.await()
}
@Test(timeout = 30_000)
fun b_mergeRegion() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).mergeOfflineRegions(
FileSource.getResourcesCachePath(rule.activity) + "/" + TEST_DB_FILE_NAME,
object : OfflineManager.MergeOfflineRegionsCallback {
override fun onMerge(offlineRegions: Array<out OfflineRegion>?) {
assert(offlineRegions?.size == 1)
latch.countDown()
}
@Rule
@JvmField
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
override fun onError(error: String?) {
throw RuntimeException("Unable to merge external offline database. $error")
}
})
private val context: Context by lazy { rule.activity }
@Test(timeout = 30_000)
fun a_copyFileFromAssets() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
FileUtils.CopyFileFromAssetsTask(
rule.activity,
object : FileUtils.OnFileCopiedFromAssetsListener {
override fun onFileCopiedFromAssets() {
latch.countDown()
}
override fun onError() {
throw IOException("Unable to copy DB file.")
}
}
).execute(TEST_DB_FILE_NAME, FileSource.getResourcesCachePath(rule.activity))
}
latch.await()
}
latch.await()
}
@Test(timeout = 30_000)
fun c_listRegion() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
override fun onList(offlineRegions: Array<out OfflineRegion>?) {
assert(offlineRegions?.size == 1)
mergedRegion = offlineRegions!![0]
latch.countDown()
}
@Test(timeout = 30_000)
fun b_mergeRegion() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).mergeOfflineRegions(
FileSource.getResourcesCachePath(rule.activity) + "/" + TEST_DB_FILE_NAME,
object : OfflineManager.MergeOfflineRegionsCallback {
override fun onMerge(offlineRegions: Array<out OfflineRegion>?) {
assert(offlineRegions?.size == 1)
latch.countDown()
}
override fun onError(error: String?) {
throw RuntimeException("Unable to merge external offline database. $error")
override fun onError(error: String?) {
throw RuntimeException("Unable to merge external offline database. $error")
}
}
)
}
})
latch.await()
}
latch.await()
}
@Test(timeout = 30_000)
fun d_invalidateRegion() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
mergedRegion.invalidate(object : OfflineRegion.OfflineRegionInvalidateCallback {
override fun onInvalidate() {
latch.countDown()
}
@Test(timeout = 30_000)
fun c_listRegion() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
OfflineManager.getInstance(context).listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
override fun onList(offlineRegions: Array<out OfflineRegion>?) {
assert(offlineRegions?.size == 1)
mergedRegion = offlineRegions!![0]
latch.countDown()
}
override fun onError(error: String?) {
throw RuntimeException("Unable to delete region")
override fun onError(error: String?) {
throw RuntimeException("Unable to merge external offline database. $error")
}
})
}
})
latch.await()
}
latch.await()
}
@Test(timeout = 30_000)
fun e_deleteRegion() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
mergedRegion.delete(object : OfflineRegion.OfflineRegionDeleteCallback {
override fun onDelete() {
latch.countDown()
}
@Test(timeout = 30_000)
fun d_invalidateRegion() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
mergedRegion.invalidate(object : OfflineRegion.OfflineRegionInvalidateCallback {
override fun onInvalidate() {
latch.countDown()
}
override fun onError(error: String?) {
throw RuntimeException("Unable to delete region")
override fun onError(error: String?) {
throw RuntimeException("Unable to delete region")
}
})
}
})
latch.await()
}
latch.await()
}
}
@Test(timeout = 30_000)
fun e_deleteRegion() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
mergedRegion.delete(object : OfflineRegion.OfflineRegionDeleteCallback {
override fun onDelete() {
latch.countDown()
}
override fun onError(error: String?) {
throw RuntimeException("Unable to delete region")
}
})
}
latch.await()
}
}

View File

@@ -6,7 +6,6 @@ import androidx.test.rule.ActivityTestRule
import com.mapbox.mapboxsdk.AppCenter
import com.mapbox.mapboxsdk.storage.FileSource
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity
import java.util.concurrent.CountDownLatch
import junit.framework.Assert
import org.junit.After
import org.junit.Before
@@ -14,45 +13,49 @@ import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestName
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
open class FileSourceMapTest : AppCenter() {
private lateinit var fileSourceTestUtils: FileSourceTestUtils
private lateinit var fileSourceTestUtils: FileSourceTestUtils
@get:Rule
val rule = ActivityTestRule(EspressoTestActivity::class.java)
@get:Rule
val rule = ActivityTestRule(EspressoTestActivity::class.java)
@get:Rule
val testName = TestName()
@get:Rule
val testName = TestName()
@Before
@UiThreadTest
fun setup() {
fileSourceTestUtils = FileSourceTestUtils(rule.activity)
fileSourceTestUtils.setup()
}
@Test
fun changeResourcesPathWhileMapVisible() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
FileSource.setResourcesCachePath(fileSourceTestUtils.testPath, object : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
latch.countDown()
Assert.assertEquals(fileSourceTestUtils.testPath, path)
}
override fun onError(message: String) {
Assert.fail("Resources path can be changed while the map is running")
}
})
@Before
@UiThreadTest
fun setup() {
fileSourceTestUtils = FileSourceTestUtils(rule.activity)
fileSourceTestUtils.setup()
}
latch.await()
}
@After
fun cleanup() {
fileSourceTestUtils.cleanup()
}
}
@Test
fun changeResourcesPathWhileMapVisible() {
val latch = CountDownLatch(1)
rule.activity.runOnUiThread {
FileSource.setResourcesCachePath(
fileSourceTestUtils.testPath,
object : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
latch.countDown()
Assert.assertEquals(fileSourceTestUtils.testPath, path)
}
override fun onError(message: String) {
Assert.fail("Resources path can be changed while the map is running")
}
}
)
}
latch.await()
}
@After
fun cleanup() {
fileSourceTestUtils.cleanup()
}
}

View File

@@ -6,105 +6,107 @@ import androidx.test.rule.ActivityTestRule
import com.mapbox.mapboxsdk.AppCenter
import com.mapbox.mapboxsdk.storage.FileSource
import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import org.junit.*
import org.junit.rules.TestName
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@RunWith(AndroidJUnit4::class)
class FileSourceStandaloneTest : AppCenter() {
private lateinit var fileSourceTestUtils: FileSourceTestUtils
private lateinit var fileSource: FileSource
private lateinit var fileSourceTestUtils: FileSourceTestUtils
private lateinit var fileSource: FileSource
@get:Rule
val rule = ActivityTestRule(FeatureOverviewActivity::class.java)
@get:Rule
val rule = ActivityTestRule(FeatureOverviewActivity::class.java)
@get:Rule
val testName = TestName()
@get:Rule
val testName = TestName()
@Before
@UiThreadTest
fun setup() {
fileSource = FileSource.getInstance(rule.activity)
fileSourceTestUtils = FileSourceTestUtils(rule.activity)
fileSourceTestUtils.setup()
}
@Before
@UiThreadTest
fun setup() {
fileSource = FileSource.getInstance(rule.activity)
fileSourceTestUtils = FileSourceTestUtils(rule.activity)
fileSourceTestUtils.setup()
}
@Test
@UiThreadTest
fun testDefault() {
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
}
@Test
@UiThreadTest
fun testDefault() {
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
}
@Test
@UiThreadTest
fun testActivateDeactivate() {
Assert.assertTrue("1) FileSource should be active", fileSource.isActivated)
fileSource.deactivate()
Assert.assertFalse("2) FileSource should not be active", fileSource.isActivated)
fileSource.activate()
Assert.assertTrue("3) FileSource should be active", fileSource.isActivated)
}
@Test
@UiThreadTest
fun testActivateDeactivate() {
Assert.assertTrue("1) FileSource should be active", fileSource.isActivated)
fileSource.deactivate()
Assert.assertFalse("2) FileSource should not be active", fileSource.isActivated)
fileSource.activate()
Assert.assertTrue("3) FileSource should be active", fileSource.isActivated)
}
@Test
fun pathChangeTest() {
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
Assert.assertEquals(fileSourceTestUtils.originalPath, FileSource.getResourcesCachePath(rule.activity))
@Test
fun pathChangeTest() {
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
Assert.assertEquals(fileSourceTestUtils.originalPath, FileSource.getResourcesCachePath(rule.activity))
fileSourceTestUtils.changePath(fileSourceTestUtils.testPath)
Assert.assertEquals(fileSourceTestUtils.testPath, FileSource.getResourcesCachePath(rule.activity))
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
fileSourceTestUtils.changePath(fileSourceTestUtils.testPath)
Assert.assertEquals(fileSourceTestUtils.testPath, FileSource.getResourcesCachePath(rule.activity))
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
fileSourceTestUtils.changePath(fileSourceTestUtils.originalPath)
Assert.assertEquals(fileSourceTestUtils.originalPath, FileSource.getResourcesCachePath(rule.activity))
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
}
fileSourceTestUtils.changePath(fileSourceTestUtils.originalPath)
Assert.assertEquals(fileSourceTestUtils.originalPath, FileSource.getResourcesCachePath(rule.activity))
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
}
@Test
fun overridePathChangeCallTest() {
val firstLatch = CountDownLatch(1)
val secondLatch = CountDownLatch(1)
rule.activity.runOnUiThread {
FileSource.setResourcesCachePath(
fileSourceTestUtils.testPath,
object : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
Assert.assertEquals(fileSourceTestUtils.testPath, path)
firstLatch.countDown()
}
@Test
fun overridePathChangeCallTest() {
val firstLatch = CountDownLatch(1)
val secondLatch = CountDownLatch(1)
rule.activity.runOnUiThread {
FileSource.setResourcesCachePath(
fileSourceTestUtils.testPath,
object : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
Assert.assertEquals(fileSourceTestUtils.testPath, path)
firstLatch.countDown()
}
override fun onError(message: String) {
override fun onError(message: String) {
Assert.fail("First attempt should succeed.")
}
}
)
FileSource.setResourcesCachePath(
fileSourceTestUtils.testPath2,
object : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
Assert.fail("Second attempt should fail because first one is in progress.")
}
override fun onError(message: String) {
Assert.assertEquals("Another resources cache path change is in progress", message)
secondLatch.countDown()
}
}
)
}
if (!secondLatch.await(5, TimeUnit.SECONDS)) {
Assert.fail("Second attempt should fail.")
}
if (!firstLatch.await(5, TimeUnit.SECONDS)) {
Assert.fail("First attempt should succeed.")
}
})
FileSource.setResourcesCachePath(
fileSourceTestUtils.testPath2,
object : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
Assert.fail("Second attempt should fail because first one is in progress.")
}
override fun onError(message: String) {
Assert.assertEquals("Another resources cache path change is in progress", message)
secondLatch.countDown()
}
})
}
}
if (!secondLatch.await(5, TimeUnit.SECONDS)) {
Assert.fail("Second attempt should fail.")
@After
fun cleanup() {
fileSourceTestUtils.cleanup()
}
if (!firstLatch.await(5, TimeUnit.SECONDS)) {
Assert.fail("First attempt should succeed.")
}
}
@After
fun cleanup() {
fileSourceTestUtils.cleanup()
}
}
}

View File

@@ -4,56 +4,57 @@ import android.app.Activity
import androidx.annotation.WorkerThread
import com.mapbox.mapboxsdk.AppCenter
import com.mapbox.mapboxsdk.storage.FileSource
import junit.framework.Assert
import java.io.File
import java.util.concurrent.CountDownLatch
import junit.framework.Assert
class FileSourceTestUtils(private val activity: Activity) : AppCenter() {
val originalPath = FileSource.getResourcesCachePath(activity)
val testPath = "$originalPath/test"
val testPath2 = "$originalPath/test2"
val originalPath = FileSource.getResourcesCachePath(activity)
val testPath = "$originalPath/test"
val testPath2 = "$originalPath/test2"
private val paths = listOf(testPath, testPath2)
private val paths = listOf(testPath, testPath2)
fun setup() {
for (path in paths) {
val testFile = File(path)
testFile.mkdirs()
}
}
@WorkerThread
fun cleanup() {
val currentPath = FileSource.getResourcesCachePath(activity)
if (currentPath != originalPath) {
changePath(originalPath)
fun setup() {
for (path in paths) {
val testFile = File(path)
testFile.mkdirs()
}
}
for (path in paths) {
val testFile = File(path)
if (testFile.exists()) {
testFile.deleteRecursively()
}
}
}
@WorkerThread
fun cleanup() {
val currentPath = FileSource.getResourcesCachePath(activity)
if (currentPath != originalPath) {
changePath(originalPath)
}
@WorkerThread
fun changePath(requestedPath: String) {
val latch = CountDownLatch(1)
activity.runOnUiThread {
FileSource.setResourcesCachePath(
requestedPath,
object : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
Assert.assertEquals(requestedPath, path)
latch.countDown()
}
override fun onError(message: String) {
Assert.fail("Resource path change failed - path: $requestedPath, message: $message")
}
})
for (path in paths) {
val testFile = File(path)
if (testFile.exists()) {
testFile.deleteRecursively()
}
}
}
latch.await()
}
}
@WorkerThread
fun changePath(requestedPath: String) {
val latch = CountDownLatch(1)
activity.runOnUiThread {
FileSource.setResourcesCachePath(
requestedPath,
object : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
Assert.assertEquals(requestedPath, path)
latch.countDown()
}
override fun onError(message: String) {
Assert.fail("Resource path change failed - path: $requestedPath, message: $message")
}
}
)
}
latch.await()
}
}

View File

@@ -19,92 +19,98 @@ import org.junit.Test
class CustomGeometrySourceTest : BaseTest() {
override fun getActivityClass(): Class<*> = GridSourceActivity::class.java
override fun getActivityClass(): Class<*> = GridSourceActivity::class.java
@Test
fun sourceNotLeakingThreadsTest() {
validateTestSetup()
WaitAction.invoke(4000)
onView(isRoot()).perform(orientationLandscape())
WaitAction.invoke(2000)
onView(isRoot()).perform(orientationPortrait())
WaitAction.invoke(2000)
Assert.assertFalse("Threads should be shutdown when the source is destroyed.",
Thread.getAllStackTraces().keys.filter {
it.name.startsWith(THREAD_PREFIX)
}.count() > THREAD_POOL_LIMIT)
}
@Test
fun threadsShutdownWhenSourceRemovedTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.style!!.removeLayer(ID_GRID_LAYER)
TestingAsyncUtils.waitForLayer(uiController, mapView)
mapboxMap.style!!.removeSource(ID_GRID_SOURCE)
TestingAsyncUtils.waitForLayer(uiController, mapView)
Assert.assertTrue("There should be no threads running when the source is removed.",
Thread.getAllStackTraces().keys.filter {
it.name.startsWith(THREAD_PREFIX)
}.count() == 0)
@Test
fun sourceNotLeakingThreadsTest() {
validateTestSetup()
WaitAction.invoke(4000)
onView(isRoot()).perform(orientationLandscape())
WaitAction.invoke(2000)
onView(isRoot()).perform(orientationPortrait())
WaitAction.invoke(2000)
Assert.assertFalse(
"Threads should be shutdown when the source is destroyed.",
Thread.getAllStackTraces().keys.filter {
it.name.startsWith(THREAD_PREFIX)
}.count() > THREAD_POOL_LIMIT
)
}
}
@Test
fun threadsRestartedWhenSourceReAddedTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.style!!.removeLayer((rule.activity as GridSourceActivity).layer)
TestingAsyncUtils.waitForLayer(uiController, mapView)
mapboxMap.style!!.removeSource(ID_GRID_SOURCE)
TestingAsyncUtils.waitForLayer(uiController, mapView)
mapboxMap.style!!.addSource((rule.activity as GridSourceActivity).source)
mapboxMap.style!!.addLayer((rule.activity as GridSourceActivity).layer)
TestingAsyncUtils.waitForLayer(uiController, mapView)
Assert.assertTrue("Threads should be restarted when the source is re-added to the map.",
Thread.getAllStackTraces().keys.filter {
it.name.startsWith(THREAD_PREFIX)
}.count() == THREAD_POOL_LIMIT)
@Test
fun threadsShutdownWhenSourceRemovedTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.style!!.removeLayer(ID_GRID_LAYER)
TestingAsyncUtils.waitForLayer(uiController, mapView)
mapboxMap.style!!.removeSource(ID_GRID_SOURCE)
TestingAsyncUtils.waitForLayer(uiController, mapView)
Assert.assertTrue(
"There should be no threads running when the source is removed.",
Thread.getAllStackTraces().keys.filter {
it.name.startsWith(THREAD_PREFIX)
}.count() == 0
)
}
}
}
@Test
fun sourceZoomDeltaTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.prefetchZoomDelta = 3
mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let {
assertNull(it.prefetchZoomDelta)
it.prefetchZoomDelta = 5
assertNotNull(it.prefetchZoomDelta)
assertEquals(5, it.prefetchZoomDelta!!)
it.prefetchZoomDelta = null
assertNull(it.prefetchZoomDelta)
}
@Test
fun threadsRestartedWhenSourceReAddedTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.style!!.removeLayer((rule.activity as GridSourceActivity).layer)
TestingAsyncUtils.waitForLayer(uiController, mapView)
mapboxMap.style!!.removeSource(ID_GRID_SOURCE)
TestingAsyncUtils.waitForLayer(uiController, mapView)
mapboxMap.style!!.addSource((rule.activity as GridSourceActivity).source)
mapboxMap.style!!.addLayer((rule.activity as GridSourceActivity).layer)
TestingAsyncUtils.waitForLayer(uiController, mapView)
Assert.assertTrue(
"Threads should be restarted when the source is re-added to the map.",
Thread.getAllStackTraces().keys.filter {
it.name.startsWith(THREAD_PREFIX)
}.count() == THREAD_POOL_LIMIT
)
}
}
}
@Test
fun isVolatileTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let {
assertFalse(it.isVolatile)
it.isVolatile = true
assertTrue(it.isVolatile)
}
@Test
fun sourceZoomDeltaTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.prefetchZoomDelta = 3
mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let {
assertNull(it.prefetchZoomDelta)
it.prefetchZoomDelta = 5
assertNotNull(it.prefetchZoomDelta)
assertEquals(5, it.prefetchZoomDelta!!)
it.prefetchZoomDelta = null
assertNull(it.prefetchZoomDelta)
}
}
}
}
@Test
fun minimumTileUpdateIntervalTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let {
assertEquals(0, it.minimumTileUpdateInterval)
it.minimumTileUpdateInterval = 1000
assertEquals(1000, it.minimumTileUpdateInterval)
}
@Test
fun isVolatileTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let {
assertFalse(it.isVolatile)
it.isVolatile = true
assertTrue(it.isVolatile)
}
}
}
}
}
@Test
fun minimumTileUpdateIntervalTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let {
assertEquals(0, it.minimumTileUpdateInterval)
it.minimumTileUpdateInterval = 1000
assertEquals(1000, it.minimumTileUpdateInterval)
}
}
}
}

View File

@@ -6,11 +6,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.mapbox.mapboxsdk.testapp.R
import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction
import com.mapbox.mapboxsdk.testapp.activity.EspressoTest
import java.util.*
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import java.util.*
/**
* CRUD tests around Image
@@ -18,58 +18,58 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ImageTest : EspressoTest() {
companion object {
private const val IMAGE_ID = "test.image"
}
@Test
fun testAddGetImage() {
validateTestSetup()
MapboxMapAction.invoke(mapboxMap) { uiController, mapboxMap ->
val drawable = rule.activity.resources.getDrawable(R.drawable.ic_launcher_round)
assertTrue(drawable is BitmapDrawable)
val bitmapSet = (drawable as BitmapDrawable).bitmap
mapboxMap.style!!.addImage(IMAGE_ID, bitmapSet)
// adding an image requires converting the image with an asynctask
uiController.loopMainThreadForAtLeast(200)
val bitmapGet = mapboxMap.style!!.getImage(IMAGE_ID)
assertTrue(bitmapGet!!.similarTo(bitmapSet))
mapboxMap.style!!.removeImage(IMAGE_ID)
assertNull(mapboxMap.style!!.getImage(IMAGE_ID))
companion object {
private const val IMAGE_ID = "test.image"
}
@Test
fun testAddGetImage() {
validateTestSetup()
MapboxMapAction.invoke(mapboxMap) { uiController, mapboxMap ->
val drawable = rule.activity.resources.getDrawable(R.drawable.ic_launcher_round)
assertTrue(drawable is BitmapDrawable)
val bitmapSet = (drawable as BitmapDrawable).bitmap
mapboxMap.style!!.addImage(IMAGE_ID, bitmapSet)
// adding an image requires converting the image with an asynctask
uiController.loopMainThreadForAtLeast(200)
val bitmapGet = mapboxMap.style!!.getImage(IMAGE_ID)
assertTrue(bitmapGet!!.similarTo(bitmapSet))
mapboxMap.style!!.removeImage(IMAGE_ID)
assertNull(mapboxMap.style!!.getImage(IMAGE_ID))
}
}
}
}
/**
* Alternative implementation of Bitmap.sameAs #14060
*/
fun Bitmap.similarTo(other: Bitmap): Boolean {
if (invalidConfig(other)) {
return false
}
// Allocate arrays
val argb = IntArray(width * height)
val argbOther = IntArray(other.width * other.height)
getPixels(argb, 0, width, 0, 0, width, height)
other.getPixels(argbOther, 0, width, 0, 0, width, height)
// Alpha channel special check
if (config == Bitmap.Config.ALPHA_8) {
// in this case we have to manually compare the alpha channel as the rest is garbage.
val length = width * height
for (i in 0 until length) {
if (argb[i] and -0x1000000 != argbOther[i] and -0x1000000) {
if (invalidConfig(other)) {
return false
}
}
return true
}
return Arrays.equals(argb, argbOther)
// Allocate arrays
val argb = IntArray(width * height)
val argbOther = IntArray(other.width * other.height)
getPixels(argb, 0, width, 0, 0, width, height)
other.getPixels(argbOther, 0, width, 0, 0, width, height)
// Alpha channel special check
if (config == Bitmap.Config.ALPHA_8) {
// in this case we have to manually compare the alpha channel as the rest is garbage.
val length = width * height
for (i in 0 until length) {
if (argb[i] and -0x1000000 != argbOther[i] and -0x1000000) {
return false
}
}
return true
}
return Arrays.equals(argb, argbOther)
}
fun Bitmap.invalidConfig(other: Bitmap): Boolean = this.config != other.config || this.width != other.width || this.height != other.height
fun Bitmap.invalidConfig(other: Bitmap): Boolean = this.config != other.config || this.width != other.width || this.height != other.height

View File

@@ -4,15 +4,15 @@ import androidx.test.espresso.UiController
import com.mapbox.mapboxsdk.maps.MapView
object TestingAsyncUtils {
private const val DEFAULT_TIMEOUT = 15_000L
private const val DEFAULT_TIMEOUT = 15_000L
fun waitForLayer(uiController: UiController, mapView: MapView) {
val start = System.nanoTime() / 1E6
var isIdle = false
mapView.addOnDidBecomeIdleListener { isIdle = true }
fun waitForLayer(uiController: UiController, mapView: MapView) {
val start = System.nanoTime() / 1E6
var isIdle = false
mapView.addOnDidBecomeIdleListener { isIdle = true }
while (!isIdle && System.nanoTime() / 1E6 - start < DEFAULT_TIMEOUT) {
uiController.loopMainThreadForAtLeast(100)
while (!isIdle && System.nanoTime() / 1E6 - start < DEFAULT_TIMEOUT) {
uiController.loopMainThreadForAtLeast(100)
}
}
}
}
}

View File

@@ -19,147 +19,149 @@ import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
import com.mapbox.mapboxsdk.testapp.R
import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil.loadStringFromAssets
import com.mapbox.mapboxsdk.utils.BitmapUtils
import java.net.URISyntaxException
import kotlinx.android.synthetic.main.activity_latlngbounds.*
import java.net.URISyntaxException
/**
* Test activity showcasing using the LatLngBounds camera API.
*/
class LatLngBoundsActivity : AppCompatActivity() {
private lateinit var mapboxMap: MapboxMap
private lateinit var bottomSheetBehavior: BottomSheetBehavior<*>
private lateinit var bounds: LatLngBounds
private lateinit var mapboxMap: MapboxMap
private lateinit var bottomSheetBehavior: BottomSheetBehavior<*>
private lateinit var bounds: LatLngBounds
private val peekHeight by lazy {
375.toPx(this) // 375dp
}
private val additionalPadding by lazy {
32.toPx(this) // 32dp
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_latlngbounds)
initMapView(savedInstanceState)
}
private fun initMapView(savedInstanceState: Bundle?) {
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
mapboxMap = map
val featureCollection: FeatureCollection = fromJson(loadStringFromAssets(this, "points-sf.geojson"))
bounds = createBounds(featureCollection)
map.getCameraForLatLngBounds(bounds, createPadding(peekHeight))?.let {
map.cameraPosition = it
}
try {
loadStyle(featureCollection)
} catch (e: URISyntaxException) {
e.printStackTrace()
}
private val peekHeight by lazy {
375.toPx(this) // 375dp
}
}
private fun loadStyle(featureCollection: FeatureCollection) {
mapboxMap.setStyle(Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withLayer(SymbolLayer("symbol", "symbol")
.withProperties(
iconAllowOverlap(true),
iconIgnorePlacement(true),
iconImage("icon"),
iconAnchor(ICON_ANCHOR_CENTER)
)
)
.withSource(GeoJsonSource("symbol", featureCollection))
.withImage("icon", BitmapUtils.getDrawableFromRes(this@LatLngBoundsActivity, R.drawable.ic_android)!!)
) {
initBottomSheet()
fab.setOnClickListener { bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED }
private val additionalPadding by lazy {
32.toPx(this) // 32dp
}
}
private fun initBottomSheet() {
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
bottomSheetBehavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val offset = convertSlideOffset(slideOffset)
val bottomPadding = (peekHeight * offset).toInt()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_latlngbounds)
initMapView(savedInstanceState)
}
mapboxMap.getCameraForLatLngBounds(bounds, createPadding(bottomPadding))?.let {
mapboxMap.cameraPosition = it
private fun initMapView(savedInstanceState: Bundle?) {
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
mapboxMap = map
val featureCollection: FeatureCollection = fromJson(loadStringFromAssets(this, "points-sf.geojson"))
bounds = createBounds(featureCollection)
map.getCameraForLatLngBounds(bounds, createPadding(peekHeight))?.let {
map.cameraPosition = it
}
try {
loadStyle(featureCollection)
} catch (e: URISyntaxException) {
e.printStackTrace()
}
}
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
// no-op
}
})
}
// slideOffset ranges from NaN to -1.0, range from 1.0 to 0 instead
fun convertSlideOffset(slideOffset: Float): Float {
return if (slideOffset.equals(Float.NaN)) {
1.0f
} else {
1 + slideOffset
}
}
fun createPadding(bottomPadding: Int): IntArray {
return intArrayOf(additionalPadding, additionalPadding, additionalPadding, bottomPadding)
}
private fun createBounds(featureCollection: FeatureCollection): LatLngBounds {
val boundsBuilder = LatLngBounds.Builder()
featureCollection.features()?.let {
for (feature in it) {
val point = feature.geometry() as Point
boundsBuilder.include(LatLng(point.latitude(), point.longitude()))
}
private fun loadStyle(featureCollection: FeatureCollection) {
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withLayer(
SymbolLayer("symbol", "symbol")
.withProperties(
iconAllowOverlap(true),
iconIgnorePlacement(true),
iconImage("icon"),
iconAnchor(ICON_ANCHOR_CENTER)
)
)
.withSource(GeoJsonSource("symbol", featureCollection))
.withImage("icon", BitmapUtils.getDrawableFromRes(this@LatLngBoundsActivity, R.drawable.ic_android)!!)
) {
initBottomSheet()
fab.setOnClickListener { bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED }
}
}
return boundsBuilder.build()
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
private fun initBottomSheet() {
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
bottomSheetBehavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val offset = convertSlideOffset(slideOffset)
val bottomPadding = (peekHeight * offset).toInt()
override fun onResume() {
super.onResume()
mapView.onResume()
}
mapboxMap.getCameraForLatLngBounds(bounds, createPadding(bottomPadding))?.let {
mapboxMap.cameraPosition = it
}
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
// no-op
}
})
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
// slideOffset ranges from NaN to -1.0, range from 1.0 to 0 instead
fun convertSlideOffset(slideOffset: Float): Float {
return if (slideOffset.equals(Float.NaN)) {
1.0f
} else {
1 + slideOffset
}
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
fun createPadding(bottomPadding: Int): IntArray {
return intArrayOf(additionalPadding, additionalPadding, additionalPadding, bottomPadding)
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
private fun createBounds(featureCollection: FeatureCollection): LatLngBounds {
val boundsBuilder = LatLngBounds.Builder()
featureCollection.features()?.let {
for (feature in it) {
val point = feature.geometry() as Point
boundsBuilder.include(LatLng(point.latitude(), point.longitude()))
}
}
return boundsBuilder.build()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
}
fun Int.toPx(context: Context): Int = (this * context.resources.displayMetrics.density).toInt()
fun Int.toPx(context: Context): Int = (this * context.resources.displayMetrics.density).toInt()

View File

@@ -63,4 +63,4 @@ class PixelTestActivity : AppCompatActivity(), OnMapReadyCallback {
super.onLowMemory()
mapView.onLowMemory()
}
}
}

View File

@@ -14,54 +14,54 @@ import kotlinx.android.synthetic.main.activity_backstack_fragment.*
*/
class FragmentBackStackActivity : AppCompatActivity() {
companion object {
private const val FRAGMENT_TAG = "map_fragment"
}
companion object {
private const val FRAGMENT_TAG = "map_fragment"
}
private lateinit var mapFragment: SupportMapFragment
private lateinit var mapFragment: SupportMapFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_backstack_fragment)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_backstack_fragment)
if (savedInstanceState == null) {
mapFragment = SupportMapFragment.newInstance()
mapFragment.getMapAsync { initMap(it) }
if (savedInstanceState == null) {
mapFragment = SupportMapFragment.newInstance()
mapFragment.getMapAsync { initMap(it) }
supportFragmentManager.beginTransaction().apply {
add(R.id.container, mapFragment, FRAGMENT_TAG)
}.commit()
} else {
supportFragmentManager.findFragmentByTag(FRAGMENT_TAG)?.also { fragment ->
if (fragment is SupportMapFragment) {
fragment.getMapAsync { initMap(it) }
supportFragmentManager.beginTransaction().apply {
add(R.id.container, mapFragment, FRAGMENT_TAG)
}.commit()
} else {
supportFragmentManager.findFragmentByTag(FRAGMENT_TAG)?.also { fragment ->
if (fragment is SupportMapFragment) {
fragment.getMapAsync { initMap(it) }
}
}
}
}
button.setOnClickListener { handleClick() }
}
button.setOnClickListener { handleClick() }
}
private fun initMap(mapboxMap: MapboxMap) {
mapboxMap.setStyle(Style.SATELLITE) {
mapboxMap.setPadding(300, 300, 300, 300)
private fun initMap(mapboxMap: MapboxMap) {
mapboxMap.setStyle(Style.SATELLITE) {
mapboxMap.setPadding(300, 300, 300, 300)
}
}
}
private fun handleClick() {
supportFragmentManager.beginTransaction().apply {
replace(R.id.container, NestedViewPagerActivity.ItemAdapter.EmptyFragment())
addToBackStack("map_empty_fragment")
}.commit()
}
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount == 0) {
// activity uses singleInstance for testing purposes
// code below provides a default navigation when using the app
NavUtils.navigateHome(this)
} else {
super.onBackPressed()
private fun handleClick() {
supportFragmentManager.beginTransaction().apply {
replace(R.id.container, NestedViewPagerActivity.ItemAdapter.EmptyFragment())
addToBackStack("map_empty_fragment")
}.commit()
}
}
}
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount == 0) {
// activity uses singleInstance for testing purposes
// code below provides a default navigation when using the app
NavUtils.navigateHome(this)
} else {
super.onBackPressed()
}
}
}

View File

@@ -41,9 +41,9 @@ class NestedViewPagerActivity : AppCompatActivity() {
class ItemAdapter(private val context: Context, private val inflater: LayoutInflater, private val fragmentManager: androidx.fragment.app.FragmentManager) : androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
private val items = listOf(
"one", "two", "three", ViewPagerItem(), "four", "five", "six", "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
"nineteen", "twenty", "twenty-one"
"one", "two", "three", ViewPagerItem(), "four", "five", "six", "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
"nineteen", "twenty", "twenty-one"
)
private var mapHolder: ViewPagerHolder? = null
@@ -162,4 +162,4 @@ class NestedViewPagerActivity : AppCompatActivity() {
}
}
}
}
}

View File

@@ -19,84 +19,85 @@ import kotlinx.android.synthetic.main.activity_viewpager.*
*/
class ViewPagerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_viewpager)
viewPager.adapter = MapFragmentAdapter(this, supportFragmentManager)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
val currentPosition = viewPager.currentItem
val offscreenLimit = viewPager.offscreenPageLimit
for (i in currentPosition - offscreenLimit..currentPosition + offscreenLimit) {
if (i < 0 || i > viewPager.adapter?.count ?: 0) {
continue
}
val mapFragment = viewPager.adapter?.instantiateItem(viewPager, i) as SupportMapFragment
mapFragment.getMapAsync(i)
}
}
internal class MapFragmentAdapter(private val context: Context, fragmentManager: androidx.fragment.app.FragmentManager) : androidx.fragment.app.FragmentStatePagerAdapter(fragmentManager) {
override fun getCount(): Int {
return NUM_ITEMS
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_viewpager)
viewPager.adapter = MapFragmentAdapter(this, supportFragmentManager)
}
override fun getItem(position: Int): androidx.fragment.app.Fragment? {
val options = MapboxMapOptions.createFromAttributes(context)
options.textureMode(true)
options.camera(
CameraPosition.Builder()
.zoom(3.0)
.target(
when (position) {
0 -> {
LatLng(34.920526, 102.634774)
}
1 -> {
LatLng(62.326440, 92.764913)
}
2 -> {
LatLng(-25.007786, 133.623852)
}
3 -> {
LatLng(62.326440, 92.764913)
}
else -> {
LatLng(34.920526, 102.634774)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
val currentPosition = viewPager.currentItem
val offscreenLimit = viewPager.offscreenPageLimit
for (i in currentPosition - offscreenLimit..currentPosition + offscreenLimit) {
if (i < 0 || i > viewPager.adapter?.count ?: 0) {
continue
}
)
.build())
val fragment = SupportMapFragment.newInstance(options)
fragment.getMapAsync(position)
return fragment
val mapFragment = viewPager.adapter?.instantiateItem(viewPager, i) as SupportMapFragment
mapFragment.getMapAsync(i)
}
}
override fun getPageTitle(position: Int): CharSequence? {
return "Page $position"
}
internal class MapFragmentAdapter(private val context: Context, fragmentManager: androidx.fragment.app.FragmentManager) : androidx.fragment.app.FragmentStatePagerAdapter(fragmentManager) {
companion object {
private const val NUM_ITEMS = 5
override fun getCount(): Int {
return NUM_ITEMS
}
override fun getItem(position: Int): androidx.fragment.app.Fragment? {
val options = MapboxMapOptions.createFromAttributes(context)
options.textureMode(true)
options.camera(
CameraPosition.Builder()
.zoom(3.0)
.target(
when (position) {
0 -> {
LatLng(34.920526, 102.634774)
}
1 -> {
LatLng(62.326440, 92.764913)
}
2 -> {
LatLng(-25.007786, 133.623852)
}
3 -> {
LatLng(62.326440, 92.764913)
}
else -> {
LatLng(34.920526, 102.634774)
}
}
)
.build()
)
val fragment = SupportMapFragment.newInstance(options)
fragment.getMapAsync(position)
return fragment
}
override fun getPageTitle(position: Int): CharSequence? {
return "Page $position"
}
companion object {
private const val NUM_ITEMS = 5
}
}
}
}
fun SupportMapFragment.getMapAsync(index: Int) {
this.getMapAsync {
it.setStyle(
when (index) {
0 -> Style.MAPBOX_STREETS
1 -> Style.DARK
2 -> Style.SATELLITE
3 -> Style.LIGHT
4 -> Style.TRAFFIC_NIGHT
else -> Style.MAPBOX_STREETS
}
)
}
}
this.getMapAsync {
it.setStyle(
when (index) {
0 -> Style.MAPBOX_STREETS
1 -> Style.DARK
2 -> Style.SATELLITE
3 -> Style.LIGHT
4 -> Style.TRAFFIC_NIGHT
else -> Style.MAPBOX_STREETS
}
)
}
}

View File

@@ -16,74 +16,74 @@ import timber.log.Timber
*/
class SnapshotActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mapboxMap: MapboxMap
private lateinit var mapboxMap: MapboxMap
private val idleListener = object : MapView.OnDidFinishRenderingFrameListener {
override fun onDidFinishRenderingFrame(fully: Boolean) {
if (fully) {
mapView.removeOnDidFinishRenderingFrameListener(this)
Logger.v(TAG, LOG_MESSAGE)
mapboxMap.snapshot { snapshot ->
imageView.setImageBitmap(snapshot)
mapView.addOnDidFinishRenderingFrameListener(this)
private val idleListener = object : MapView.OnDidFinishRenderingFrameListener {
override fun onDidFinishRenderingFrame(fully: Boolean) {
if (fully) {
mapView.removeOnDidFinishRenderingFrameListener(this)
Logger.v(TAG, LOG_MESSAGE)
mapboxMap.snapshot { snapshot ->
imageView.setImageBitmap(snapshot)
mapView.addOnDidFinishRenderingFrameListener(this)
}
}
}
}
}
}
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_snapshot)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync(this)
}
override fun onMapReady(map: MapboxMap) {
mapboxMap = map
mapboxMap.setStyle(Style.Builder().fromUri(Style.OUTDOORS)) { mapView.addOnDidFinishRenderingFrameListener(idleListener) }
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapboxMap.snapshot {
Timber.e("Regression test for https://github.com/mapbox/mapbox-gl-native/pull/11358")
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_snapshot)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync(this)
}
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onMapReady(map: MapboxMap) {
mapboxMap = map
mapboxMap.setStyle(Style.Builder().fromUri(Style.OUTDOORS)) { mapView.addOnDidFinishRenderingFrameListener(idleListener) }
}
public override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
public override fun onDestroy() {
super.onDestroy()
mapView.removeOnDidFinishRenderingFrameListener(idleListener)
mapView.onDestroy()
}
override fun onPause() {
super.onPause()
mapboxMap.snapshot {
Timber.e("Regression test for https://github.com/mapbox/mapbox-gl-native/pull/11358")
}
mapView.onPause()
}
companion object {
const val TAG = "Mbgl-SnapshotActivity"
const val LOG_MESSAGE = "OnSnapshot"
}
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
public override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
public override fun onDestroy() {
super.onDestroy()
mapView.removeOnDidFinishRenderingFrameListener(idleListener)
mapView.onDestroy()
}
companion object {
const val TAG = "Mbgl-SnapshotActivity"
const val LOG_MESSAGE = "OnSnapshot"
}
}

View File

@@ -23,154 +23,159 @@ import com.mapbox.mapboxsdk.testapp.R
import kotlinx.android.synthetic.main.activity_location_layer_fragment.*
class LocationFragmentActivity : AppCompatActivity() {
private lateinit var permissionsManager: PermissionsManager
private lateinit var permissionsManager: PermissionsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_location_layer_fragment)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_location_layer_fragment)
fab.setOnClickListener {
val fragment = supportFragmentManager.findFragmentByTag(EmptyFragment.TAG)
if (fragment == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.container, EmptyFragment.newInstance(), EmptyFragment.TAG)
.addToBackStack("transaction2")
.commit()
} else {
this.onBackPressed()
}
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
if (PermissionsManager.areLocationPermissionsGranted(this)) {
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.container, LocationFragment.newInstance(), LocationFragment.TAG)
.commit()
}
} else {
permissionsManager = PermissionsManager(object : PermissionsListener {
override fun onExplanationNeeded(permissionsToExplain: MutableList<String>?) {
Toast.makeText(this@LocationFragmentActivity, "You need to accept location permissions.",
Toast.LENGTH_SHORT).show()
}
override fun onPermissionResult(granted: Boolean) {
if (granted) {
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.container, LocationFragment.newInstance(), LocationFragment.TAG)
.commit()
fab.setOnClickListener {
val fragment = supportFragmentManager.findFragmentByTag(EmptyFragment.TAG)
if (fragment == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.container, EmptyFragment.newInstance(), EmptyFragment.TAG)
.addToBackStack("transaction2")
.commit()
} else {
this.onBackPressed()
}
} else {
finish()
}
}
})
permissionsManager.requestLocationPermissions(this)
}
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
if (PermissionsManager.areLocationPermissionsGranted(this)) {
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.container, LocationFragment.newInstance(), LocationFragment.TAG)
.commit()
}
} else {
permissionsManager = PermissionsManager(object : PermissionsListener {
override fun onExplanationNeeded(permissionsToExplain: MutableList<String>?) {
Toast.makeText(
this@LocationFragmentActivity,
"You need to accept location permissions.",
Toast.LENGTH_SHORT
).show()
}
class LocationFragment : androidx.fragment.app.Fragment(), LocationEngineCallback<LocationEngineResult> {
companion object {
const val TAG = "LFragment"
fun newInstance(): LocationFragment {
return LocationFragment()
}
}
private lateinit var mapView: MapView
private lateinit var mapboxMap: MapboxMap
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mapView = MapView(inflater.context)
return mapView
}
@SuppressLint("MissingPermission")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync {
mapboxMap = it
it.setStyle(Style.MAPBOX_STREETS) { style ->
val component = mapboxMap.locationComponent
component.activateLocationComponent(LocationComponentActivationOptions
.builder(activity!!, style)
.useDefaultLocationEngine(true)
.build())
component.isLocationComponentEnabled = true
component.locationEngine?.getLastLocation(this)
override fun onPermissionResult(granted: Boolean) {
if (granted) {
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.container, LocationFragment.newInstance(), LocationFragment.TAG)
.commit()
}
} else {
finish()
}
}
})
permissionsManager.requestLocationPermissions(this)
}
}
}
override fun onSuccess(result: LocationEngineResult?) {
if (!mapView.isDestroyed) mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(result?.lastLocation), 12.0))
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
override fun onFailure(exception: Exception) {
// noop
class LocationFragment : androidx.fragment.app.Fragment(), LocationEngineCallback<LocationEngineResult> {
companion object {
const val TAG = "LFragment"
fun newInstance(): LocationFragment {
return LocationFragment()
}
}
private lateinit var mapView: MapView
private lateinit var mapboxMap: MapboxMap
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mapView = MapView(inflater.context)
return mapView
}
@SuppressLint("MissingPermission")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync {
mapboxMap = it
it.setStyle(Style.MAPBOX_STREETS) { style ->
val component = mapboxMap.locationComponent
component.activateLocationComponent(
LocationComponentActivationOptions
.builder(activity!!, style)
.useDefaultLocationEngine(true)
.build()
)
component.isLocationComponentEnabled = true
component.locationEngine?.getLastLocation(this)
}
}
}
override fun onSuccess(result: LocationEngineResult?) {
if (!mapView.isDestroyed) mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(result?.lastLocation), 12.0))
}
override fun onFailure(exception: Exception) {
// noop
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroyView() {
super.onDestroyView()
mapView.onDestroy()
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
class EmptyFragment : androidx.fragment.app.Fragment() {
companion object {
const val TAG = "EmptyFragment"
fun newInstance(): EmptyFragment {
return EmptyFragment()
}
}
override fun onResume() {
super.onResume()
mapView.onResume()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val textView = TextView(inflater.context)
textView.text = "This is an empty Fragment"
return textView
}
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroyView() {
super.onDestroyView()
mapView.onDestroy()
}
}
class EmptyFragment : androidx.fragment.app.Fragment() {
companion object {
const val TAG = "EmptyFragment"
fun newInstance(): EmptyFragment {
return EmptyFragment()
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val textView = TextView(inflater.context)
textView.text = "This is an empty Fragment"
return textView
}
}
}
}

View File

@@ -21,137 +21,137 @@ import kotlinx.android.synthetic.main.activity_recyclerview.*
@SuppressLint("ClickableViewAccessibility")
open class GLSurfaceRecyclerViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recyclerview)
recyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
recyclerView.adapter = ItemAdapter(this, LayoutInflater.from(this))
}
override fun onLowMemory() {
super.onLowMemory()
// to release memory, we need to call MapView#onLowMemory
(recyclerView.adapter as ItemAdapter).onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
// to perform cleanup, we need to call MapView#onDestroy
(recyclerView.adapter as ItemAdapter).onDestroy()
}
open fun getMapItemLayoutId(): Int {
return R.layout.item_map_gl
}
class ItemAdapter(private val activity: GLSurfaceRecyclerViewActivity, private val inflater: LayoutInflater) : androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
private val items = listOf(
"one", "two", "three", MapItem(Style.MAPBOX_STREETS), "four", "five", MapItem(Style.DARK), "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
"nineteen", "twenty", "twenty-one"
)
private var mapHolders: MutableList<MapHolder> = mutableListOf()
companion object {
const val TYPE_MAP = 0
const val TYPE_TEXT = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recyclerview)
recyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
recyclerView.adapter = ItemAdapter(this, LayoutInflater.from(this))
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder {
return if (viewType == TYPE_MAP) {
val mapView = inflater.inflate(activity.getMapItemLayoutId(), parent, false) as MapView
val mapHolder = MapHolder(mapView)
mapHolders.add(mapHolder)
return mapHolder
} else {
TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView)
}
override fun onLowMemory() {
super.onLowMemory()
// to release memory, we need to call MapView#onLowMemory
(recyclerView.adapter as ItemAdapter).onLowMemory()
}
override fun onViewAttachedToWindow(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder) {
super.onViewAttachedToWindow(holder)
if (holder is MapHolder) {
val mapView = holder.mapView
mapView.isEnabled = false
mapView.onStart()
mapView.onResume()
}
override fun onDestroy() {
super.onDestroy()
// to perform cleanup, we need to call MapView#onDestroy
(recyclerView.adapter as ItemAdapter).onDestroy()
}
override fun onViewDetachedFromWindow(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder) {
super.onViewDetachedFromWindow(holder)
if (holder is MapHolder) {
val mapView = holder.mapView
mapView.onPause()
mapView.onStop()
}
open fun getMapItemLayoutId(): Int {
return R.layout.item_map_gl
}
override fun getItemCount(): Int {
return items.count()
}
class ItemAdapter(private val activity: GLSurfaceRecyclerViewActivity, private val inflater: LayoutInflater) : androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) {
if (holder is TextHolder) {
holder.bind(items[position] as String)
} else if (holder is MapHolder) {
holder.bind(items[position] as MapItem)
}
}
private val items = listOf(
"one", "two", "three", MapItem(Style.MAPBOX_STREETS), "four", "five", MapItem(Style.DARK), "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
"nineteen", "twenty", "twenty-one"
)
override fun getItemViewType(position: Int): Int {
return if (items[position] is MapItem) {
TYPE_MAP
} else {
TYPE_TEXT
}
}
private var mapHolders: MutableList<MapHolder> = mutableListOf()
fun onLowMemory() {
for (mapHolder in mapHolders) {
mapHolder.mapView.onLowMemory()
}
}
fun onDestroy() {
for (mapHolder in mapHolders) {
mapHolder.mapView.let {
it.onPause()
it.onStop()
it.onDestroy()
companion object {
const val TYPE_MAP = 0
const val TYPE_TEXT = 1
}
}
}
data class MapItem(val style: String)
class MapHolder(val mapView: MapView) : androidx.recyclerview.widget.RecyclerView.ViewHolder(mapView) {
init {
// unfortunately, if there are multiple maps hosted in one activity, state saving is not possible
mapView.onCreate(null)
mapView.setOnTouchListener { view, motionEvent ->
// Disallow the touch request for recyclerView scroll
view.parent.requestDisallowInterceptTouchEvent(true)
mapView.onTouchEvent(motionEvent)
true
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder {
return if (viewType == TYPE_MAP) {
val mapView = inflater.inflate(activity.getMapItemLayoutId(), parent, false) as MapView
val mapHolder = MapHolder(mapView)
mapHolders.add(mapHolder)
return mapHolder
} else {
TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView)
}
}
}
fun bind(mapItem: MapItem) {
mapView.getMapAsync { mapboxMap ->
mapboxMap.setStyle(mapItem.style) {
mapboxMap.snapshot { }
}
override fun onViewAttachedToWindow(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder) {
super.onViewAttachedToWindow(holder)
if (holder is MapHolder) {
val mapView = holder.mapView
mapView.isEnabled = false
mapView.onStart()
mapView.onResume()
}
}
}
}
class TextHolder(val textView: TextView) : androidx.recyclerview.widget.RecyclerView.ViewHolder(textView) {
fun bind(item: String) {
textView.text = item
}
override fun onViewDetachedFromWindow(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder) {
super.onViewDetachedFromWindow(holder)
if (holder is MapHolder) {
val mapView = holder.mapView
mapView.onPause()
mapView.onStop()
}
}
override fun getItemCount(): Int {
return items.count()
}
override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) {
if (holder is TextHolder) {
holder.bind(items[position] as String)
} else if (holder is MapHolder) {
holder.bind(items[position] as MapItem)
}
}
override fun getItemViewType(position: Int): Int {
return if (items[position] is MapItem) {
TYPE_MAP
} else {
TYPE_TEXT
}
}
fun onLowMemory() {
for (mapHolder in mapHolders) {
mapHolder.mapView.onLowMemory()
}
}
fun onDestroy() {
for (mapHolder in mapHolders) {
mapHolder.mapView.let {
it.onPause()
it.onStop()
it.onDestroy()
}
}
}
data class MapItem(val style: String)
class MapHolder(val mapView: MapView) : androidx.recyclerview.widget.RecyclerView.ViewHolder(mapView) {
init {
// unfortunately, if there are multiple maps hosted in one activity, state saving is not possible
mapView.onCreate(null)
mapView.setOnTouchListener { view, motionEvent ->
// Disallow the touch request for recyclerView scroll
view.parent.requestDisallowInterceptTouchEvent(true)
mapView.onTouchEvent(motionEvent)
true
}
}
fun bind(mapItem: MapItem) {
mapView.getMapAsync { mapboxMap ->
mapboxMap.setStyle(mapItem.style) {
mapboxMap.snapshot { }
}
}
}
}
class TextHolder(val textView: TextView) : androidx.recyclerview.widget.RecyclerView.ViewHolder(textView) {
fun bind(item: String) {
textView.text = item
}
}
}
}
}
}

View File

@@ -57,10 +57,10 @@ class OverlayMapActivity : AppCompatActivity() {
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
}
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
class OverlayView(context: Context) : View(context) {
@@ -77,11 +77,17 @@ class OverlayMapActivity : AppCompatActivity() {
paint.color = Color.BLACK
paint.strokeWidth = 1.0f
paint.style = Paint.Style.FILL_AND_STROKE
paint.shader = RadialGradient(width / 2.0f, height / 2.0f,
height / 3.0f, Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP)
paint.shader = RadialGradient(
width / 2.0f,
height / 2.0f,
height / 3.0f,
Color.TRANSPARENT,
Color.BLACK,
Shader.TileMode.CLAMP
)
}
it.drawRect(0.0f, 0.0f, width.toFloat(), height.toFloat(), paint)
}
}
}
}
}

View File

@@ -9,7 +9,7 @@ import com.mapbox.mapboxsdk.testapp.R
@SuppressLint("ClickableViewAccessibility")
class TextureRecyclerViewActivity : GLSurfaceRecyclerViewActivity() {
override fun getMapItemLayoutId(): Int {
return R.layout.item_map_texture
}
}
override fun getMapItemLayoutId(): Int {
return R.layout.item_map_texture
}
}

View File

@@ -17,164 +17,165 @@ import com.mapbox.mapboxsdk.offline.OfflineManager
import com.mapbox.mapboxsdk.offline.OfflineRegion
import com.mapbox.mapboxsdk.storage.FileSource
import com.mapbox.mapboxsdk.testapp.R
import java.io.File
import kotlinx.android.synthetic.main.activity_change_resources_cache_path.*
import java.io.File
class ChangeResourcesCachePathActivity : AppCompatActivity(),
AdapterView.OnItemClickListener,
FileSource.ResourcesCachePathChangeCallback {
class ChangeResourcesCachePathActivity :
AppCompatActivity(),
AdapterView.OnItemClickListener,
FileSource.ResourcesCachePathChangeCallback {
companion object {
private const val TAG = "Mbgl-ChangeResourcesCachePathActivity"
}
private lateinit var adapter: PathAdapter
private lateinit var offlineManager: OfflineManager
private val callback = PathChangeCallback(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_change_resources_cache_path)
adapter = PathAdapter(this, obtainExternalFilesPaths())
listView.adapter = adapter
listView.emptyView = empty
listView.onItemClickListener = this
offlineManager = OfflineManager.getInstance(this)
}
override fun onStart() {
super.onStart()
val path: String? = FileSource.getResourcesCachePath(this)
Toast.makeText(this, "Current path: $path", Toast.LENGTH_LONG).show()
}
override fun onDestroy() {
super.onDestroy()
callback.onActivityDestroy()
}
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
listView.onItemClickListener = null
val path: String = adapter.getItem(position) as String
FileSource.setResourcesCachePath(path, callback)
}
override fun onError(message: String) {
listView.onItemClickListener = this
Toast.makeText(this, "Error: $message", Toast.LENGTH_LONG).show()
}
override fun onSuccess(path: String) {
listView.onItemClickListener = this
Toast.makeText(this, "New path: $path", Toast.LENGTH_LONG).show()
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
override fun onList(offlineRegions: Array<out OfflineRegion>?) {
Logger.i(TAG, "Number of saved offline regions in the new path: ${offlineRegions?.size}")
}
override fun onError(error: String?) {
Logger.e(TAG, error)
}
})
}
private fun Context.obtainExternalFilesPaths(): List<String> {
val paths = ArrayList<String>()
paths.add(this.filesDir.absolutePath)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
paths.addAll(obtainExternalFilesPathsKitKat())
} else {
paths.addAll(obtainExternalFilesPathsLegacy())
companion object {
private const val TAG = "Mbgl-ChangeResourcesCachePathActivity"
}
paths.add("${File.separator}invalid${File.separator}cache${File.separator}path")
return paths
}
private fun Context.obtainExternalFilesPathsLegacy(): List<String> {
val postFix =
"${File.separator}Android${File.separator}data${File.separator}${this.packageName}${File.separator}files"
val paths = ArrayList<String>()
val externalStorage = System.getenv("EXTERNAL_STORAGE")
val secondaryStorage = System.getenv("SECONDARY_STORAGE")
if (externalStorage != null) {
paths.add(externalStorage + postFix)
private lateinit var adapter: PathAdapter
private lateinit var offlineManager: OfflineManager
private val callback = PathChangeCallback(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_change_resources_cache_path)
adapter = PathAdapter(this, obtainExternalFilesPaths())
listView.adapter = adapter
listView.emptyView = empty
listView.onItemClickListener = this
offlineManager = OfflineManager.getInstance(this)
}
if (secondaryStorage != null) {
val secPaths = secondaryStorage.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (path in secPaths) {
paths.add(path + postFix)
}
override fun onStart() {
super.onStart()
val path: String? = FileSource.getResourcesCachePath(this)
Toast.makeText(this, "Current path: $path", Toast.LENGTH_LONG).show()
}
return paths
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private fun Context.obtainExternalFilesPathsKitKat(): List<String> {
val paths = ArrayList<String>()
val extDirs = this.getExternalFilesDirs(null)
for (dir in extDirs) {
if (dir != null) {
paths.add(dir.absolutePath)
}
override fun onDestroy() {
super.onDestroy()
callback.onActivityDestroy()
}
return paths
}
private class PathChangeCallback(private var activity: ChangeResourcesCachePathActivity?) : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
activity?.onSuccess(path)
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
listView.onItemClickListener = null
val path: String = adapter.getItem(position) as String
FileSource.setResourcesCachePath(path, callback)
}
override fun onError(message: String) {
activity?.onError(message)
listView.onItemClickListener = this
Toast.makeText(this, "Error: $message", Toast.LENGTH_LONG).show()
}
fun onActivityDestroy() {
activity = null
}
}
override fun onSuccess(path: String) {
listView.onItemClickListener = this
Toast.makeText(this, "New path: $path", Toast.LENGTH_LONG).show()
class PathAdapter(private val context: Context, private val paths: List<String>) : BaseAdapter() {
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
override fun onList(offlineRegions: Array<out OfflineRegion>?) {
Logger.i(TAG, "Number of saved offline regions in the new path: ${offlineRegions?.size}")
}
override fun getItem(position: Int): Any {
return paths[position]
override fun onError(error: String?) {
Logger.e(TAG, error)
}
})
}
override fun getItemId(position: Int): Long {
return position.toLong()
private fun Context.obtainExternalFilesPaths(): List<String> {
val paths = ArrayList<String>()
paths.add(this.filesDir.absolutePath)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
paths.addAll(obtainExternalFilesPathsKitKat())
} else {
paths.addAll(obtainExternalFilesPathsLegacy())
}
paths.add("${File.separator}invalid${File.separator}cache${File.separator}path")
return paths
}
override fun getCount(): Int {
return paths.size
private fun Context.obtainExternalFilesPathsLegacy(): List<String> {
val postFix =
"${File.separator}Android${File.separator}data${File.separator}${this.packageName}${File.separator}files"
val paths = ArrayList<String>()
val externalStorage = System.getenv("EXTERNAL_STORAGE")
val secondaryStorage = System.getenv("SECONDARY_STORAGE")
if (externalStorage != null) {
paths.add(externalStorage + postFix)
}
if (secondaryStorage != null) {
val secPaths = secondaryStorage.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (path in secPaths) {
paths.add(path + postFix)
}
}
return paths
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val viewHolder: ViewHolder
val view: View
if (convertView == null) {
viewHolder = ViewHolder()
view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false)
viewHolder.textView = view.findViewById(android.R.id.text1)
view?.tag = viewHolder
} else {
view = convertView
viewHolder = view.tag as ViewHolder
}
viewHolder.textView?.text = paths[position]
return view
@TargetApi(Build.VERSION_CODES.KITKAT)
private fun Context.obtainExternalFilesPathsKitKat(): List<String> {
val paths = ArrayList<String>()
val extDirs = this.getExternalFilesDirs(null)
for (dir in extDirs) {
if (dir != null) {
paths.add(dir.absolutePath)
}
}
return paths
}
class ViewHolder {
var textView: TextView? = null
private class PathChangeCallback(private var activity: ChangeResourcesCachePathActivity?) : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
activity?.onSuccess(path)
}
override fun onError(message: String) {
activity?.onError(message)
}
fun onActivityDestroy() {
activity = null
}
}
}
}
class PathAdapter(private val context: Context, private val paths: List<String>) : BaseAdapter() {
override fun getItem(position: Int): Any {
return paths[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getCount(): Int {
return paths.size
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val viewHolder: ViewHolder
val view: View
if (convertView == null) {
viewHolder = ViewHolder()
view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false)
viewHolder.textView = view.findViewById(android.R.id.text1)
view?.tag = viewHolder
} else {
view = convertView
viewHolder = view.tag as ViewHolder
}
viewHolder.textView?.text = paths[position]
return view
}
class ViewHolder {
var textView: TextView? = null
}
}
}

View File

@@ -14,306 +14,313 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.offline.*
import com.mapbox.mapboxsdk.testapp.R
import java.util.*
import java.util.concurrent.TimeUnit
import kotlinx.android.synthetic.main.activity_region_download.*
import timber.log.Timber
import java.util.*
import java.util.concurrent.TimeUnit
/**
* Example showcasing how to download an offline region headless, allows to test pausing and resuming the download.
*/
class DownloadRegionActivity : AppCompatActivity(), OfflineRegion.OfflineRegionObserver {
companion object {
const val STATUS_UPDATE_TIMEOUT_MS = 10_000L
}
private val handler: Handler = Handler()
private lateinit var offlineManager: OfflineManager
private var offlineRegion: OfflineRegion? = null
private var downloading = false
private var previousCompletedResourceCount: Long = 0
private var previousUpdateTimestamp: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_region_download)
offlineManager = OfflineManager.getInstance(this)
offlineManager.setOfflineMapboxTileCountLimit(Long.MAX_VALUE)
initUi()
deleteOldOfflineRegions {
container.visibility = View.VISIBLE
fab.visibility = View.VISIBLE
}
}
override fun onDestroy() {
handler.removeCallbacksAndMessages(null)
offlineRegion?.setObserver(null)
super.onDestroy()
}
private fun createOfflineRegion() {
val latitudeNorth = editTextLatNorth.text.toString().toDouble()
val longitudeEast = editTextLonEast.text.toString().toDouble()
val latitudeSouth = editTextLatSouth.text.toString().toDouble()
val longitudeWest = editTextLonWest.text.toString().toDouble()
val styleUrl = spinnerStyleUrl.selectedItem as String
val maxZoom = seekbarMaxZoom.progress.toFloat()
val minZoom = seekbarMinZoom.progress.toFloat()
if (!validCoordinates(latitudeNorth, longitudeEast, latitudeSouth, longitudeWest)) {
Toast.makeText(this, "coordinates need to be in valid range", Toast.LENGTH_LONG).show()
return
companion object {
const val STATUS_UPDATE_TIMEOUT_MS = 10_000L
}
// create offline definition from data
val definition = OfflineTilePyramidRegionDefinition(
styleUrl,
LatLngBounds.Builder()
.include(LatLng(latitudeNorth, longitudeEast))
.include(LatLng(latitudeSouth, longitudeWest))
.build(),
minZoom.toDouble(),
maxZoom.toDouble(),
resources.displayMetrics.density
)
private val handler: Handler = Handler()
private lateinit var offlineManager: OfflineManager
private var offlineRegion: OfflineRegion? = null
private var downloading = false
private var previousCompletedResourceCount: Long = 0
private var previousUpdateTimestamp: Long = 0
logMessage("Creating offline region")
offlineManager.createOfflineRegion(definition, byteArrayOf(), object : OfflineManager.CreateOfflineRegionCallback {
override fun onCreate(region: OfflineRegion) {
logMessage("Region with id ${region.id} created")
offlineRegion = region
startDownload(region)
fab.visibility = View.VISIBLE
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_region_download)
override fun onError(error: String) {
logMessage("Failed to create offline region: $error")
}
})
}
offlineManager = OfflineManager.getInstance(this)
offlineManager.setOfflineMapboxTileCountLimit(Long.MAX_VALUE)
initUi()
private fun startDownload(region: OfflineRegion) {
downloading = true
fab.setImageResource(R.drawable.ic_pause_black_24dp)
logMessage("Downloading...")
region.setObserver(this)
region.setDownloadState(OfflineRegion.STATE_ACTIVE)
previousUpdateTimestamp = System.currentTimeMillis()
handler.postDelayed(object : Runnable {
override fun run() {
if (System.currentTimeMillis() > previousUpdateTimestamp + STATUS_UPDATE_TIMEOUT_MS) {
logMessage("FAILURE! No progress in ${TimeUnit.MILLISECONDS.toSeconds(STATUS_UPDATE_TIMEOUT_MS)} seconds")
} else {
handler.postDelayed(this, 1000)
deleteOldOfflineRegions {
container.visibility = View.VISIBLE
fab.visibility = View.VISIBLE
}
}
}, 1000)
}
private fun pauseDownload(region: OfflineRegion) {
downloading = false
fab.setImageResource(R.drawable.ic_play_arrow_black_24dp)
handler.removeCallbacksAndMessages(null)
region.setDownloadState(OfflineRegion.STATE_INACTIVE)
"Paused".let {
logMessage(it)
download_status.text = it
}
}
override fun onStatusChanged(status: OfflineRegionStatus) {
if (status.isComplete) {
"Completed".let {
logMessage("SUCCESS! $it")
download_status.text = it
}
fab.setImageResource(R.drawable.ic_play_arrow_black_24dp)
handler.removeCallbacksAndMessages(null)
offlineRegion?.setObserver(null)
offlineRegion?.setDownloadState(OfflineRegion.STATE_INACTIVE)
} else {
val statusText = "Downloaded ${status.completedResourceCount}/${status.requiredResourceCount}"
statusText.let {
logMessage(it)
download_status.text = it
}
if (status.completedResourceCount > status.requiredResourceCount &&
previousCompletedResourceCount <= status.requiredResourceCount
) {
logMessage("FAILURE! Completed > required")
}
}
previousCompletedResourceCount = status.completedResourceCount
previousUpdateTimestamp = System.currentTimeMillis()
}
override fun onDestroy() {
handler.removeCallbacksAndMessages(null)
offlineRegion?.setObserver(null)
super.onDestroy()
}
override fun onError(error: OfflineRegionError) {
logMessage("Error: $error")
}
private fun createOfflineRegion() {
val latitudeNorth = editTextLatNorth.text.toString().toDouble()
val longitudeEast = editTextLonEast.text.toString().toDouble()
val latitudeSouth = editTextLatSouth.text.toString().toDouble()
val longitudeWest = editTextLonWest.text.toString().toDouble()
val styleUrl = spinnerStyleUrl.selectedItem as String
val maxZoom = seekbarMaxZoom.progress.toFloat()
val minZoom = seekbarMinZoom.progress.toFloat()
override fun mapboxTileCountLimitExceeded(limit: Long) {
logMessage("Error: tile count limit exceeded")
}
if (!validCoordinates(latitudeNorth, longitudeEast, latitudeSouth, longitudeWest)) {
Toast.makeText(this, "coordinates need to be in valid range", Toast.LENGTH_LONG).show()
return
}
protected fun logMessage(message: String) {
Timber.d(message)
logView.append(message)
logView.append("\n")
}
// create offline definition from data
val definition = OfflineTilePyramidRegionDefinition(
styleUrl,
LatLngBounds.Builder()
.include(LatLng(latitudeNorth, longitudeEast))
.include(LatLng(latitudeSouth, longitudeWest))
.build(),
minZoom.toDouble(),
maxZoom.toDouble(),
resources.displayMetrics.density
)
fun deleteOldOfflineRegions(onCompleted: () -> Unit) {
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
override fun onList(offlineRegions: Array<out OfflineRegion>) {
val count = offlineRegions.size
var remainingCount = count
if (count > 0) {
logMessage("Deleting $count old region...")
offlineRegions.forEach {
it.delete(object : OfflineRegion.OfflineRegionDeleteCallback {
override fun onDelete() {
Timber.d("Deleted region with id ${it.id}")
onProcessed()
}
override fun onError(error: String) {
Timber.e("Failed to delete region: $error")
onProcessed()
}
private fun onProcessed() {
remainingCount--
if (remainingCount == 0) {
logMessage("Done deleting")
onCompleted()
logMessage("Creating offline region")
offlineManager.createOfflineRegion(
definition,
byteArrayOf(),
object : OfflineManager.CreateOfflineRegionCallback {
override fun onCreate(region: OfflineRegion) {
logMessage("Region with id ${region.id} created")
offlineRegion = region
startDownload(region)
fab.visibility = View.VISIBLE
}
}
})
}
override fun onError(error: String) {
logMessage("Failed to create offline region: $error")
}
}
)
}
private fun startDownload(region: OfflineRegion) {
downloading = true
fab.setImageResource(R.drawable.ic_pause_black_24dp)
logMessage("Downloading...")
region.setObserver(this)
region.setDownloadState(OfflineRegion.STATE_ACTIVE)
previousUpdateTimestamp = System.currentTimeMillis()
handler.postDelayed(
object : Runnable {
override fun run() {
if (System.currentTimeMillis() > previousUpdateTimestamp + STATUS_UPDATE_TIMEOUT_MS) {
logMessage("FAILURE! No progress in ${TimeUnit.MILLISECONDS.toSeconds(STATUS_UPDATE_TIMEOUT_MS)} seconds")
} else {
handler.postDelayed(this, 1000)
}
}
},
1000
)
}
private fun pauseDownload(region: OfflineRegion) {
downloading = false
fab.setImageResource(R.drawable.ic_play_arrow_black_24dp)
handler.removeCallbacksAndMessages(null)
region.setDownloadState(OfflineRegion.STATE_INACTIVE)
"Paused".let {
logMessage(it)
download_status.text = it
}
}
override fun onStatusChanged(status: OfflineRegionStatus) {
if (status.isComplete) {
"Completed".let {
logMessage("SUCCESS! $it")
download_status.text = it
}
fab.setImageResource(R.drawable.ic_play_arrow_black_24dp)
handler.removeCallbacksAndMessages(null)
offlineRegion?.setObserver(null)
offlineRegion?.setDownloadState(OfflineRegion.STATE_INACTIVE)
} else {
onCompleted()
val statusText = "Downloaded ${status.completedResourceCount}/${status.requiredResourceCount}"
statusText.let {
logMessage(it)
download_status.text = it
}
if (status.completedResourceCount > status.requiredResourceCount &&
previousCompletedResourceCount <= status.requiredResourceCount
) {
logMessage("FAILURE! Completed > required")
}
}
}
override fun onError(error: String) {
logMessage("Failed to list offline regions: $error")
onCompleted()
}
})
}
previousCompletedResourceCount = status.completedResourceCount
previousUpdateTimestamp = System.currentTimeMillis()
}
// ui
override fun onError(error: OfflineRegionError) {
logMessage("Error: $error")
}
private val logView: TextView by lazy {
findViewById<TextView>(R.id.log_text)
}
override fun mapboxTileCountLimitExceeded(limit: Long) {
logMessage("Error: tile count limit exceeded")
}
private fun initUi() {
initEditTexts()
initSeekbars()
initSpinner()
initZoomLevelTextviews()
initSeekbarListeners()
initFab()
}
protected fun logMessage(message: String) {
Timber.d(message)
logView.append(message)
logView.append("\n")
}
private fun initEditTexts() {
editTextLatNorth.setText("62.0")
editTextLonEast.setText("24.0")
editTextLatSouth.setText("60.0")
editTextLonWest.setText("22.5")
}
fun deleteOldOfflineRegions(onCompleted: () -> Unit) {
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
override fun onList(offlineRegions: Array<out OfflineRegion>) {
val count = offlineRegions.size
var remainingCount = count
if (count > 0) {
logMessage("Deleting $count old region...")
offlineRegions.forEach {
it.delete(object : OfflineRegion.OfflineRegionDeleteCallback {
override fun onDelete() {
Timber.d("Deleted region with id ${it.id}")
onProcessed()
}
private fun initSeekbars() {
val maxZoom = MapboxConstants.MAXIMUM_ZOOM.toInt()
seekbarMinZoom.max = maxZoom
seekbarMinZoom.progress = 1
seekbarMaxZoom.max = maxZoom
seekbarMaxZoom.progress = 15
}
override fun onError(error: String) {
Timber.e("Failed to delete region: $error")
onProcessed()
}
private fun initSpinner() {
val styles = ArrayList<String>()
styles.add(Style.MAPBOX_STREETS)
styles.add(Style.DARK)
styles.add(Style.LIGHT)
styles.add(Style.OUTDOORS)
val spinnerArrayAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, styles)
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinnerStyleUrl.adapter = spinnerArrayAdapter
}
private fun onProcessed() {
remainingCount--
if (remainingCount == 0) {
logMessage("Done deleting")
onCompleted()
}
}
})
}
} else {
onCompleted()
}
}
private fun initZoomLevelTextviews() {
textViewMaxText.text = String.format("Max zoom: %s", seekbarMaxZoom.progress)
textViewMinText.text = String.format("Min zoom: %s", seekbarMinZoom.progress)
}
override fun onError(error: String) {
logMessage("Failed to list offline regions: $error")
onCompleted()
}
})
}
private fun initFab() {
fab.setOnClickListener {
container.visibility = View.GONE
if (offlineRegion == null) {
fab.visibility = View.GONE
createOfflineRegion()
} else {
offlineRegion?.let {
if (downloading) {
pauseDownload(it)
} else {
startDownload(it)
}
// ui
private val logView: TextView by lazy {
findViewById<TextView>(R.id.log_text)
}
private fun initUi() {
initEditTexts()
initSeekbars()
initSpinner()
initZoomLevelTextviews()
initSeekbarListeners()
initFab()
}
private fun initEditTexts() {
editTextLatNorth.setText("62.0")
editTextLonEast.setText("24.0")
editTextLatSouth.setText("60.0")
editTextLonWest.setText("22.5")
}
private fun initSeekbars() {
val maxZoom = MapboxConstants.MAXIMUM_ZOOM.toInt()
seekbarMinZoom.max = maxZoom
seekbarMinZoom.progress = 1
seekbarMaxZoom.max = maxZoom
seekbarMaxZoom.progress = 15
}
private fun initSpinner() {
val styles = ArrayList<String>()
styles.add(Style.MAPBOX_STREETS)
styles.add(Style.DARK)
styles.add(Style.LIGHT)
styles.add(Style.OUTDOORS)
val spinnerArrayAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, styles)
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinnerStyleUrl.adapter = spinnerArrayAdapter
}
private fun initZoomLevelTextviews() {
textViewMaxText.text = String.format("Max zoom: %s", seekbarMaxZoom.progress)
textViewMinText.text = String.format("Min zoom: %s", seekbarMinZoom.progress)
}
private fun initFab() {
fab.setOnClickListener {
container.visibility = View.GONE
if (offlineRegion == null) {
fab.visibility = View.GONE
createOfflineRegion()
} else {
offlineRegion?.let {
if (downloading) {
pauseDownload(it)
} else {
startDownload(it)
}
}
}
}
}
}
}
private fun initSeekbarListeners() {
seekbarMaxZoom.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
textViewMaxText.text = String.format("Max zoom: %s", progress)
}
private fun initSeekbarListeners() {
seekbarMaxZoom.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
textViewMaxText.text = String.format("Max zoom: %s", progress)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
}
})
override fun onStopTrackingTouch(seekBar: SeekBar) {
}
})
seekbarMinZoom.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
textViewMinText.text = String.format("Min zoom: %s", progress)
}
seekbarMinZoom.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
textViewMinText.text = String.format("Min zoom: %s", progress)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
}
})
}
private fun validCoordinates(
latitudeNorth: Double,
longitudeEast: Double,
latitudeSouth: Double,
longitudeWest: Double
): Boolean {
if (latitudeNorth < -90 || latitudeNorth > 90) {
return false
} else if (longitudeEast < -180 || longitudeEast > 180) {
return false
} else if (latitudeSouth < -90 || latitudeSouth > 90) {
return false
} else if (longitudeWest < -180 || longitudeWest > 180) {
return false
override fun onStopTrackingTouch(seekBar: SeekBar) {
}
})
}
return true
}
}
private fun validCoordinates(
latitudeNorth: Double,
longitudeEast: Double,
latitudeSouth: Double,
longitudeWest: Double
): Boolean {
if (latitudeNorth < -90 || latitudeNorth > 90) {
return false
} else if (longitudeEast < -180 || longitudeEast > 180) {
return false
} else if (latitudeSouth < -90 || latitudeSouth > 90) {
return false
} else if (longitudeWest < -180 || longitudeWest > 180) {
return false
}
return true
}
}

View File

@@ -14,134 +14,139 @@ import com.mapbox.mapboxsdk.testapp.utils.FileUtils
import kotlinx.android.synthetic.main.activity_merge_offline_regions.*
class MergeOfflineRegionsActivity : AppCompatActivity() {
companion object {
private const val LOG_TAG = "Mbgl-MergeOfflineRegionsActivity"
private const val TEST_DB_FILE_NAME = "offline_test.db"
private const val TEST_STYLE = Style.SATELLITE
}
private val onFileCopiedListener = object : FileUtils.OnFileCopiedFromAssetsListener {
override fun onFileCopiedFromAssets() {
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("OnFileCopied."),
Toast.LENGTH_LONG).show()
mergeDb()
companion object {
private const val LOG_TAG = "Mbgl-MergeOfflineRegionsActivity"
private const val TEST_DB_FILE_NAME = "offline_test.db"
private const val TEST_STYLE = Style.SATELLITE
}
override fun onError() {
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("Error copying DB file."),
Toast.LENGTH_LONG).show()
}
}
private val onFileCopiedListener = object : FileUtils.OnFileCopiedFromAssetsListener {
override fun onFileCopiedFromAssets() {
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("OnFileCopied."),
Toast.LENGTH_LONG
).show()
mergeDb()
}
private val onRegionMergedListener = object : OfflineManager.MergeOfflineRegionsCallback {
override fun onMerge(offlineRegions: Array<OfflineRegion>) {
mapView.getMapAsync {
it.setStyle(Style.Builder().fromUri(TEST_STYLE))
}
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("Merged %d regions.", offlineRegions.size),
Toast.LENGTH_LONG).show()
override fun onError() {
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("Error copying DB file."),
Toast.LENGTH_LONG
).show()
}
}
override fun onError(error: String) {
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("Offline DB merge error."),
Toast.LENGTH_LONG).show()
Logger.e(LOG_TAG, error)
}
}
private val onRegionMergedListener = object : OfflineManager.MergeOfflineRegionsCallback {
override fun onMerge(offlineRegions: Array<OfflineRegion>) {
mapView.getMapAsync {
it.setStyle(Style.Builder().fromUri(TEST_STYLE))
}
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("Merged %d regions.", offlineRegions.size),
Toast.LENGTH_LONG
).show()
}
/**
* Since we expect from the results of the offline merge callback to interact with the hosting activity,
* we need to ensure that we are not interacting with a destroyed activity.
*/
private class MergeCallback(private var activityCallback: OfflineManager.MergeOfflineRegionsCallback?) : OfflineManager.MergeOfflineRegionsCallback {
override fun onMerge(offlineRegions: Array<out OfflineRegion>?) {
activityCallback?.onMerge(offlineRegions)
override fun onError(error: String) {
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("Offline DB merge error."),
Toast.LENGTH_LONG
).show()
Logger.e(LOG_TAG, error)
}
}
override fun onError(error: String?) {
activityCallback?.onError(error)
/**
* Since we expect from the results of the offline merge callback to interact with the hosting activity,
* we need to ensure that we are not interacting with a destroyed activity.
*/
private class MergeCallback(private var activityCallback: OfflineManager.MergeOfflineRegionsCallback?) : OfflineManager.MergeOfflineRegionsCallback {
override fun onMerge(offlineRegions: Array<out OfflineRegion>?) {
activityCallback?.onMerge(offlineRegions)
}
override fun onError(error: String?) {
activityCallback?.onError(error)
}
fun onActivityDestroy() {
activityCallback = null
}
}
fun onActivityDestroy() {
activityCallback = null
private val mergeCallback = MergeCallback(onRegionMergedListener)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_merge_offline_regions)
// forcing offline state
Mapbox.setConnected(false)
mapView.onCreate(savedInstanceState)
load_region_btn.setOnClickListener {
copyAsset()
}
mapView.getMapAsync {
it.isDebugActive = true
it.setStyle(Style.Builder().fromUri(TEST_STYLE))
}
}
}
private val mergeCallback = MergeCallback(onRegionMergedListener)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_merge_offline_regions)
// forcing offline state
Mapbox.setConnected(false)
mapView.onCreate(savedInstanceState)
load_region_btn.setOnClickListener {
copyAsset()
private fun copyAsset() {
// copy db asset to internal memory
FileUtils.CopyFileFromAssetsTask(this, onFileCopiedListener).execute(TEST_DB_FILE_NAME, FileSource.getResourcesCachePath(this))
}
mapView.getMapAsync {
it.isDebugActive = true
it.setStyle(Style.Builder().fromUri(TEST_STYLE))
private fun mergeDb() {
OfflineManager.getInstance(this).mergeOfflineRegions(
FileSource.getResourcesCachePath(this) + "/" + TEST_DB_FILE_NAME,
mergeCallback
)
}
}
private fun copyAsset() {
// copy db asset to internal memory
FileUtils.CopyFileFromAssetsTask(this, onFileCopiedListener).execute(TEST_DB_FILE_NAME, FileSource.getResourcesCachePath(this))
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
private fun mergeDb() {
OfflineManager.getInstance(this).mergeOfflineRegions(
FileSource.getResourcesCachePath(this) + "/" + TEST_DB_FILE_NAME, mergeCallback
)
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onDestroy() {
super.onDestroy()
mergeCallback.onActivityDestroy()
mapView.onDestroy()
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
// restoring connectivity state
Mapbox.setConnected(null)
}
override fun onDestroy() {
super.onDestroy()
mergeCallback.onActivityDestroy()
mapView.onDestroy()
// restoring connectivity state
Mapbox.setConnected(null)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
}

View File

@@ -13,65 +13,68 @@ import kotlinx.android.synthetic.main.activity_cache_management.*
*/
class CacheManagementActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_cache_management)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_cache_management)
val fileSource = OfflineManager.getInstance(this)
resetDatabaseButton.setOnClickListener {
fileSource.resetDatabase(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Reset database success")
val fileSource = OfflineManager.getInstance(this)
resetDatabaseButton.setOnClickListener {
fileSource.resetDatabase(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Reset database success")
}
override fun onError(message: String) {
showSnackbar("Reset database fail: $message")
}
})
}
override fun onError(message: String) {
showSnackbar("Reset database fail: $message")
invalidateAmbientCacheButton.setOnClickListener {
fileSource.invalidateAmbientCache(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Invalidate ambient cache success")
}
override fun onError(message: String) {
showSnackbar("Invalidate ambient cache fail: $message")
}
})
}
clearAmbientCacheButton.setOnClickListener {
fileSource.clearAmbientCache(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Clear ambient cache success")
}
override fun onError(message: String) {
showSnackbar("Clear ambient cache fail: $message")
}
})
}
setMaximumAmbientCacheSizeButton.setOnClickListener {
fileSource.setMaximumAmbientCacheSize(
5000000,
object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Set maximum ambient cache size success")
}
override fun onError(message: String) {
showSnackbar("Set maximum ambient cache size fail: $message")
}
}
)
}
})
}
invalidateAmbientCacheButton.setOnClickListener {
fileSource.invalidateAmbientCache(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Invalidate ambient cache success")
}
fun showSnackbar(message: String) {
// validate that all callbacks occur on main thread
assert(Looper.myLooper() == Looper.getMainLooper())
override fun onError(message: String) {
showSnackbar("Invalidate ambient cache fail: $message")
}
})
// show snackbar
Snackbar.make(container, message, Snackbar.LENGTH_SHORT).show()
}
clearAmbientCacheButton.setOnClickListener {
fileSource.clearAmbientCache(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Clear ambient cache success")
}
override fun onError(message: String) {
showSnackbar("Clear ambient cache fail: $message")
}
})
}
setMaximumAmbientCacheSizeButton.setOnClickListener {
fileSource.setMaximumAmbientCacheSize(5000000, object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Set maximum ambient cache size success")
}
override fun onError(message: String) {
showSnackbar("Set maximum ambient cache size fail: $message")
}
})
}
}
fun showSnackbar(message: String) {
// validate that all callbacks occur on main thread
assert(Looper.myLooper() == Looper.getMainLooper())
// show snackbar
Snackbar.make(container, message, Snackbar.LENGTH_SHORT).show()
}
}
}

View File

@@ -18,118 +18,119 @@ import com.mapbox.mapboxsdk.style.layers.LineLayer
import com.mapbox.mapboxsdk.style.layers.PropertyFactory
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
import com.mapbox.mapboxsdk.testapp.R
import java.util.*
import kotlinx.android.synthetic.main.activity_collection_update_on_style_change.*
import java.util.*
/**
* Test activity that verifies whether the GeoJsonSource transition over style changes can be smooth.
*/
class CollectionUpdateOnStyleChange : AppCompatActivity(), OnMapReadyCallback, Style.OnStyleLoaded {
private lateinit var mapboxMap: MapboxMap
private var currentStyleIndex: Int = 0
private lateinit var mapboxMap: MapboxMap
private var currentStyleIndex: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_collection_update_on_style_change)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync(this)
setupStyleChangeView()
Toast.makeText(
this,
"Make sure that the collection doesn't blink on style change",
Toast.LENGTH_LONG)
.show()
}
override fun onMapReady(map: MapboxMap) {
mapboxMap = map
mapboxMap.setStyle(Style.Builder().fromUri(STYLES[currentStyleIndex]), this)
}
override fun onStyleLoaded(style: Style) {
setupLayer(style)
}
private fun setupLayer(style: Style) {
val source = GeoJsonSource("source", featureCollection)
val lineLayer = LineLayer("layer", "source")
.withProperties(
PropertyFactory.lineColor(Color.RED),
PropertyFactory.lineWidth(10f)
)
style.addSource(source)
style.addLayer(lineLayer)
}
private fun setupStyleChangeView() {
val fabStyles = findViewById<FloatingActionButton>(R.id.fabStyles)
fabStyles.setOnClickListener {
currentStyleIndex++
if (currentStyleIndex == STYLES.size) {
currentStyleIndex = 0
}
mapboxMap.setStyle(Style.Builder().fromUri(STYLES[currentStyleIndex]), this)
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
companion object {
private val STYLES = arrayOf(Style.MAPBOX_STREETS, Style.OUTDOORS, Style.LIGHT, Style.DARK, Style.SATELLITE, Style.SATELLITE_STREETS, Style.TRAFFIC_DAY, Style.TRAFFIC_NIGHT)
private val featureCollection: FeatureCollection
init {
val bounds = LatLngBounds.from(60.0, 100.0, -60.0, -100.0)
val points = ArrayList<Point>()
for (i in 0 until 1000) {
val latLng = getLatLngInBounds(bounds)
points.add(Point.fromLngLat(latLng.longitude, latLng.latitude))
}
featureCollection = FeatureCollection.fromFeature(Feature.fromGeometry(LineString.fromLngLats(points)))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_collection_update_on_style_change)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync(this)
setupStyleChangeView()
Toast.makeText(
this,
"Make sure that the collection doesn't blink on style change",
Toast.LENGTH_LONG
)
.show()
}
private fun getLatLngInBounds(bounds: LatLngBounds): LatLng {
val generator = Random()
val randomLat = bounds.latSouth + generator.nextDouble() * (bounds.latNorth - bounds.latSouth)
val randomLon = bounds.lonWest + generator.nextDouble() * (bounds.lonEast - bounds.lonWest)
return LatLng(randomLat, randomLon)
override fun onMapReady(map: MapboxMap) {
mapboxMap = map
mapboxMap.setStyle(Style.Builder().fromUri(STYLES[currentStyleIndex]), this)
}
}
}
override fun onStyleLoaded(style: Style) {
setupLayer(style)
}
private fun setupLayer(style: Style) {
val source = GeoJsonSource("source", featureCollection)
val lineLayer = LineLayer("layer", "source")
.withProperties(
PropertyFactory.lineColor(Color.RED),
PropertyFactory.lineWidth(10f)
)
style.addSource(source)
style.addLayer(lineLayer)
}
private fun setupStyleChangeView() {
val fabStyles = findViewById<FloatingActionButton>(R.id.fabStyles)
fabStyles.setOnClickListener {
currentStyleIndex++
if (currentStyleIndex == STYLES.size) {
currentStyleIndex = 0
}
mapboxMap.setStyle(Style.Builder().fromUri(STYLES[currentStyleIndex]), this)
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
companion object {
private val STYLES = arrayOf(Style.MAPBOX_STREETS, Style.OUTDOORS, Style.LIGHT, Style.DARK, Style.SATELLITE, Style.SATELLITE_STREETS, Style.TRAFFIC_DAY, Style.TRAFFIC_NIGHT)
private val featureCollection: FeatureCollection
init {
val bounds = LatLngBounds.from(60.0, 100.0, -60.0, -100.0)
val points = ArrayList<Point>()
for (i in 0 until 1000) {
val latLng = getLatLngInBounds(bounds)
points.add(Point.fromLngLat(latLng.longitude, latLng.latitude))
}
featureCollection = FeatureCollection.fromFeature(Feature.fromGeometry(LineString.fromLngLats(points)))
}
private fun getLatLngInBounds(bounds: LatLngBounds): LatLng {
val generator = Random()
val randomLat = bounds.latSouth + generator.nextDouble() * (bounds.latNorth - bounds.latSouth)
val randomLon = bounds.lonWest + generator.nextDouble() * (bounds.lonEast - bounds.lonWest)
return LatLng(randomLat, randomLon)
}
}
}

View File

@@ -26,104 +26,109 @@ import kotlinx.android.synthetic.main.activity_physical_circle.*
*/
class DistanceExpressionActivity : AppCompatActivity() {
private lateinit var mapboxMap: MapboxMap
private lateinit var mapboxMap: MapboxMap
private val lat = 37.78794572301525
private val lon = -122.40752220153807
private val lat = 37.78794572301525
private val lon = -122.40752220153807
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_within_expression)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_within_expression)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
mapboxMap = map
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
mapboxMap = map
// Setup camera position above Georgetown
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(lat, lon))
.zoom(16.0)
.build()
setupStyle()
// Setup camera position above Georgetown
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(lat, lon))
.zoom(16.0)
.build()
setupStyle()
}
}
}
private fun setupStyle() {
val center = Point.fromLngLat(lon, lat)
val circle = TurfTransformation.circle(center, 150.0, TurfConstants.UNIT_METRES)
// Setup style with additional layers,
// using Style.MAPBOX_STREETS as a base style
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withSources(
GeoJsonSource(
POINT_ID, Point.fromLngLat(lon, lat)
),
GeoJsonSource(CIRCLE_ID, circle)
)
.withLayerBelow(
FillLayer(CIRCLE_ID, CIRCLE_ID)
.withProperties(
fillOpacity(0.5f),
fillColor(Color.parseColor("#3bb2d0"))
), "poi-label"
)
) { style ->
// Show only POI labels inside circle radius using distance expression
val symbolLayer = style.getLayer("poi-label") as SymbolLayer
symbolLayer.setFilter(lt(
distance(
Point.fromLngLat(lon, lat)
), 150)
)
private fun setupStyle() {
val center = Point.fromLngLat(lon, lat)
val circle = TurfTransformation.circle(center, 150.0, TurfConstants.UNIT_METRES)
// Setup style with additional layers,
// using Style.MAPBOX_STREETS as a base style
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withSources(
GeoJsonSource(
POINT_ID,
Point.fromLngLat(lon, lat)
),
GeoJsonSource(CIRCLE_ID, circle)
)
.withLayerBelow(
FillLayer(CIRCLE_ID, CIRCLE_ID)
.withProperties(
fillOpacity(0.5f),
fillColor(Color.parseColor("#3bb2d0"))
),
"poi-label"
)
) { style ->
// Show only POI labels inside circle radius using distance expression
val symbolLayer = style.getLayer("poi-label") as SymbolLayer
symbolLayer.setFilter(
lt(
distance(
Point.fromLngLat(lon, lat)
),
150
)
)
// Hide other types of labels to highlight POI labels
(style.getLayer("road-label") as SymbolLayer).setProperties(visibility(NONE))
(style.getLayer("transit-label") as SymbolLayer).setProperties(visibility(NONE))
(style.getLayer("road-number-shield") as SymbolLayer).setProperties(visibility(NONE))
// Hide other types of labels to highlight POI labels
(style.getLayer("road-label") as SymbolLayer).setProperties(visibility(NONE))
(style.getLayer("transit-label") as SymbolLayer).setProperties(visibility(NONE))
(style.getLayer("road-number-shield") as SymbolLayer).setProperties(visibility(NONE))
}
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
override fun onStart() {
super.onStart()
mapView.onStart()
}
}
companion object {
const val POINT_ID = "point"
const val CIRCLE_ID = "circle"
}
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
companion object {
const val POINT_ID = "point"
const val CIRCLE_ID = "circle"
}
}

View File

@@ -28,305 +28,320 @@ import kotlinx.android.synthetic.main.activity_draggable_marker.*
* An Activity that showcases how to make symbols draggable.
*/
class DraggableMarkerActivity : AppCompatActivity() {
companion object {
private const val sourceId = "source_draggable"
private const val layerId = "layer_draggable"
private const val markerImageId = "marker_icon_draggable"
companion object {
private const val sourceId = "source_draggable"
private const val layerId = "layer_draggable"
private const val markerImageId = "marker_icon_draggable"
private var latestId: Long = 0
fun generateMarkerId(): String {
if (latestId == Long.MAX_VALUE) {
throw RuntimeException("You've added too many markers.")
}
return latestId++.toString()
}
}
private val actionBarHeight: Int by lazy {
supportActionBar?.height ?: 0
}
// View property is required for activity sanity tests
// we perform reflection on this requires using findViewById
private lateinit var mapView: MapView
private lateinit var mapboxMap: MapboxMap
private val featureCollection = FeatureCollection.fromFeatures(mutableListOf())
private val source = GeoJsonSource(sourceId, featureCollection)
private val layer = SymbolLayer(layerId, sourceId)
.withProperties(
iconImage(markerImageId),
iconAllowOverlap(true),
iconIgnorePlacement(true))
private var draggableSymbolsManager: DraggableSymbolsManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_draggable_marker)
mapView = findViewById(R.id.mapView)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { mapboxMap ->
this.mapboxMap = mapboxMap
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withImage(markerImageId, IconFactory.getInstance(this).defaultMarker().bitmap)
.withSource(source)
.withLayer(layer)
)
// Add initial markers
addMarker(LatLng(52.407210, 16.924324))
addMarker(LatLng(41.382679, 2.181555))
addMarker(LatLng(51.514886, -0.112589))
// Initial camera position
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
LatLng(45.0, 8.0), 3.0
))
mapboxMap.addOnMapClickListener {
// Adding a marker on map click
val features = mapboxMap.queryRenderedSymbols(it, layerId)
if (features.isEmpty()) {
addMarker(it)
} else {
// Displaying marker info on marker click
Snackbar.make(
mapView,
"Marker's position: %.4f, %.4f".format(it.latitude, it.longitude),
Snackbar.LENGTH_LONG)
.show()
}
false
}
draggableSymbolsManager = DraggableSymbolsManager(
mapView, mapboxMap, featureCollection, source, layerId, actionBarHeight, 0)
// Adding symbol drag listeners
draggableSymbolsManager?.addOnSymbolDragListener(object : DraggableSymbolsManager.OnSymbolDragListener {
override fun onSymbolDragStarted(id: String) {
draggedMarkerPositionTv.visibility = View.VISIBLE
Snackbar.make(
mapView,
"Marker drag started (%s)".format(id),
Snackbar.LENGTH_SHORT)
.show()
}
override fun onSymbolDrag(id: String) {
val point = featureCollection.features()?.find {
it.id() == id
}?.geometry() as Point
draggedMarkerPositionTv.text = "Dragged marker's position: %.4f, %.4f".format(point.latitude(), point.longitude())
}
override fun onSymbolDragFinished(id: String) {
draggedMarkerPositionTv.visibility = View.GONE
Snackbar.make(
mapView,
"Marker drag finished (%s)".format(id),
Snackbar.LENGTH_SHORT)
.show()
}
})
}
}
private fun addMarker(latLng: LatLng) {
featureCollection.features()?.add(
Feature.fromGeometry(Point.fromLngLat(latLng.longitude, latLng.latitude), null, generateMarkerId()))
source.setGeoJson(featureCollection)
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
// Dispatching parent's touch events to the manager
draggableSymbolsManager?.onParentTouchEvent(ev)
return super.dispatchTouchEvent(ev)
}
/**
* A manager, that allows dragging symbols after they are long clicked.
* Since this manager lives outside of the Maps SDK, we need to intercept parent's motion events
* and pass them with [DraggableSymbolsManager.onParentTouchEvent].
* If we were to try and overwrite [AppCompatActivity.onTouchEvent], those events would've been
* consumed by the map.
*
* We also need to setup a [DraggableSymbolsManager.androidGesturesManager],
* because after disabling map's gestures and starting the drag process
* we still need to listen for move gesture events which map won't be able to provide anymore.
*
* @param mapView the mapView
* @param mapboxMap the mapboxMap
* @param symbolsCollection the collection that contains all the symbols that we want to be draggable
* @param symbolsSource the source that contains the [symbolsCollection]
* @param symbolsLayerId the ID of the layer that the symbols are displayed on
* @param touchAreaShiftX X-axis padding that is applied to the parent's window motion event,
* as that window can be bigger than the [mapView].
* @param touchAreaShiftY Y-axis padding that is applied to the parent's window motion event,
* as that window can be bigger than the [mapView].
* @param touchAreaMaxX maximum value of X-axis motion event
* @param touchAreaMaxY maximum value of Y-axis motion event
*/
class DraggableSymbolsManager(
mapView: MapView,
private val mapboxMap: MapboxMap,
private val symbolsCollection: FeatureCollection,
private val symbolsSource: GeoJsonSource,
private val symbolsLayerId: String,
private val touchAreaShiftY: Int = 0,
private val touchAreaShiftX: Int = 0,
private val touchAreaMaxX: Int = mapView.width,
private val touchAreaMaxY: Int = mapView.height
) {
private val androidGesturesManager: AndroidGesturesManager = AndroidGesturesManager(mapView.context, false)
private var draggedSymbolId: String? = null
private val onSymbolDragListeners: MutableList<OnSymbolDragListener> = mutableListOf<OnSymbolDragListener>()
init {
mapboxMap.addOnMapLongClickListener {
// Starting the drag process on long click
draggedSymbolId = mapboxMap.queryRenderedSymbols(it, symbolsLayerId).firstOrNull()?.id()?.also { id ->
mapboxMap.uiSettings.setAllGesturesEnabled(false)
mapboxMap.gesturesManager.moveGestureDetector.interrupt()
notifyOnSymbolDragListeners {
onSymbolDragStarted(id)
}
}
false
}
androidGesturesManager.setMoveGestureListener(MyMoveGestureListener())
}
inner class MyMoveGestureListener : MoveGestureDetector.OnMoveGestureListener {
override fun onMoveBegin(detector: MoveGestureDetector): Boolean {
return true
}
override fun onMove(detector: MoveGestureDetector, distanceX: Float, distanceY: Float): Boolean {
if (detector.pointersCount > 1) {
// Stopping the drag when we don't work with a simple, on-pointer move anymore
stopDragging()
return true
}
// Updating symbol's position
draggedSymbolId?.also { draggedSymbolId ->
val moveObject = detector.getMoveObject(0)
val point = PointF(moveObject.currentX - touchAreaShiftX, moveObject.currentY - touchAreaShiftY)
if (point.x < 0 || point.y < 0 || point.x > touchAreaMaxX || point.y > touchAreaMaxY) {
stopDragging()
}
val latLng = mapboxMap.projection.fromScreenLocation(point)
symbolsCollection.features()?.indexOfFirst {
it.id() == draggedSymbolId
}?.also { index ->
symbolsCollection.features()?.get(index)?.also { oldFeature ->
val properties = oldFeature.properties()
val newFeature = Feature.fromGeometry(
Point.fromLngLat(latLng.longitude, latLng.latitude),
properties,
draggedSymbolId
)
symbolsCollection.features()?.set(index, newFeature)
symbolsSource.setGeoJson(symbolsCollection)
notifyOnSymbolDragListeners {
onSymbolDrag(draggedSymbolId)
}
return true
private var latestId: Long = 0
fun generateMarkerId(): String {
if (latestId == Long.MAX_VALUE) {
throw RuntimeException("You've added too many markers.")
}
}
return latestId++.toString()
}
}
private val actionBarHeight: Int by lazy {
supportActionBar?.height ?: 0
}
// View property is required for activity sanity tests
// we perform reflection on this requires using findViewById
private lateinit var mapView: MapView
private lateinit var mapboxMap: MapboxMap
private val featureCollection = FeatureCollection.fromFeatures(mutableListOf())
private val source = GeoJsonSource(sourceId, featureCollection)
private val layer = SymbolLayer(layerId, sourceId)
.withProperties(
iconImage(markerImageId),
iconAllowOverlap(true),
iconIgnorePlacement(true)
)
private var draggableSymbolsManager: DraggableSymbolsManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_draggable_marker)
mapView = findViewById(R.id.mapView)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { mapboxMap ->
this.mapboxMap = mapboxMap
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withImage(markerImageId, IconFactory.getInstance(this).defaultMarker().bitmap)
.withSource(source)
.withLayer(layer)
)
// Add initial markers
addMarker(LatLng(52.407210, 16.924324))
addMarker(LatLng(41.382679, 2.181555))
addMarker(LatLng(51.514886, -0.112589))
// Initial camera position
mapboxMap.moveCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(45.0, 8.0),
3.0
)
)
mapboxMap.addOnMapClickListener {
// Adding a marker on map click
val features = mapboxMap.queryRenderedSymbols(it, layerId)
if (features.isEmpty()) {
addMarker(it)
} else {
// Displaying marker info on marker click
Snackbar.make(
mapView,
"Marker's position: %.4f, %.4f".format(it.latitude, it.longitude),
Snackbar.LENGTH_LONG
)
.show()
}
false
}
draggableSymbolsManager = DraggableSymbolsManager(
mapView,
mapboxMap,
featureCollection,
source,
layerId,
actionBarHeight,
0
)
// Adding symbol drag listeners
draggableSymbolsManager?.addOnSymbolDragListener(object : DraggableSymbolsManager.OnSymbolDragListener {
override fun onSymbolDragStarted(id: String) {
draggedMarkerPositionTv.visibility = View.VISIBLE
Snackbar.make(
mapView,
"Marker drag started (%s)".format(id),
Snackbar.LENGTH_SHORT
)
.show()
}
override fun onSymbolDrag(id: String) {
val point = featureCollection.features()?.find {
it.id() == id
}?.geometry() as Point
draggedMarkerPositionTv.text = "Dragged marker's position: %.4f, %.4f".format(point.latitude(), point.longitude())
}
override fun onSymbolDragFinished(id: String) {
draggedMarkerPositionTv.visibility = View.GONE
Snackbar.make(
mapView,
"Marker drag finished (%s)".format(id),
Snackbar.LENGTH_SHORT
)
.show()
}
})
}
}
private fun addMarker(latLng: LatLng) {
featureCollection.features()?.add(
Feature.fromGeometry(Point.fromLngLat(latLng.longitude, latLng.latitude), null, generateMarkerId())
)
source.setGeoJson(featureCollection)
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
// Dispatching parent's touch events to the manager
draggableSymbolsManager?.onParentTouchEvent(ev)
return super.dispatchTouchEvent(ev)
}
/**
* A manager, that allows dragging symbols after they are long clicked.
* Since this manager lives outside of the Maps SDK, we need to intercept parent's motion events
* and pass them with [DraggableSymbolsManager.onParentTouchEvent].
* If we were to try and overwrite [AppCompatActivity.onTouchEvent], those events would've been
* consumed by the map.
*
* We also need to setup a [DraggableSymbolsManager.androidGesturesManager],
* because after disabling map's gestures and starting the drag process
* we still need to listen for move gesture events which map won't be able to provide anymore.
*
* @param mapView the mapView
* @param mapboxMap the mapboxMap
* @param symbolsCollection the collection that contains all the symbols that we want to be draggable
* @param symbolsSource the source that contains the [symbolsCollection]
* @param symbolsLayerId the ID of the layer that the symbols are displayed on
* @param touchAreaShiftX X-axis padding that is applied to the parent's window motion event,
* as that window can be bigger than the [mapView].
* @param touchAreaShiftY Y-axis padding that is applied to the parent's window motion event,
* as that window can be bigger than the [mapView].
* @param touchAreaMaxX maximum value of X-axis motion event
* @param touchAreaMaxY maximum value of Y-axis motion event
*/
class DraggableSymbolsManager(
mapView: MapView,
private val mapboxMap: MapboxMap,
private val symbolsCollection: FeatureCollection,
private val symbolsSource: GeoJsonSource,
private val symbolsLayerId: String,
private val touchAreaShiftY: Int = 0,
private val touchAreaShiftX: Int = 0,
private val touchAreaMaxX: Int = mapView.width,
private val touchAreaMaxY: Int = mapView.height
) {
private val androidGesturesManager: AndroidGesturesManager = AndroidGesturesManager(mapView.context, false)
private var draggedSymbolId: String? = null
private val onSymbolDragListeners: MutableList<OnSymbolDragListener> = mutableListOf<OnSymbolDragListener>()
init {
mapboxMap.addOnMapLongClickListener {
// Starting the drag process on long click
draggedSymbolId = mapboxMap.queryRenderedSymbols(it, symbolsLayerId).firstOrNull()?.id()?.also { id ->
mapboxMap.uiSettings.setAllGesturesEnabled(false)
mapboxMap.gesturesManager.moveGestureDetector.interrupt()
notifyOnSymbolDragListeners {
onSymbolDragStarted(id)
}
}
false
}
androidGesturesManager.setMoveGestureListener(MyMoveGestureListener())
}
return false
}
inner class MyMoveGestureListener : MoveGestureDetector.OnMoveGestureListener {
override fun onMoveBegin(detector: MoveGestureDetector): Boolean {
return true
}
override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) {
// Stopping the drag when move ends
stopDragging()
}
}
override fun onMove(detector: MoveGestureDetector, distanceX: Float, distanceY: Float): Boolean {
if (detector.pointersCount > 1) {
// Stopping the drag when we don't work with a simple, on-pointer move anymore
stopDragging()
return true
}
private fun stopDragging() {
mapboxMap.uiSettings.setAllGesturesEnabled(true)
draggedSymbolId?.let {
notifyOnSymbolDragListeners {
onSymbolDragFinished(it)
// Updating symbol's position
draggedSymbolId?.also { draggedSymbolId ->
val moveObject = detector.getMoveObject(0)
val point = PointF(moveObject.currentX - touchAreaShiftX, moveObject.currentY - touchAreaShiftY)
if (point.x < 0 || point.y < 0 || point.x > touchAreaMaxX || point.y > touchAreaMaxY) {
stopDragging()
}
val latLng = mapboxMap.projection.fromScreenLocation(point)
symbolsCollection.features()?.indexOfFirst {
it.id() == draggedSymbolId
}?.also { index ->
symbolsCollection.features()?.get(index)?.also { oldFeature ->
val properties = oldFeature.properties()
val newFeature = Feature.fromGeometry(
Point.fromLngLat(latLng.longitude, latLng.latitude),
properties,
draggedSymbolId
)
symbolsCollection.features()?.set(index, newFeature)
symbolsSource.setGeoJson(symbolsCollection)
notifyOnSymbolDragListeners {
onSymbolDrag(draggedSymbolId)
}
return true
}
}
}
return false
}
override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) {
// Stopping the drag when move ends
stopDragging()
}
}
private fun stopDragging() {
mapboxMap.uiSettings.setAllGesturesEnabled(true)
draggedSymbolId?.let {
notifyOnSymbolDragListeners {
onSymbolDragFinished(it)
}
}
draggedSymbolId = null
}
fun onParentTouchEvent(ev: MotionEvent?) {
androidGesturesManager.onTouchEvent(ev)
}
private fun notifyOnSymbolDragListeners(action: OnSymbolDragListener.() -> Unit) {
onSymbolDragListeners.forEach(action)
}
fun addOnSymbolDragListener(listener: OnSymbolDragListener) {
onSymbolDragListeners.add(listener)
}
fun removeOnSymbolDragListener(listener: OnSymbolDragListener) {
onSymbolDragListeners.remove(listener)
}
interface OnSymbolDragListener {
fun onSymbolDragStarted(id: String)
fun onSymbolDrag(id: String)
fun onSymbolDragFinished(id: String)
}
}
draggedSymbolId = null
}
fun onParentTouchEvent(ev: MotionEvent?) {
androidGesturesManager.onTouchEvent(ev)
override fun onStart() {
super.onStart()
mapView.onStart()
}
private fun notifyOnSymbolDragListeners(action: OnSymbolDragListener.() -> Unit) {
onSymbolDragListeners.forEach(action)
override fun onResume() {
super.onResume()
mapView.onResume()
}
fun addOnSymbolDragListener(listener: OnSymbolDragListener) {
onSymbolDragListeners.add(listener)
override fun onPause() {
super.onPause()
mapView.onPause()
}
fun removeOnSymbolDragListener(listener: OnSymbolDragListener) {
onSymbolDragListeners.remove(listener)
override fun onStop() {
super.onStop()
mapView.onStop()
}
interface OnSymbolDragListener {
fun onSymbolDragStarted(id: String)
fun onSymbolDrag(id: String)
fun onSymbolDragFinished(id: String)
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
}
}
private fun MapboxMap.queryRenderedSymbols(latLng: LatLng, layerId: String): List<Feature> {
return this.queryRenderedFeatures(this.projection.toScreenLocation(latLng), layerId)
}
return this.queryRenderedFeatures(this.projection.toScreenLocation(latLng), layerId)
}

View File

@@ -12,74 +12,74 @@ import com.mapbox.mapboxsdk.style.layers.PropertyFactory.*
import com.mapbox.mapboxsdk.style.layers.SymbolLayer
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
import com.mapbox.mapboxsdk.testapp.R
import java.net.URI
import kotlinx.android.synthetic.main.activity_map_simple.*
import java.net.URI
/**
* Activity showcasing how to load symbols on a map without a Style URI or Style JSON.
*/
class NoStyleActivity : AppCompatActivity() {
private val imageIcon: Drawable by lazy {
ResourcesCompat.getDrawable(resources, R.drawable.ic_add_white, theme)!!
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_map_simple)
mapView.getMapAsync { map ->
map.moveCamera(CameraUpdateFactory.newLatLngZoom(cameraTarget, cameraZoom))
map.setStyle(
Style.Builder()
.withImage(imageId, imageIcon)
.withSource(GeoJsonSource(sourceId, URI("asset://points-sf.geojson")))
.withLayer(SymbolLayer(layerId, sourceId).withProperties(iconImage(imageId)))
)
private val imageIcon: Drawable by lazy {
ResourcesCompat.getDrawable(resources, R.drawable.ic_add_white, theme)!!
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_map_simple)
mapView.getMapAsync { map ->
map.moveCamera(CameraUpdateFactory.newLatLngZoom(cameraTarget, cameraZoom))
map.setStyle(
Style.Builder()
.withImage(imageId, imageIcon)
.withSource(GeoJsonSource(sourceId, URI("asset://points-sf.geojson")))
.withLayer(SymbolLayer(layerId, sourceId).withProperties(iconImage(imageId)))
)
}
}
}
companion object {
const val layerId = "custom-layer-id"
const val sourceId = "custom-source-id"
const val imageId = "image-id"
const val cameraZoom = 10.0
val cameraTarget = LatLng(37.758912, -122.442578)
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
companion object {
const val layerId = "custom-layer-id"
const val sourceId = "custom-source-id"
const val imageId = "image-id"
const val cameraZoom = 10.0
val cameraTarget = LatLng(37.758912, -122.442578)
}
}

View File

@@ -30,248 +30,254 @@ import kotlinx.android.synthetic.main.activity_snapshot.*
*/
class MapSnapshotterWithinExpression : AppCompatActivity() {
private lateinit var mapboxMap: MapboxMap
private lateinit var snapshotter: MapSnapshotter
private var snapshotInProgress = false
private lateinit var mapboxMap: MapboxMap
private lateinit var snapshotter: MapSnapshotter
private var snapshotInProgress = false
private val cameraListener = object : MapView.OnCameraDidChangeListener {
override fun onCameraDidChange(animated: Boolean) {
if (!snapshotInProgress) {
snapshotInProgress = true
snapshotter.setCameraPosition(mapboxMap.cameraPosition)
snapshotter.start {
imageView.setImageBitmap(it.bitmap)
snapshotInProgress = false
private val cameraListener = object : MapView.OnCameraDidChangeListener {
override fun onCameraDidChange(animated: Boolean) {
if (!snapshotInProgress) {
snapshotInProgress = true
snapshotter.setCameraPosition(mapboxMap.cameraPosition)
snapshotter.start {
imageView.setImageBitmap(it.bitmap)
snapshotInProgress = false
}
}
}
}
}
}
private val snapshotterObserver = object : MapSnapshotter.Observer {
override fun onStyleImageMissing(imageName: String?) {
}
override fun onDidFinishLoadingStyle() {
// Show only POI labels inside geometry using within expression
(snapshotter.getLayer("poi-label") as SymbolLayer).setFilter(
within(
bufferLineStringGeometry()
)
)
// Hide other types of labels to highlight POI labels
(snapshotter.getLayer("road-label") as SymbolLayer).setProperties(visibility(NONE))
(snapshotter.getLayer("transit-label") as SymbolLayer).setProperties(visibility(NONE))
(snapshotter.getLayer("road-number-shield") as SymbolLayer).setProperties(visibility(NONE))
private val snapshotterObserver = object : MapSnapshotter.Observer {
override fun onStyleImageMissing(imageName: String?) {
}
override fun onDidFinishLoadingStyle() {
// Show only POI labels inside geometry using within expression
(snapshotter.getLayer("poi-label") as SymbolLayer).setFilter(
within(
bufferLineStringGeometry()
)
)
// Hide other types of labels to highlight POI labels
(snapshotter.getLayer("road-label") as SymbolLayer).setProperties(visibility(NONE))
(snapshotter.getLayer("transit-label") as SymbolLayer).setProperties(visibility(NONE))
(snapshotter.getLayer("road-number-shield") as SymbolLayer).setProperties(visibility(NONE))
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_mapsnapshotter_within_expression)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_mapsnapshotter_within_expression)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
mapboxMap = map
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
mapboxMap = map
// Setup camera position above Georgetown
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(38.90628988399711, -77.06574689337494))
.zoom(15.5)
.build()
// Wait for the map to become idle before manipulating the style and camera of the map
mapView.addOnDidBecomeIdleListener(object : MapView.OnDidBecomeIdleListener {
override fun onDidBecomeIdle() {
mapboxMap.easeCamera(
CameraUpdateFactory.newCameraPosition(
CameraPosition.Builder()
.zoom(16.0)
.target(LatLng(38.905156245642814, -77.06535338052844))
.bearing(80.68015859462369)
.tilt(55.0)
// Setup camera position above Georgetown
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(38.90628988399711, -77.06574689337494))
.zoom(15.5)
.build()
), 1000
)
mapView.removeOnDidBecomeIdleListener(this)
// Wait for the map to become idle before manipulating the style and camera of the map
mapView.addOnDidBecomeIdleListener(object : MapView.OnDidBecomeIdleListener {
override fun onDidBecomeIdle() {
mapboxMap.easeCamera(
CameraUpdateFactory.newCameraPosition(
CameraPosition.Builder()
.zoom(16.0)
.target(LatLng(38.905156245642814, -77.06535338052844))
.bearing(80.68015859462369)
.tilt(55.0)
.build()
),
1000
)
mapView.removeOnDidBecomeIdleListener(this)
}
})
// Load mapbox streets and add lines and circles
setupStyle()
}
})
// Load mapbox streets and add lines and circles
setupStyle()
}
}
private fun setupStyle() {
// Assume the route is represented by an array of coordinates.
val coordinates = listOf<Point>(
Point.fromLngLat(
-77.06866264343262,
38.90506061276737
),
Point.fromLngLat(
-77.06283688545227,
38.905194197410545
),
Point.fromLngLat(
-77.06285834312439,
38.906429843444094
),
Point.fromLngLat(
-77.0630407333374,
38.90680554236621
)
)
// Setup style with additional layers,
// using Style.MAPBOX_STREETS as a base style
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
) {
mapView.addOnCameraDidChangeListener(cameraListener)
}
val options = MapSnapshotter.Options(imageView.measuredWidth / 2, imageView.measuredHeight / 2)
.withCameraPosition(mapboxMap.cameraPosition)
.withPixelRatio(2.0f)
.withStyleBuilder(Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withSources(
GeoJsonSource(
POINT_ID, LineString.fromLngLats(coordinates)
),
GeoJsonSource(
FILL_ID,
FeatureCollection.fromFeature(Feature.fromGeometry(bufferLineStringGeometry())),
GeoJsonOptions().withBuffer(0).withTolerance(0.0f)
)
private fun setupStyle() {
// Assume the route is represented by an array of coordinates.
val coordinates = listOf<Point>(
Point.fromLngLat(
-77.06866264343262,
38.90506061276737
),
Point.fromLngLat(
-77.06283688545227,
38.905194197410545
),
Point.fromLngLat(
-77.06285834312439,
38.906429843444094
),
Point.fromLngLat(
-77.0630407333374,
38.90680554236621
)
)
.withLayerBelow(
LineLayer(LINE_ID, POINT_ID)
.withProperties(lineWidth(7.5f), lineColor(Color.LTGRAY)),
"poi-label"
)
.withLayerBelow(
CircleLayer(POINT_ID, POINT_ID)
.withProperties(
circleRadius(7.5f),
circleColor(Color.DKGRAY),
circleOpacity(0.75f)
), "poi-label"
).withLayerBelow(
FillLayer(FILL_ID, FILL_ID)
.withProperties(
fillOpacity(0.12f),
fillColor(Color.YELLOW)
), LINE_ID
))
snapshotter = MapSnapshotter(this, options)
snapshotter.setObserver(snapshotterObserver)
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
// Setup style with additional layers,
// using Style.MAPBOX_STREETS as a base style
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
) {
mapView.addOnCameraDidChangeListener(cameraListener)
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
val options = MapSnapshotter.Options(imageView.measuredWidth / 2, imageView.measuredHeight / 2)
.withCameraPosition(mapboxMap.cameraPosition)
.withPixelRatio(2.0f)
.withStyleBuilder(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withSources(
GeoJsonSource(
POINT_ID,
LineString.fromLngLats(coordinates)
),
GeoJsonSource(
FILL_ID,
FeatureCollection.fromFeature(Feature.fromGeometry(bufferLineStringGeometry())),
GeoJsonOptions().withBuffer(0).withTolerance(0.0f)
)
)
.withLayerBelow(
LineLayer(LINE_ID, POINT_ID)
.withProperties(lineWidth(7.5f), lineColor(Color.LTGRAY)),
"poi-label"
)
.withLayerBelow(
CircleLayer(POINT_ID, POINT_ID)
.withProperties(
circleRadius(7.5f),
circleColor(Color.DKGRAY),
circleOpacity(0.75f)
),
"poi-label"
).withLayerBelow(
FillLayer(FILL_ID, FILL_ID)
.withProperties(
fillOpacity(0.12f),
fillColor(Color.YELLOW)
),
LINE_ID
)
)
snapshotter = MapSnapshotter(this, options)
snapshotter.setObserver(snapshotterObserver)
}
}
private fun bufferLineStringGeometry(): Polygon {
// TODO replace static data by Turf#Buffer: mapbox-java/issues/987
return FeatureCollection.fromJson(
"""
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-77.06867337226866,
38.90467655551809
],
[
-77.06233263015747,
38.90479344272695
],
[
-77.06234335899353,
38.906463238984344
],
[
-77.06290125846863,
38.907206285691615
],
[
-77.06364154815674,
38.90684728656818
],
[
-77.06326603889465,
38.90637140121084
],
[
-77.06321239471436,
38.905561553883246
],
[
-77.0691454410553,
38.905436318935635
],
[
-77.06912398338318,
38.90466820642439
],
[
-77.06867337226866,
38.90467655551809
]
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
private fun bufferLineStringGeometry(): Polygon {
// TODO replace static data by Turf#Buffer: mapbox-java/issues/987
return FeatureCollection.fromJson(
"""
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-77.06867337226866,
38.90467655551809
],
[
-77.06233263015747,
38.90479344272695
],
[
-77.06234335899353,
38.906463238984344
],
[
-77.06290125846863,
38.907206285691615
],
[
-77.06364154815674,
38.90684728656818
],
[
-77.06326603889465,
38.90637140121084
],
[
-77.06321239471436,
38.905561553883246
],
[
-77.0691454410553,
38.905436318935635
],
[
-77.06912398338318,
38.90466820642439
],
[
-77.06867337226866,
38.90467655551809
]
]
]
}
}
]
]
}
}
]
}
""".trimIndent()
).features()!![0].geometry() as Polygon
}
""".trimIndent()
).features()!![0].geometry() as Polygon
}
companion object {
const val POINT_ID = "point"
const val FILL_ID = "fill"
const val LINE_ID = "line"
}
}
companion object {
const val POINT_ID = "point"
const val FILL_ID = "fill"
const val LINE_ID = "line"
}
}

View File

@@ -22,105 +22,124 @@ import kotlinx.android.synthetic.main.activity_physical_circle.*
*/
class PhysicalUnitCircleActivity : AppCompatActivity(), SeekBar.OnSeekBarChangeListener {
companion object {
const val LAYER_ID = "circle-id"
const val SOURCE_ID = "circle-id"
const val LATITUDE = 22.928207
const val LONGITUDE = 15.0155543
const val ZOOM = 10.0
}
private lateinit var source: GeoJsonSource
private var steps: Int = 10
private var radius: Double = 9000.0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_physical_circle)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { mapboxMap ->
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(LATITUDE, LONGITUDE))
.zoom(ZOOM)
.build()
source = GeoJsonSource(SOURCE_ID, TurfTransformation.circle(
Point.fromLngLat(LONGITUDE, LATITUDE), 9000.0, 10, "meters")
)
stepsBar.setOnSeekBarChangeListener(this)
radiusBar.setOnSeekBarChangeListener(this)
mapboxMap.setStyle(Style.Builder()
.fromUri(Style.SATELLITE_STREETS)
.withLayer(FillLayer(LAYER_ID, SOURCE_ID).withProperties(fillColor(interpolate(
exponential(0.5f), zoom(),
stop(8, color(Color.RED)),
stop(12, color(Color.BLUE)),
stop(16, color(Color.GREEN))
))))
.withSource(source)
)
companion object {
const val LAYER_ID = "circle-id"
const val SOURCE_ID = "circle-id"
const val LATITUDE = 22.928207
const val LONGITUDE = 15.0155543
const val ZOOM = 10.0
}
}
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
seekBar?.let {
if (it.id == stepsBar.id) {
steps = progress
} else {
radius = progress.toDouble()
}
private lateinit var source: GeoJsonSource
private var steps: Int = 10
private var radius: Double = 9000.0
source.setGeoJson(TurfTransformation.circle(
Point.fromLngLat(LONGITUDE, LATITUDE), radius, steps, "meters")
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_physical_circle)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { mapboxMap ->
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(LATITUDE, LONGITUDE))
.zoom(ZOOM)
.build()
source = GeoJsonSource(
SOURCE_ID,
TurfTransformation.circle(
Point.fromLngLat(LONGITUDE, LATITUDE),
9000.0,
10,
"meters"
)
)
stepsBar.setOnSeekBarChangeListener(this)
radiusBar.setOnSeekBarChangeListener(this)
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.SATELLITE_STREETS)
.withLayer(
FillLayer(LAYER_ID, SOURCE_ID).withProperties(
fillColor(
interpolate(
exponential(0.5f),
zoom(),
stop(8, color(Color.RED)),
stop(12, color(Color.BLUE)),
stop(16, color(Color.GREEN))
)
)
)
)
.withSource(source)
)
}
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
// no-op
}
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
seekBar?.let {
if (it.id == stepsBar.id) {
steps = progress
} else {
radius = progress.toDouble()
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
// no-op
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
source.setGeoJson(
TurfTransformation.circle(
Point.fromLngLat(LONGITUDE, LATITUDE),
radius,
steps,
"meters"
)
)
}
}
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
// no-op
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
// no-op
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
}

View File

@@ -29,240 +29,244 @@ import kotlinx.android.synthetic.main.activity_physical_circle.*
*/
class WithinExpressionActivity : AppCompatActivity() {
private lateinit var mapboxMap: MapboxMap
private val handler: Handler = Handler()
private val runnable: Runnable = Runnable {
optimizeStyle()
}
private lateinit var mapboxMap: MapboxMap
private val handler: Handler = Handler()
private val runnable: Runnable = Runnable {
optimizeStyle()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_within_expression)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_within_expression)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
mapboxMap = map
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
mapboxMap = map
// Setup camera position above Georgetown
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(38.90628988399711, -77.06574689337494))
.zoom(15.5)
.build()
// Setup camera position above Georgetown
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(38.90628988399711, -77.06574689337494))
.zoom(15.5)
.build()
// Wait for the map to become idle before manipulating the style and camera of the map
mapView.addOnDidBecomeIdleListener(object : MapView.OnDidBecomeIdleListener {
override fun onDidBecomeIdle() {
handler.postDelayed(runnable, 2500)
mapView.removeOnDidBecomeIdleListener(this)
// Wait for the map to become idle before manipulating the style and camera of the map
mapView.addOnDidBecomeIdleListener(object : MapView.OnDidBecomeIdleListener {
override fun onDidBecomeIdle() {
handler.postDelayed(runnable, 2500)
mapView.removeOnDidBecomeIdleListener(this)
}
})
// Load mapbox streets and add lines and circles
setupStyle()
}
})
// Load mapbox streets and add lines and circles
setupStyle()
}
}
private fun setupStyle() {
// Assume the route is represented by an array of coordinates.
val coordinates = listOf<Point>(
Point.fromLngLat(
-77.06866264343262,
38.90506061276737
),
Point.fromLngLat(
-77.06283688545227,
38.905194197410545
),
Point.fromLngLat(
-77.06285834312439,
38.906429843444094
),
Point.fromLngLat(
-77.0630407333374,
38.90680554236621
)
)
// Convert to a LineString
val routeLineString = LineString.fromLngLats(coordinates)
// Create buffer around linestring
val bufferedRouteGeometry = bufferLineStringGeometry(routeLineString)
// Setup style with additional layers,
// using Style.MAPBOX_STREETS as a base style
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withSources(
GeoJsonSource(
POINT_ID, LineString.fromLngLats(coordinates)
),
GeoJsonSource(
FILL_ID,
FeatureCollection.fromFeature(Feature.fromGeometry(bufferedRouteGeometry)),
GeoJsonOptions().withBuffer(0).withTolerance(0.0f)
)
private fun setupStyle() {
// Assume the route is represented by an array of coordinates.
val coordinates = listOf<Point>(
Point.fromLngLat(
-77.06866264343262,
38.90506061276737
),
Point.fromLngLat(
-77.06283688545227,
38.905194197410545
),
Point.fromLngLat(
-77.06285834312439,
38.906429843444094
),
Point.fromLngLat(
-77.0630407333374,
38.90680554236621
)
)
.withLayerBelow(
LineLayer(LINE_ID, POINT_ID)
.withProperties(lineWidth(7.5f), lineColor(Color.LTGRAY)),
"poi-label"
// Convert to a LineString
val routeLineString = LineString.fromLngLats(coordinates)
// Create buffer around linestring
val bufferedRouteGeometry = bufferLineStringGeometry(routeLineString)
// Setup style with additional layers,
// using Style.MAPBOX_STREETS as a base style
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withSources(
GeoJsonSource(
POINT_ID,
LineString.fromLngLats(coordinates)
),
GeoJsonSource(
FILL_ID,
FeatureCollection.fromFeature(Feature.fromGeometry(bufferedRouteGeometry)),
GeoJsonOptions().withBuffer(0).withTolerance(0.0f)
)
)
.withLayerBelow(
LineLayer(LINE_ID, POINT_ID)
.withProperties(lineWidth(7.5f), lineColor(Color.LTGRAY)),
"poi-label"
)
.withLayerBelow(
CircleLayer(POINT_ID, POINT_ID)
.withProperties(
circleRadius(7.5f),
circleColor(Color.DKGRAY),
circleOpacity(0.75f)
),
"poi-label"
)
)
.withLayerBelow(
CircleLayer(POINT_ID, POINT_ID)
.withProperties(
circleRadius(7.5f),
circleColor(Color.DKGRAY),
circleOpacity(0.75f)
), "poi-label"
)
)
}
private fun optimizeStyle() {
val style = mapboxMap.style!!
// Add fill layer to represent buffered LineString
mapboxMap.style!!.addLayerBelow(
FillLayer(FILL_ID, FILL_ID)
.withProperties(
fillOpacity(0.12f),
fillColor(Color.YELLOW)
), LINE_ID
)
// Move to a new camera position
mapboxMap.easeCamera(
CameraUpdateFactory.newCameraPosition(
CameraPosition.Builder()
.zoom(16.0)
.target(LatLng(38.905156245642814, -77.06535338052844))
.bearing(80.68015859462369)
.tilt(55.0)
.build()
), 1750
)
// Show only POI labels inside geometry using within expression
val symbolLayer = style.getLayer("poi-label") as SymbolLayer
symbolLayer.setFilter(
within(
bufferLineStringGeometry()
)
)
// Hide other types of labels to highlight POI labels
(style.getLayer("road-label") as SymbolLayer).setProperties(visibility(NONE))
(style.getLayer("transit-label") as SymbolLayer).setProperties(visibility(NONE))
(style.getLayer("road-number-shield") as SymbolLayer).setProperties(visibility(NONE))
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacks(runnable)
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
private fun bufferLineStringGeometry(lineString: LineString? = null): Polygon {
// TODO replace static data by Turf#Buffer: mapbox-java/issues/987
return FeatureCollection.fromJson(
"""
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-77.06867337226866,
38.90467655551809
],
[
-77.06233263015747,
38.90479344272695
],
[
-77.06234335899353,
38.906463238984344
],
[
-77.06290125846863,
38.907206285691615
],
[
-77.06364154815674,
38.90684728656818
],
[
-77.06326603889465,
38.90637140121084
],
[
-77.06321239471436,
38.905561553883246
],
[
-77.0691454410553,
38.905436318935635
],
[
-77.06912398338318,
38.90466820642439
],
[
-77.06867337226866,
38.90467655551809
]
private fun optimizeStyle() {
val style = mapboxMap.style!!
// Add fill layer to represent buffered LineString
mapboxMap.style!!.addLayerBelow(
FillLayer(FILL_ID, FILL_ID)
.withProperties(
fillOpacity(0.12f),
fillColor(Color.YELLOW)
),
LINE_ID
)
// Move to a new camera position
mapboxMap.easeCamera(
CameraUpdateFactory.newCameraPosition(
CameraPosition.Builder()
.zoom(16.0)
.target(LatLng(38.905156245642814, -77.06535338052844))
.bearing(80.68015859462369)
.tilt(55.0)
.build()
),
1750
)
// Show only POI labels inside geometry using within expression
val symbolLayer = style.getLayer("poi-label") as SymbolLayer
symbolLayer.setFilter(
within(
bufferLineStringGeometry()
)
)
// Hide other types of labels to highlight POI labels
(style.getLayer("road-label") as SymbolLayer).setProperties(visibility(NONE))
(style.getLayer("transit-label") as SymbolLayer).setProperties(visibility(NONE))
(style.getLayer("road-number-shield") as SymbolLayer).setProperties(visibility(NONE))
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacks(runnable)
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
private fun bufferLineStringGeometry(lineString: LineString? = null): Polygon {
// TODO replace static data by Turf#Buffer: mapbox-java/issues/987
return FeatureCollection.fromJson(
"""
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-77.06867337226866,
38.90467655551809
],
[
-77.06233263015747,
38.90479344272695
],
[
-77.06234335899353,
38.906463238984344
],
[
-77.06290125846863,
38.907206285691615
],
[
-77.06364154815674,
38.90684728656818
],
[
-77.06326603889465,
38.90637140121084
],
[
-77.06321239471436,
38.905561553883246
],
[
-77.0691454410553,
38.905436318935635
],
[
-77.06912398338318,
38.90466820642439
],
[
-77.06867337226866,
38.90467655551809
]
]
]
}
}
]
]
}
}
]
}
""".trimIndent()
).features()!![0].geometry() as Polygon
}
""".trimIndent()
).features()!![0].geometry() as Polygon
}
companion object {
const val POINT_ID = "point"
const val FILL_ID = "fill"
const val LINE_ID = "line"
}
}
companion object {
const val POINT_ID = "point"
const val FILL_ID = "fill"
const val LINE_ID = "line"
}
}

View File

@@ -8,57 +8,57 @@ import java.lang.ref.WeakReference
class FileUtils {
/**
* Task that copies a file from the assets directory to a provided directory.
* The asset's name is going to be kept in the new directory.
*/
class CopyFileFromAssetsTask(context: Context, listener: OnFileCopiedFromAssetsListener) : AsyncTask<String, Void, Boolean>() {
private val contextWeakReference: WeakReference<Context> = WeakReference(context)
private val listenerWeakReference: WeakReference<OnFileCopiedFromAssetsListener> = WeakReference(listener)
/**
* Task that copies a file from the assets directory to a provided directory.
* The asset's name is going to be kept in the new directory.
*/
class CopyFileFromAssetsTask(context: Context, listener: OnFileCopiedFromAssetsListener) : AsyncTask<String, Void, Boolean>() {
private val contextWeakReference: WeakReference<Context> = WeakReference(context)
private val listenerWeakReference: WeakReference<OnFileCopiedFromAssetsListener> = WeakReference(listener)
override fun doInBackground(vararg strings: String): Boolean? {
val assetName = strings[0]
val destinationPath = strings[1]
contextWeakReference.get()?.let {
try {
copyAsset(it, assetName, destinationPath)
} catch (ex: Exception) {
return false
override fun doInBackground(vararg strings: String): Boolean? {
val assetName = strings[0]
val destinationPath = strings[1]
contextWeakReference.get()?.let {
try {
copyAsset(it, assetName, destinationPath)
} catch (ex: Exception) {
return false
}
}
return true
}
}
return true
override fun onCancelled() {
listenerWeakReference.get()?.onError()
}
override fun onPostExecute(result: Boolean) {
if (result) {
listenerWeakReference.get()?.onFileCopiedFromAssets()
} else {
listenerWeakReference.get()?.onError()
}
}
private fun copyAsset(context: Context, assetName: String, destinationPath: String) {
val bufferSize = 1024
val assetManager = context.assets
val inputStream = assetManager.open(assetName)
val outputStream = FileOutputStream(File(destinationPath, assetName))
try {
inputStream.copyTo(outputStream, bufferSize)
} finally {
inputStream.close()
outputStream.flush()
outputStream.close()
}
}
}
override fun onCancelled() {
listenerWeakReference.get()?.onError()
interface OnFileCopiedFromAssetsListener {
fun onFileCopiedFromAssets()
fun onError()
}
override fun onPostExecute(result: Boolean) {
if (result) {
listenerWeakReference.get()?.onFileCopiedFromAssets()
} else {
listenerWeakReference.get()?.onError()
}
}
private fun copyAsset(context: Context, assetName: String, destinationPath: String) {
val bufferSize = 1024
val assetManager = context.assets
val inputStream = assetManager.open(assetName)
val outputStream = FileOutputStream(File(destinationPath, assetName))
try {
inputStream.copyTo(outputStream, bufferSize)
} finally {
inputStream.close()
outputStream.flush()
outputStream.close()
}
}
}
interface OnFileCopiedFromAssetsListener {
fun onFileCopiedFromAssets()
fun onError()
}
}
}

View File

@@ -37,7 +37,7 @@ ext {
gms : '16.0.0',
jacoco : '0.8.5',
appcenter : '1.4',
ktlint : '0.34.0',
ktlint : '0.40.0',
commonsIO : '2.6',
mapboxSdkVersions: '1.0.1'
]

View File

@@ -16,7 +16,7 @@ task ktlint(type: JavaExec, group: "verification") {
description = "Check Kotlin code style."
classpath = configurations.ktlint
main = "com.pinterest.ktlint.Main"
args "src/**/*.kt"
args "--disabled_rules=no-wildcard-imports", "src/**/*.kt"
}
task ktlintFormat(type: JavaExec, group: "formatting") {