diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java index d9ae215dd..5cb1f37df 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java @@ -8,6 +8,7 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.location.modes.RenderMode; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.utils.BitmapUtils; import com.mapbox.mapboxsdk.utils.ColorUtils; @@ -26,26 +27,30 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { private Style style; private final LayerSourceProvider layerSourceProvider; - private LocationIndicatorLayer layer; + private Layer layer; @Nullable - private LatLng latLng; + private LatLng lastLatLng; + private double lastBearing = 0; + private float lastAccuracy = 0; - IndicatorLocationLayerRenderer(Style style, - LayerSourceProvider layerSourceProvider) { - this.style = style; + IndicatorLocationLayerRenderer(LayerSourceProvider layerSourceProvider) { this.layerSourceProvider = layerSourceProvider; } @Override public void initializeComponents(Style style) { this.style = style; + layer = layerSourceProvider.generateLocationComponentLayer(); + if (lastLatLng != null) { + setLatLng(lastLatLng); + } + setLayerBearing(lastBearing); + setAccuracyRadius(lastAccuracy); } @Override public void addLayers(LocationComponentPositionManager positionManager) { - layer = layerSourceProvider.generateLocationComponentLayer(); - setLayerLocation(latLng); positionManager.addLayerToMap(layer); } @@ -106,6 +111,7 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { layer.setProperties( LocationPropertyFactory.accuracyRadius(accuracy) ); + lastAccuracy = accuracy; } @Override @@ -160,20 +166,19 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { layer.setProperties(LocationPropertyFactory.visibility(visible ? VISIBLE : NONE)); } - private void setLayerLocation(@Nullable LatLng latLng) { - this.latLng = latLng; - if (latLng != null) { - Double[] values = new Double[] {latLng.getLatitude(), latLng.getLongitude(), 0d}; - layer.setProperties( - LocationPropertyFactory.location(values) - ); - } + private void setLayerLocation(LatLng latLng) { + Double[] values = new Double[] {latLng.getLatitude(), latLng.getLongitude(), 0d}; + layer.setProperties( + LocationPropertyFactory.location(values) + ); + lastLatLng = latLng; } private void setLayerBearing(double bearing) { layer.setProperties( LocationPropertyFactory.bearing(bearing) ); + lastBearing = bearing; } private void setImages(@RenderMode.Mode int renderMode, boolean isStale) { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java index d33206f10..3626f42db 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java @@ -117,7 +117,16 @@ class LayerSourceProvider { return new HashSet<>(); } - LocationIndicatorLayer generateLocationComponentLayer() { + LocationLayerRenderer getSymbolLocationLayerRenderer(LayerFeatureProvider featureProvider, + boolean isStale) { + return new SymbolLocationLayerRenderer(this, featureProvider, isStale); + } + + LocationLayerRenderer getIndicatorLocationLayerRenderer() { + return new IndicatorLocationLayerRenderer(this); + } + + Layer generateLocationComponentLayer() { LocationIndicatorLayer layer = new LocationIndicatorLayer(FOREGROUND_LAYER); layer.setProperties( LocationPropertyFactory.perspectiveCompensation(0.9f), diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index 733dbb259..bbb60289d 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -141,7 +141,7 @@ public final class LocationComponent { private boolean isComponentInitialized; /** - * Indicates whether we're using the {@link com.mapbox.mapboxsdk.style.layers.LocationIndicatorLayer} + * Indicates whether we're using the {@link com.mapbox.mapboxsdk.location.LocationIndicatorLayer} * or the stack of {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer}s. */ private boolean useSpecializedLocationLayer; @@ -217,7 +217,8 @@ public final class LocationComponent { @NonNull LocationAnimatorCoordinator locationAnimatorCoordinator, @NonNull StaleStateManager staleStateManager, @NonNull CompassEngine compassEngine, - @NonNull InternalLocationEngineProvider internalLocationEngineProvider) { + @NonNull InternalLocationEngineProvider internalLocationEngineProvider, + boolean useSpecializedLocationLayer) { this.mapboxMap = mapboxMap; this.transform = transform; developerAnimationListeners.add(developerAnimationListener); @@ -229,6 +230,7 @@ public final class LocationComponent { this.staleStateManager = staleStateManager; this.compassEngine = compassEngine; this.internalLocationEngineProvider = internalLocationEngineProvider; + this.useSpecializedLocationLayer = useSpecializedLocationLayer; isComponentInitialized = true; } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java index 91f6141dd..bc295e920 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java @@ -123,14 +123,14 @@ public class LocationComponentActivationOptions { /** * True if you want to initialize and use the specialized location layer to render the location puck. *

- * The specialized layer comes with significant performance improvements, + * The specialized layer is not based on runtime styling. This brings significant performance improvements, * but since it's not based on the runtime styling, * it's not fully compatible with the traditional implementation. The incompatibilities are: *

* * @return whether the default specialized location layer is used @@ -236,14 +236,14 @@ public class LocationComponentActivationOptions { /** * True if you want to initialize and use the specialized location layer to render the location puck. *

- * The specialized layer comes with significant performance improvements, + * The specialized layer is not based on runtime styling. This brings significant performance improvements, * but since it's not based on the runtime styling, * it's not fully compatible with the traditional implementation. The incompatibilities are: *

* * @param useSpecializedLocationLayer true if you want to initialize and use the diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java index 556254297..656191ddb 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -39,7 +39,6 @@ final class LocationLayerController { private int renderMode; private final MapboxMap mapboxMap; - private Style style; private final LayerBitmapProvider bitmapProvider; private LocationComponentOptions options; private final OnRenderModeChangedListener internalRenderModeChangedListener; @@ -60,21 +59,20 @@ final class LocationLayerController { @NonNull OnRenderModeChangedListener internalRenderModeChangedListener, boolean useSpecializedLocationLayer) { this.mapboxMap = mapboxMap; - this.style = style; this.bitmapProvider = bitmapProvider; this.internalRenderModeChangedListener = internalRenderModeChangedListener; this.useSpecializedLocationLayer = useSpecializedLocationLayer; this.isStale = options.enableStaleState(); if (useSpecializedLocationLayer) { - locationLayerRenderer = new IndicatorLocationLayerRenderer(style, layerSourceProvider); + locationLayerRenderer = layerSourceProvider.getIndicatorLocationLayerRenderer(); } else { - locationLayerRenderer = new SymbolLocationLayerRenderer(style, layerSourceProvider, featureProvider, isStale); + locationLayerRenderer = + layerSourceProvider.getSymbolLocationLayerRenderer(featureProvider, isStale); } initializeComponents(style, options); } void initializeComponents(Style style, LocationComponentOptions options) { - this.style = style; this.positionManager = new LocationComponentPositionManager(style, options.layerAbove(), options.layerBelow()); locationLayerRenderer.initializeComponents(style); locationLayerRenderer.addLayers(positionManager); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java index 7ad336313..ae722b3d2 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java @@ -58,11 +58,9 @@ final class SymbolLocationLayerRenderer implements LocationLayerRenderer { private Feature locationFeature; private GeoJsonSource locationSource; - SymbolLocationLayerRenderer(Style style, - LayerSourceProvider layerSourceProvider, + SymbolLocationLayerRenderer(LayerSourceProvider layerSourceProvider, LayerFeatureProvider featureProvider, boolean isStale) { - this.style = style; this.layerSourceProvider = layerSourceProvider; this.layerSet = layerSourceProvider.getEmptyLayerSet(); this.locationFeature = featureProvider.generateLocationFeature(locationFeature, isStale); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java index 735ba3d70..871ac36f9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java @@ -10,6 +10,8 @@ import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.utils.ColorUtils; +import java.util.Arrays; + /** * Properties for Layer */ @@ -124,4 +126,35 @@ public class PropertyValue { public String toString() { return String.format("%s: %s", name, value); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PropertyValue that = (PropertyValue) o; + + if (!name.equals(that.name)) { + return false; + } + if (value != null) { + if (value instanceof Object[]) { + return Arrays.deepEquals((Object[]) value, (Object[]) that.value); + } + return value.equals(that.value); + } else { + return that.value == null; + } + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + (value != null ? value.hashCode() : 0); + return result; + } } diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRendererTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRendererTest.kt new file mode 100644 index 000000000..0d485952b --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRendererTest.kt @@ -0,0 +1,327 @@ +package com.mapbox.mapboxsdk.location + +import android.graphics.Bitmap +import android.graphics.Color +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.location.LocationComponentConstants.* +import com.mapbox.mapboxsdk.location.modes.RenderMode +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.style.expressions.Expression +import com.mapbox.mapboxsdk.style.layers.Layer +import com.mapbox.mapboxsdk.style.layers.Property +import com.mapbox.mapboxsdk.utils.BitmapUtils +import com.mapbox.mapboxsdk.utils.ColorUtils +import io.mockk.* +import org.junit.Assert +import org.junit.Before +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 lateinit var locationLayerRenderer: IndicatorLocationLayerRenderer + + @Before + fun setup() { + every { style.removeLayer(any()) } 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) + ) + } + } + + @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 show_gps_notStale() { + locationLayerRenderer.show(RenderMode.GPS, false) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(""), + LocationPropertyFactory.bearingImage(FOREGROUND_ICON), + LocationPropertyFactory.shadowImage("") + ) + } + verify { layer.setProperties(LocationPropertyFactory.accuracyRadius(0f)) } + } + + @Test + fun show_normal_stale() { + locationLayerRenderer.show(RenderMode.NORMAL, true) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON), + LocationPropertyFactory.bearingImage(BACKGROUND_STALE_ICON), + LocationPropertyFactory.shadowImage(SHADOW_ICON) + ) + } + } + + @Test + fun show_compass_stale() { + locationLayerRenderer.show(RenderMode.COMPASS, true) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON), + LocationPropertyFactory.bearingImage(BEARING_STALE_ICON), + LocationPropertyFactory.shadowImage(SHADOW_ICON) + ) + } + } + + @Test + fun show_gps_stale() { + locationLayerRenderer.show(RenderMode.GPS, true) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(""), + LocationPropertyFactory.bearingImage(FOREGROUND_STALE_ICON), + LocationPropertyFactory.shadowImage("") + ) + } + 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) + + locationLayerRenderer.styleAccuracy(0.7f, Color.RED) + + verify { + layer.setProperties( + LocationPropertyFactory.accuracyRadiusColor(exp), + LocationPropertyFactory.accuracyRadiusBorderColor(exp) + ) + } + } + + @Test + fun setLatLng() { + val latLng = LatLng(10.0, 20.0) + locationLayerRenderer.setLatLng(latLng) + + 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) + ) + } + } + + @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() + 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() + 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() + private val backgroundBitmap = mockk() + private val backgroundStaleBitmap = mockk() + private val bearingBitmap = mockk() + private val foregroundBitmap = mockk() + private val foregroundStaleBitmap = mockk() + + 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) +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt index 4a2839361..33a067f59 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -13,6 +13,7 @@ import com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMA import com.mapbox.mapboxsdk.location.modes.CameraMode import com.mapbox.mapboxsdk.location.modes.RenderMode import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.Projection import com.mapbox.mapboxsdk.maps.Style import com.mapbox.mapboxsdk.maps.Transform import org.junit.Assert @@ -80,7 +81,7 @@ class LocationComponentTest { fun before() { MockitoAnnotations.initMocks(this) developerAnimationListeners = mutableListOf() - locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, locationEngineProvider) + locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, locationEngineProvider, false) doReturn(locationEngine).`when`(locationEngineProvider).getBestLocationEngine(context, false) doReturn(style).`when`(mapboxMap).style } @@ -587,4 +588,46 @@ class LocationComponentTest { verify(callback, times(0)).onCancel() verify(locationAnimatorCoordinator).feedNewZoomLevel(14.0, CameraPosition.DEFAULT, 500L, callback) } + + @Test + fun newLocation_accuracy_symbolLayerRadiusValue() { + val location = Location("test") + location.accuracy = 50f + val projection: Projection = mock(Projection::class.java) + `when`(projection.getMetersPerPixelAtLatitude(location.latitude)).thenReturn(10.0) + `when`(mapboxMap.projection).thenReturn(projection) + `when`(style.isFullyLoaded).thenReturn(true) + locationComponent.activateLocationComponent( + LocationComponentActivationOptions.builder(context, style) + .locationComponentOptions(locationComponentOptions) + .useDefaultLocationEngine(false) + .build() + ) + locationComponent.isLocationComponentEnabled = true + locationComponent.onStart() + locationComponent.forceLocationUpdate(location) + + val radius = (location.accuracy * (1 / 10.0)).toFloat() + verify(locationAnimatorCoordinator).feedNewAccuracyRadius(radius, false) + } + + @Test + fun newLocation_accuracy_indicatorLayerRadiusValue() { + val location = Location("test") + location.accuracy = 50f + `when`(style.isFullyLoaded).thenReturn(true) + locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, locationEngineProvider, true) + locationComponent.activateLocationComponent( + LocationComponentActivationOptions.builder(context, style) + .locationComponentOptions(locationComponentOptions) + .useSpecializedLocationLayer(true) + .useDefaultLocationEngine(false) + .build() + ) + locationComponent.isLocationComponentEnabled = true + locationComponent.onStart() + locationComponent.forceLocationUpdate(location) + + verify(locationAnimatorCoordinator).feedNewAccuracyRadius(location.accuracy, false) + } } \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java index c41732bc9..40726acbe 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.location; import android.graphics.Bitmap; + import androidx.annotation.NonNull; import com.google.gson.JsonElement; @@ -15,6 +16,8 @@ import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import java.util.HashSet; import java.util.Set; @@ -43,6 +46,8 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -53,6 +58,7 @@ public class LocationLayerControllerTest { private MapboxMap mapboxMap = mock(MapboxMap.class); private Style style = mock(Style.class); + private LocationLayerRenderer indicatorRenderer = mock(LocationLayerRenderer.class); @Before public void before() { @@ -316,6 +322,20 @@ public class LocationLayerControllerTest { verify(style).addImage(BEARING_ICON, bitmap); } + @Test + public void applyStyle_specializedLayer_ignoreBitmapNames() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.foregroundName()).thenReturn("new_name"); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener, true); + + verify(indicatorRenderer).updateIconIds(eq(FOREGROUND_ICON), anyString(), anyString(), anyString(), anyString()); + } + @Test public void applyStyle_layerBelowChanged() { OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); @@ -599,7 +619,7 @@ public class LocationLayerControllerTest { LocationLayerController controller = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener, false); + bitmapProvider, options, internalRenderModeChangedListener, false); controller.setRenderMode(RenderMode.NORMAL); controller.setRenderMode(RenderMode.NORMAL); @@ -618,7 +638,7 @@ public class LocationLayerControllerTest { LocationLayerController controller = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener, false); + bitmapProvider, options, internalRenderModeChangedListener, false); controller.setRenderMode(RenderMode.GPS); controller.setRenderMode(RenderMode.GPS); @@ -642,7 +662,7 @@ public class LocationLayerControllerTest { LocationLayerController controller = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener, false); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addImage(FOREGROUND_ICON, bitmap); @@ -674,7 +694,18 @@ public class LocationLayerControllerTest { } private LayerSourceProvider buildLayerProvider() { - LayerSourceProvider layerSourceProvider = mock(LayerSourceProvider.class); + final LayerSourceProvider layerSourceProvider = mock(LayerSourceProvider.class); + when(layerSourceProvider.getIndicatorLocationLayerRenderer()).thenReturn(indicatorRenderer); + when(layerSourceProvider.getSymbolLocationLayerRenderer(any(LayerFeatureProvider.class), anyBoolean())).thenAnswer( + new Answer() { + @Override + public LocationLayerRenderer answer(InvocationOnMock invocation) { + LayerFeatureProvider featureProvider = invocation.getArgument(0); + boolean isStale = invocation.getArgument(1); + return new SymbolLocationLayerRenderer(layerSourceProvider, featureProvider, isStale); + } + } + ); Layer shadowLayer = mock(Layer.class); when(shadowLayer.getId()).thenReturn(SHADOW_LAYER); diff --git a/gradle/gradle-checkstyle.gradle b/gradle/gradle-checkstyle.gradle index 8eb4baa85..3e36e7746 100644 --- a/gradle/gradle-checkstyle.gradle +++ b/gradle/gradle-checkstyle.gradle @@ -21,6 +21,9 @@ task checkstyle(type: Checkstyle) { exclude '**/log/LoggerDefinition.java' exclude '**/log/Logger.java' exclude '**/Expression.java' + exclude '**/location/LocationPropertyFactory.java' + exclude '**/location/LocationIndicatorLayer.java' + exclude '**/location/LocationIndicatorLayerTest.java' classpath = files() ignoreFailures = false }