From 1c68f5a40f8ca2db5b11d85d007a93f6d1130b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 24 Apr 2019 13:19:31 +0200 Subject: [android] clear up LocationComponent's z-index positioning docs and add "layer-above" option --- .../location/LocationComponentOptions.java | 318 +++++++++++++-------- .../location/LocationComponentPositionManager.java | 48 ++++ .../location/LocationLayerController.java | 33 +-- .../src/main/res-public/values/public.xml | 5 + .../src/main/res/values/attrs.xml | 1 + .../location/LocationComponentOptionsTest.java | 11 + .../LocationComponentPositionManagerTest.kt | 130 +++++++++ .../location/LocationLayerControllerTest.java | 3 +- .../location/LocationLayerControllerTest.kt | 3 +- .../activity/location/LocationModesActivity.java | 1 - .../src/main/res/values/styles.xml | 2 + 11 files changed, 419 insertions(+), 136 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java create mode 100644 platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManagerTest.kt diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java index a7b83d7d9d..eb74cc7066 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java @@ -14,6 +14,7 @@ import android.support.annotation.StyleRes; import com.mapbox.android.gestures.AndroidGesturesManager; import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.style.layers.Layer; import java.util.Arrays; @@ -108,6 +109,7 @@ public class LocationComponentOptions implements Parcelable { private boolean trackingGesturesManagement; private float trackingInitialMoveThreshold; private float trackingMultiFingerMoveThreshold; + private String layerAbove; private String layerBelow; private float trackingAnimationDurationMultiplier; private boolean compassAnimationEnabled; @@ -142,6 +144,7 @@ public class LocationComponentOptions implements Parcelable { boolean trackingGesturesManagement, float trackingInitialMoveThreshold, float trackingMultiFingerMoveThreshold, + String layerAbove, String layerBelow, float trackingAnimationDurationMultiplier, boolean compassAnimationEnabled, @@ -177,6 +180,7 @@ public class LocationComponentOptions implements Parcelable { this.trackingGesturesManagement = trackingGesturesManagement; this.trackingInitialMoveThreshold = trackingInitialMoveThreshold; this.trackingMultiFingerMoveThreshold = trackingMultiFingerMoveThreshold; + this.layerAbove = layerAbove; this.layerBelow = layerBelow; this.trackingAnimationDurationMultiplier = trackingAnimationDurationMultiplier; this.compassAnimationEnabled = compassAnimationEnabled; @@ -271,6 +275,9 @@ public class LocationComponentOptions implements Parcelable { typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingBottom, 0), }); + builder.layerAbove( + typedArray.getString(R.styleable.mapbox_LocationComponent_mapbox_layer_above)); + builder.layerBelow( typedArray.getString(R.styleable.mapbox_LocationComponent_mapbox_layer_below)); @@ -681,9 +688,24 @@ public class LocationComponentOptions implements Parcelable { } /** - * Gets the id of the layer to add the location component above to. + * Gets the id of the layer that's referenced when placing the component on the map using + * {@link com.mapbox.mapboxsdk.maps.Style#addLayerAbove(Layer, String)}. + *

+ * The component is going to placed directly above this layer. + * + * @return layerAbove the id of the layer the component is going to placed directly above. + */ + public String layerAbove() { + return layerAbove; + } + + /** + * Gets the id of the layer that's referenced when placing the component on the map using + * {@link com.mapbox.mapboxsdk.maps.Style#addLayerBelow(Layer, String)}. + *

+ * The component is going to placed directly below this layer. * - * @return layerBelow the id of the layer to add the location component above to + * @return layerBelow the id of the layer the component is going to placed directly below. */ public String layerBelow() { return layerBelow; @@ -749,6 +771,7 @@ public class LocationComponentOptions implements Parcelable { + "trackingGesturesManagement=" + trackingGesturesManagement + ", " + "trackingInitialMoveThreshold=" + trackingInitialMoveThreshold + ", " + "trackingMultiFingerMoveThreshold=" + trackingMultiFingerMoveThreshold + ", " + + "layerAbove=" + layerAbove + "layerBelow=" + layerBelow + "trackingAnimationDurationMultiplier=" + trackingAnimationDurationMultiplier + "}"; @@ -756,124 +779,160 @@ public class LocationComponentOptions implements Parcelable { @Override public boolean equals(Object o) { - if (o == this) { + if (this == o) { return true; } - if (o instanceof LocationComponentOptions) { - LocationComponentOptions that = (LocationComponentOptions) o; - return (Float.floatToIntBits(this.accuracyAlpha) == Float.floatToIntBits(that.accuracyAlpha())) - && (this.accuracyColor == that.accuracyColor()) - && (this.backgroundDrawableStale == that.backgroundDrawableStale()) - && ((this.backgroundStaleName == null) ? (that.backgroundStaleName() == null) - : this.backgroundStaleName.equals(that.backgroundStaleName())) - && (this.foregroundDrawableStale == that.foregroundDrawableStale()) - && ((this.foregroundStaleName == null) ? (that.foregroundStaleName() == null) - : this.foregroundStaleName.equals(that.foregroundStaleName())) - && (this.gpsDrawable == that.gpsDrawable()) - && ((this.gpsName == null) ? (that.gpsName() == null) : this.gpsName.equals(that.gpsName())) - && (this.foregroundDrawable == that.foregroundDrawable()) - && ((this.foregroundName == null) ? (that.foregroundName() == null) - : this.foregroundName.equals(that.foregroundName())) - && (this.backgroundDrawable == that.backgroundDrawable()) - && ((this.backgroundName == null) ? (that.backgroundName() == null) - : this.backgroundName.equals(that.backgroundName())) - && (this.bearingDrawable == that.bearingDrawable()) - && ((this.bearingName == null) ? (that.bearingName() == null) - : this.bearingName.equals(that.bearingName())) - && ((this.bearingTintColor == null) ? (that.bearingTintColor() == null) - : this.bearingTintColor.equals(that.bearingTintColor())) - && ((this.foregroundTintColor == null) ? (that.foregroundTintColor() == null) - : this.foregroundTintColor.equals(that.foregroundTintColor())) - && ((this.backgroundTintColor == null) ? (that.backgroundTintColor() == null) - : this.backgroundTintColor.equals(that.backgroundTintColor())) - && ((this.foregroundStaleTintColor == null) ? (that.foregroundStaleTintColor() == null) - : this.foregroundStaleTintColor.equals(that.foregroundStaleTintColor())) - && ((this.backgroundStaleTintColor == null) ? (that.backgroundStaleTintColor() == null) - : this.backgroundStaleTintColor.equals(that.backgroundStaleTintColor())) - && (Float.floatToIntBits(this.elevation) == Float.floatToIntBits(that.elevation())) - && (this.enableStaleState == that.enableStaleState()) - && (this.staleStateTimeout == that.staleStateTimeout()) - && (Arrays.equals(this.padding, that.padding()) - && (Float.floatToIntBits(this.maxZoomIconScale) == Float.floatToIntBits(that.maxZoomIconScale())) - && (Float.floatToIntBits(this.minZoomIconScale) == Float.floatToIntBits(that.minZoomIconScale())) - && (this.trackingGesturesManagement == that.trackingGesturesManagement()) - && (Float.floatToIntBits(this.trackingInitialMoveThreshold) - == Float.floatToIntBits(that.trackingInitialMoveThreshold())) - && (Float.floatToIntBits(this.trackingMultiFingerMoveThreshold) - == Float.floatToIntBits(that.trackingMultiFingerMoveThreshold())) - && layerBelow.equals(that.layerBelow)) - && (Float.floatToIntBits(this.trackingAnimationDurationMultiplier) - == Float.floatToIntBits(that.trackingAnimationDurationMultiplier())); - } - return false; + if (o == null || getClass() != o.getClass()) { + return false; + } + + LocationComponentOptions options = (LocationComponentOptions) o; + + if (Float.compare(options.accuracyAlpha, accuracyAlpha) != 0) { + return false; + } + if (accuracyColor != options.accuracyColor) { + return false; + } + if (backgroundDrawableStale != options.backgroundDrawableStale) { + return false; + } + if (foregroundDrawableStale != options.foregroundDrawableStale) { + return false; + } + if (gpsDrawable != options.gpsDrawable) { + return false; + } + if (foregroundDrawable != options.foregroundDrawable) { + return false; + } + if (backgroundDrawable != options.backgroundDrawable) { + return false; + } + if (bearingDrawable != options.bearingDrawable) { + return false; + } + if (Float.compare(options.elevation, elevation) != 0) { + return false; + } + if (enableStaleState != options.enableStaleState) { + return false; + } + if (staleStateTimeout != options.staleStateTimeout) { + return false; + } + if (Float.compare(options.maxZoomIconScale, maxZoomIconScale) != 0) { + return false; + } + if (Float.compare(options.minZoomIconScale, minZoomIconScale) != 0) { + return false; + } + if (trackingGesturesManagement != options.trackingGesturesManagement) { + return false; + } + if (Float.compare(options.trackingInitialMoveThreshold, trackingInitialMoveThreshold) != 0) { + return false; + } + if (Float.compare(options.trackingMultiFingerMoveThreshold, trackingMultiFingerMoveThreshold) != 0) { + return false; + } + if (Float.compare(options.trackingAnimationDurationMultiplier, trackingAnimationDurationMultiplier) != 0) { + return false; + } + if (compassAnimationEnabled != options.compassAnimationEnabled) { + return false; + } + if (accuracyAnimationEnabled != options.accuracyAnimationEnabled) { + return false; + } + if (backgroundStaleName != null ? !backgroundStaleName.equals(options.backgroundStaleName) : + options.backgroundStaleName != null) { + return false; + } + if (foregroundStaleName != null ? !foregroundStaleName.equals(options.foregroundStaleName) : + options.foregroundStaleName != null) { + return false; + } + if (gpsName != null ? !gpsName.equals(options.gpsName) : options.gpsName != null) { + return false; + } + if (foregroundName != null ? !foregroundName.equals(options.foregroundName) : options.foregroundName != null) { + return false; + } + if (backgroundName != null ? !backgroundName.equals(options.backgroundName) : options.backgroundName != null) { + return false; + } + if (bearingName != null ? !bearingName.equals(options.bearingName) : options.bearingName != null) { + return false; + } + if (bearingTintColor != null ? !bearingTintColor.equals(options.bearingTintColor) : + options.bearingTintColor != null) { + return false; + } + if (foregroundTintColor != null ? !foregroundTintColor.equals(options.foregroundTintColor) : + options.foregroundTintColor != null) { + return false; + } + if (backgroundTintColor != null ? !backgroundTintColor.equals(options.backgroundTintColor) : + options.backgroundTintColor != null) { + return false; + } + if (foregroundStaleTintColor != null ? !foregroundStaleTintColor.equals(options.foregroundStaleTintColor) : + options.foregroundStaleTintColor != null) { + return false; + } + if (backgroundStaleTintColor != null ? !backgroundStaleTintColor.equals(options.backgroundStaleTintColor) : + options.backgroundStaleTintColor != null) { + return false; + } + if (!Arrays.equals(padding, options.padding)) { + return false; + } + if (layerAbove != null ? !layerAbove.equals(options.layerAbove) : options.layerAbove != null) { + return false; + } + return layerBelow != null ? layerBelow.equals(options.layerBelow) : options.layerBelow == null; } @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= Float.floatToIntBits(accuracyAlpha); - h$ *= 1000003; - h$ ^= accuracyColor; - h$ *= 1000003; - h$ ^= backgroundDrawableStale; - h$ *= 1000003; - h$ ^= (backgroundStaleName == null) ? 0 : backgroundStaleName.hashCode(); - h$ *= 1000003; - h$ ^= foregroundDrawableStale; - h$ *= 1000003; - h$ ^= (foregroundStaleName == null) ? 0 : foregroundStaleName.hashCode(); - h$ *= 1000003; - h$ ^= gpsDrawable; - h$ *= 1000003; - h$ ^= (gpsName == null) ? 0 : gpsName.hashCode(); - h$ *= 1000003; - h$ ^= foregroundDrawable; - h$ *= 1000003; - h$ ^= (foregroundName == null) ? 0 : foregroundName.hashCode(); - h$ *= 1000003; - h$ ^= backgroundDrawable; - h$ *= 1000003; - h$ ^= (backgroundName == null) ? 0 : backgroundName.hashCode(); - h$ *= 1000003; - h$ ^= bearingDrawable; - h$ *= 1000003; - h$ ^= (bearingName == null) ? 0 : bearingName.hashCode(); - h$ *= 1000003; - h$ ^= (bearingTintColor == null) ? 0 : bearingTintColor.hashCode(); - h$ *= 1000003; - h$ ^= (foregroundTintColor == null) ? 0 : foregroundTintColor.hashCode(); - h$ *= 1000003; - h$ ^= (backgroundTintColor == null) ? 0 : backgroundTintColor.hashCode(); - h$ *= 1000003; - h$ ^= (foregroundStaleTintColor == null) ? 0 : foregroundStaleTintColor.hashCode(); - h$ *= 1000003; - h$ ^= (backgroundStaleTintColor == null) ? 0 : backgroundStaleTintColor.hashCode(); - h$ *= 1000003; - h$ ^= Float.floatToIntBits(elevation); - h$ *= 1000003; - h$ ^= enableStaleState ? 1231 : 1237; - h$ *= 1000003; - h$ ^= (int) ((staleStateTimeout >>> 32) ^ staleStateTimeout); - h$ *= 1000003; - h$ ^= Arrays.hashCode(padding); - h$ *= 1000003; - h$ ^= Float.floatToIntBits(maxZoomIconScale); - h$ *= 1000003; - h$ ^= Float.floatToIntBits(minZoomIconScale); - h$ *= 1000003; - h$ ^= trackingGesturesManagement ? 1231 : 1237; - h$ *= 1000003; - h$ ^= Float.floatToIntBits(trackingInitialMoveThreshold); - h$ *= 1000003; - h$ ^= Float.floatToIntBits(trackingMultiFingerMoveThreshold); - h$ *= 1000003; - h$ ^= Float.floatToIntBits(trackingAnimationDurationMultiplier); - h$ *= 1000003; - h$ ^= compassAnimationEnabled ? 1231 : 1237; - h$ *= 1000003; - h$ ^= accuracyAnimationEnabled ? 1231 : 1237; - return h$; + int result = (accuracyAlpha != +0.0f ? Float.floatToIntBits(accuracyAlpha) : 0); + result = 31 * result + accuracyColor; + result = 31 * result + backgroundDrawableStale; + result = 31 * result + (backgroundStaleName != null ? backgroundStaleName.hashCode() : 0); + result = 31 * result + foregroundDrawableStale; + result = 31 * result + (foregroundStaleName != null ? foregroundStaleName.hashCode() : 0); + result = 31 * result + gpsDrawable; + result = 31 * result + (gpsName != null ? gpsName.hashCode() : 0); + result = 31 * result + foregroundDrawable; + result = 31 * result + (foregroundName != null ? foregroundName.hashCode() : 0); + result = 31 * result + backgroundDrawable; + result = 31 * result + (backgroundName != null ? backgroundName.hashCode() : 0); + result = 31 * result + bearingDrawable; + result = 31 * result + (bearingName != null ? bearingName.hashCode() : 0); + result = 31 * result + (bearingTintColor != null ? bearingTintColor.hashCode() : 0); + result = 31 * result + (foregroundTintColor != null ? foregroundTintColor.hashCode() : 0); + result = 31 * result + (backgroundTintColor != null ? backgroundTintColor.hashCode() : 0); + result = 31 * result + (foregroundStaleTintColor != null ? foregroundStaleTintColor.hashCode() : 0); + result = 31 * result + (backgroundStaleTintColor != null ? backgroundStaleTintColor.hashCode() : 0); + result = 31 * result + (elevation != +0.0f ? Float.floatToIntBits(elevation) : 0); + result = 31 * result + (enableStaleState ? 1 : 0); + result = 31 * result + (int) (staleStateTimeout ^ (staleStateTimeout >>> 32)); + result = 31 * result + Arrays.hashCode(padding); + result = 31 * result + (maxZoomIconScale != +0.0f ? Float.floatToIntBits(maxZoomIconScale) : 0); + result = 31 * result + (minZoomIconScale != +0.0f ? Float.floatToIntBits(minZoomIconScale) : 0); + result = 31 * result + (trackingGesturesManagement ? 1 : 0); + result = 31 * result + (trackingInitialMoveThreshold != +0.0f + ? Float.floatToIntBits(trackingInitialMoveThreshold) : 0); + result = 31 * result + (trackingMultiFingerMoveThreshold != +0.0f + ? Float.floatToIntBits(trackingMultiFingerMoveThreshold) : 0); + result = 31 * result + (layerAbove != null ? layerAbove.hashCode() : 0); + result = 31 * result + (layerBelow != null ? layerBelow.hashCode() : 0); + result = 31 * result + (trackingAnimationDurationMultiplier != +0.0f + ? Float.floatToIntBits(trackingAnimationDurationMultiplier) : 0); + result = 31 * result + (compassAnimationEnabled ? 1 : 0); + result = 31 * result + (accuracyAnimationEnabled ? 1 : 0); + return result; } public static final Parcelable.Creator CREATOR = @@ -910,6 +969,7 @@ public class LocationComponentOptions implements Parcelable { in.readFloat(), in.readFloat(), in.readString(), + in.readString(), in.readFloat(), in.readInt() == 1, in.readInt() == 1 @@ -1007,6 +1067,7 @@ public class LocationComponentOptions implements Parcelable { dest.writeInt(trackingGesturesManagement() ? 1 : 0); dest.writeFloat(trackingInitialMoveThreshold()); dest.writeFloat(trackingMultiFingerMoveThreshold()); + dest.writeString(layerAbove()); dest.writeString(layerBelow()); dest.writeFloat(trackingAnimationDurationMultiplier); dest.writeInt(compassAnimationEnabled() ? 1 : 0); @@ -1041,6 +1102,11 @@ public class LocationComponentOptions implements Parcelable { + locationComponentOptions.elevation() + ". Must be >= 0"); } + if (locationComponentOptions.layerAbove() != null && locationComponentOptions.layerBelow() != null) { + throw new IllegalArgumentException("You cannot set both layerAbove and layerBelow options." + + "Choose one or the other."); + } + return locationComponentOptions; } @@ -1084,6 +1150,7 @@ public class LocationComponentOptions implements Parcelable { private Boolean trackingGesturesManagement; private Float trackingInitialMoveThreshold; private Float trackingMultiFingerMoveThreshold; + private String layerAbove; private String layerBelow; private Float trackingAnimationDurationMultiplier; private Boolean compassAnimationEnabled; @@ -1121,6 +1188,7 @@ public class LocationComponentOptions implements Parcelable { this.trackingGesturesManagement = source.trackingGesturesManagement(); this.trackingInitialMoveThreshold = source.trackingInitialMoveThreshold(); this.trackingMultiFingerMoveThreshold = source.trackingMultiFingerMoveThreshold(); + this.layerAbove = source.layerAbove(); this.layerBelow = source.layerBelow(); this.trackingAnimationDurationMultiplier = source.trackingAnimationDurationMultiplier(); this.compassAnimationEnabled = source.compassAnimationEnabled(); @@ -1547,9 +1615,26 @@ public class LocationComponentOptions implements Parcelable { } /** - * Sets the layer id to set the location component below to. + * Sets the id of the layer that's referenced when placing the component on the map using + * {@link com.mapbox.mapboxsdk.maps.Style#addLayerAbove(Layer, String)}. + *

+ * The component is going to placed directly above this layer. + * + * @param layerAbove the id of the layer the component is going to placed directly above. + */ + @NonNull + public LocationComponentOptions.Builder layerAbove(String layerAbove) { + this.layerAbove = layerAbove; + return this; + } + + /** + * Sets the id of the layer that's referenced when placing the component on the map using + * {@link com.mapbox.mapboxsdk.maps.Style#addLayerBelow(Layer, String)}. + *

+ * The component is going to placed directly below this layer. * - * @param layerBelow the id to set the location component below to. + * @param layerBelow the id of the layer the component is going to placed directly below. */ @NonNull public LocationComponentOptions.Builder layerBelow(String layerBelow) { @@ -1679,6 +1764,7 @@ public class LocationComponentOptions implements Parcelable { trackingGesturesManagement, this.trackingInitialMoveThreshold, this.trackingMultiFingerMoveThreshold, + this.layerAbove, this.layerBelow, this.trackingAnimationDurationMultiplier, this.compassAnimationEnabled, diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java new file mode 100644 index 0000000000..f2e4d0bb41 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java @@ -0,0 +1,48 @@ +package com.mapbox.mapboxsdk.location; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.style.layers.Layer; + +class LocationComponentPositionManager { + + @NonNull + private final Style style; + + @Nullable + private String layerAbove; + + @Nullable + private String layerBelow; + + LocationComponentPositionManager(@NonNull Style style, @Nullable String layerAbove, @Nullable String layerBelow) { + this.style = style; + this.layerAbove = layerAbove; + this.layerBelow = layerBelow; + } + + /** + * Returns true whenever layer above/below configuration has changed and requires re-layout. + */ + boolean update(@Nullable String layerAbove, @Nullable String layerBelow) { + boolean requiresUpdate = + !(this.layerAbove == layerAbove || (this.layerAbove != null && this.layerAbove.equals(layerAbove))) + || !(this.layerBelow == layerBelow || (this.layerBelow != null && this.layerBelow.equals(layerBelow))); + + this.layerAbove = layerAbove; + this.layerBelow = layerBelow; + return requiresUpdate; + } + + void addLayerToMap(@NonNull Layer layer) { + if (layerAbove != null) { + style.addLayerAbove(layer, layerAbove); + } else if (layerBelow != null) { + style.addLayerBelow(layer, layerBelow); + } else { + style.addLayer(layer); + } + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java index aa8a82bf6d..c0c6017cd6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -77,8 +77,7 @@ final class LocationLayerController { private boolean isHidden = true; - @Nullable - private String layerBelow; + private LocationComponentPositionManager positionManager; LocationLayerController(MapboxMap mapboxMap, Style style, LayerSourceProvider layerSourceProvider, LayerFeatureProvider featureProvider, LayerBitmapProvider bitmapProvider, @@ -95,8 +94,9 @@ final class LocationLayerController { void initializeComponents(Style style, LocationComponentOptions options) { this.style = style; + this.positionManager = new LocationComponentPositionManager(style, options.layerAbove(), options.layerBelow()); addLocationSource(); - addLayers(options.layerBelow()); + addLayers(); applyStyle(options); if (isHidden) { @@ -107,18 +107,15 @@ final class LocationLayerController { } void applyStyle(@NonNull LocationComponentOptions options) { - String newLayerBelowOption = options.layerBelow(); - if ((layerBelow != null || newLayerBelowOption != null)) { - if (layerBelow == null || !layerBelow.equals(newLayerBelowOption)) { - removeLayers(); - addLayers(newLayerBelowOption); - if (isHidden) { - for (String layerId : layerSet) { - setLayerVisibility(layerId, false); - } + if (positionManager.update(options.layerAbove(), options.layerBelow())) { + removeLayers(); + addLayers(); + if (isHidden) { + for (String layerId : layerSet) { + setLayerVisibility(layerId, false); } - setRenderMode(renderMode); } + setRenderMode(renderMode); } this.options = options; @@ -237,9 +234,13 @@ final class LocationLayerController { } } - private void addLayers(@NonNull String idBelowLayer) { - layerBelow = idBelowLayer; - addSymbolLayer(BEARING_LAYER, idBelowLayer); + private void addLayers() { + // positions the top-most reference layer + Layer layer = layerSourceProvider.generateLayer(BEARING_LAYER); + positionManager.addLayerToMap(layer); + layerSet.add(layer.getId()); + + // adds remaining layers while keeping the order addSymbolLayer(FOREGROUND_LAYER, BEARING_LAYER); addSymbolLayer(BACKGROUND_LAYER, FOREGROUND_LAYER); addSymbolLayer(SHADOW_LAYER, BACKGROUND_LAYER); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml index 58109257f2..756b337f12 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml @@ -150,4 +150,9 @@ + + + + + diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml index 2eeb5057f2..a7182d6e4b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml @@ -156,6 +156,7 @@ + diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java index f228adcce7..b1e1f14cb1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java @@ -67,4 +67,15 @@ public class LocationComponentOptionsTest { .elevation(-500) .build(); } + + @Test + public void passingBothLayerPositionOptions_throwsException() throws Exception { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("You cannot set both layerAbove and layerBelow options." + + "Choose one or the other."); + LocationComponentOptions.builder(context) + .layerAbove("above") + .layerBelow("below") + .build(); + } } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManagerTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManagerTest.kt new file mode 100644 index 0000000000..c8a75b6701 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManagerTest.kt @@ -0,0 +1,130 @@ +package com.mapbox.mapboxsdk.location + +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.style.layers.Layer +import io.mockk.mockk +import io.mockk.verify +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class LocationComponentPositionManagerTest { + + private lateinit var style: Style + private lateinit var layer: Layer + + @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_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_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_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_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 addLayer_noModifier() { + val positionManager = LocationComponentPositionManager(style, null, null) + positionManager.addLayerToMap(layer) + + verify { style.addLayer(layer) } + } + + @Test + fun addLayer_above() { + val positionManager = LocationComponentPositionManager(style, "above", null) + positionManager.addLayerToMap(layer) + + verify { style.addLayerAbove(layer, "above") } + } + + @Test + fun addLayer_below() { + val positionManager = LocationComponentPositionManager(style, null, "below") + positionManager.addLayerToMap(layer) + + verify { style.addLayerBelow(layer, "below") } + } + + @Test + fun addLayer_afterUpdate_above() { + val positionManager = LocationComponentPositionManager(style, null, null) + positionManager.update("above", null) + positionManager.addLayerToMap(layer) + + verify { style.addLayerAbove(layer, "above") } + } + + @Test + fun addLayer_afterUpdate_below() { + val positionManager = LocationComponentPositionManager(style, null, null) + positionManager.update(null, "below") + positionManager.addLayerToMap(layer) + + verify { style.addLayerBelow(layer, "below") } + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java index 6a44cf1f79..aa0a07b73e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java @@ -400,7 +400,8 @@ public class LocationLayerControllerTest { layerController.applyStyle(options); verify(style, times(0)).removeLayer(any(String.class)); - verify(style, times(5)).addLayerBelow(any(Layer.class), Mockito.any()); + verify(style, times(1)).addLayer(any(Layer.class)); + verify(style, times(4)).addLayerBelow(any(Layer.class), Mockito.any()); } @Test diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt index fb450de527..95a3891b6d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt @@ -284,8 +284,7 @@ class LocationLayerControllerTest : EspressoTest() { TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true)) - val options = - LocationComponentOptions.createFromAttributes(context, com.mapbox.mapboxsdk.testapp.R.style.CustomLocationComponent) + val options = component.locationComponentOptions .toBuilder() .layerBelow("road-label") .build() diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java index 28d165428d..718a536a08 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java @@ -207,7 +207,6 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea options = options.toBuilder() .padding(padding) - .layerBelow("road-label") .build(); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml index faa994e978..8d7da603f7 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml @@ -50,6 +50,8 @@ 0dp false false + + road-label -- cgit v1.2.1