292 lines
11 KiB
Java
292 lines
11 KiB
Java
package com.mapbox.mapboxsdk.location;
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
|
|
import com.google.gson.JsonArray;
|
|
import com.google.gson.JsonObject;
|
|
import com.mapbox.geojson.Feature;
|
|
import com.mapbox.geojson.Point;
|
|
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.style.layers.SymbolLayer;
|
|
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
|
|
|
|
import java.util.Set;
|
|
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_LAYER;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_LAYER;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_STALE_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_LAYER;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_LAYER;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_STALE_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.LOCATION_SOURCE;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_ALPHA;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_COLOR;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_RADIUS;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BACKGROUND_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BACKGROUND_STALE_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BEARING_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_COMPASS_BEARING;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON_OFFSET;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_STALE_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_LOCATION_STALE;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON;
|
|
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER;
|
|
import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
|
|
import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
|
|
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
|
|
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
|
|
import static com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaString;
|
|
|
|
final class SymbolLocationLayerRenderer implements LocationLayerRenderer {
|
|
private Style style;
|
|
private final LayerSourceProvider layerSourceProvider;
|
|
|
|
private final Set<String> layerSet;
|
|
private Feature locationFeature;
|
|
private GeoJsonSource locationSource;
|
|
|
|
SymbolLocationLayerRenderer(LayerSourceProvider layerSourceProvider,
|
|
LayerFeatureProvider featureProvider,
|
|
boolean isStale) {
|
|
this.layerSourceProvider = layerSourceProvider;
|
|
this.layerSet = layerSourceProvider.getEmptyLayerSet();
|
|
this.locationFeature = featureProvider.generateLocationFeature(locationFeature, isStale);
|
|
}
|
|
|
|
@Override
|
|
public void initializeComponents(Style style) {
|
|
this.style = style;
|
|
addLocationSource();
|
|
}
|
|
|
|
@Override
|
|
public void addLayers(LocationComponentPositionManager positionManager) {
|
|
// 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);
|
|
addAccuracyLayer();
|
|
}
|
|
|
|
@Override
|
|
public void removeLayers() {
|
|
for (String layerId : layerSet) {
|
|
style.removeLayer(layerId);
|
|
}
|
|
layerSet.clear();
|
|
}
|
|
|
|
@Override
|
|
public void hide() {
|
|
for (String layerId : layerSet) {
|
|
setLayerVisibility(layerId, false);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void cameraTiltUpdated(double tilt) {
|
|
updateForegroundOffset(tilt);
|
|
}
|
|
|
|
@Override
|
|
public void cameraBearingUpdated(double bearing) {
|
|
updateForegroundBearing((float) bearing);
|
|
}
|
|
|
|
@Override
|
|
public void show(@RenderMode.Mode int renderMode, boolean isStale) {
|
|
switch (renderMode) {
|
|
case RenderMode.NORMAL:
|
|
setLayerVisibility(SHADOW_LAYER, true);
|
|
setLayerVisibility(FOREGROUND_LAYER, true);
|
|
setLayerVisibility(BACKGROUND_LAYER, true);
|
|
setLayerVisibility(ACCURACY_LAYER, !isStale);
|
|
setLayerVisibility(BEARING_LAYER, false);
|
|
break;
|
|
case RenderMode.COMPASS:
|
|
setLayerVisibility(SHADOW_LAYER, true);
|
|
setLayerVisibility(FOREGROUND_LAYER, true);
|
|
setLayerVisibility(BACKGROUND_LAYER, true);
|
|
setLayerVisibility(ACCURACY_LAYER, !isStale);
|
|
setLayerVisibility(BEARING_LAYER, true);
|
|
break;
|
|
case RenderMode.GPS:
|
|
setLayerVisibility(SHADOW_LAYER, false);
|
|
setLayerVisibility(FOREGROUND_LAYER, true);
|
|
setLayerVisibility(BACKGROUND_LAYER, true);
|
|
setLayerVisibility(ACCURACY_LAYER, false);
|
|
setLayerVisibility(BEARING_LAYER, false);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void styleAccuracy(float accuracyAlpha, int accuracyColor) {
|
|
locationFeature.addNumberProperty(PROPERTY_ACCURACY_ALPHA, accuracyAlpha);
|
|
locationFeature.addStringProperty(PROPERTY_ACCURACY_COLOR, colorToRgbaString(accuracyColor));
|
|
refreshSource();
|
|
}
|
|
|
|
@Override
|
|
public void setLatLng(LatLng latLng) {
|
|
Point point = Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude());
|
|
setLocationPoint(point);
|
|
}
|
|
|
|
@Override
|
|
public void setGpsBearing(Float gpsBearing) {
|
|
setBearingProperty(PROPERTY_GPS_BEARING, gpsBearing);
|
|
}
|
|
|
|
@Override
|
|
public void setCompassBearing(Float compassBearing) {
|
|
setBearingProperty(PROPERTY_COMPASS_BEARING, compassBearing);
|
|
}
|
|
|
|
@Override
|
|
public void setAccuracyRadius(Float accuracy) {
|
|
updateAccuracyRadius(accuracy);
|
|
}
|
|
|
|
@Override
|
|
public void styleScaling(Expression scaleExpression) {
|
|
for (String layerId : layerSet) {
|
|
Layer layer = style.getLayer(layerId);
|
|
if (layer instanceof SymbolLayer) {
|
|
layer.setProperties(
|
|
iconSize(scaleExpression)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setLocationStale(boolean isStale, int renderMode) {
|
|
locationFeature.addBooleanProperty(PROPERTY_LOCATION_STALE, isStale);
|
|
refreshSource();
|
|
if (renderMode != RenderMode.GPS) {
|
|
setLayerVisibility(ACCURACY_LAYER, !isStale);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void updateIconIds(String foregroundIconString, String foregroundStaleIconString, String backgroundIconString,
|
|
String backgroundStaleIconString, String bearingIconString) {
|
|
locationFeature.addStringProperty(PROPERTY_FOREGROUND_ICON, foregroundIconString);
|
|
locationFeature.addStringProperty(PROPERTY_BACKGROUND_ICON, backgroundIconString);
|
|
locationFeature.addStringProperty(PROPERTY_FOREGROUND_STALE_ICON, foregroundStaleIconString);
|
|
locationFeature.addStringProperty(PROPERTY_BACKGROUND_STALE_ICON, backgroundStaleIconString);
|
|
locationFeature.addStringProperty(PROPERTY_BEARING_ICON, bearingIconString);
|
|
refreshSource();
|
|
}
|
|
|
|
@Override
|
|
public void addBitmaps(@RenderMode.Mode int renderMode, @Nullable Bitmap shadowBitmap, Bitmap backgroundBitmap,
|
|
Bitmap backgroundStaleBitmap, Bitmap bearingBitmap,
|
|
Bitmap foregroundBitmap, Bitmap foregroundBitmapStale) {
|
|
if (shadowBitmap != null) {
|
|
style.addImage(SHADOW_ICON, shadowBitmap);
|
|
} else {
|
|
style.removeImage(SHADOW_ICON);
|
|
}
|
|
style.addImage(BACKGROUND_ICON, backgroundBitmap);
|
|
style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap);
|
|
style.addImage(BEARING_ICON, bearingBitmap);
|
|
style.addImage(FOREGROUND_ICON, foregroundBitmap);
|
|
style.addImage(FOREGROUND_STALE_ICON, foregroundBitmapStale);
|
|
}
|
|
|
|
private void updateForegroundOffset(double tilt) {
|
|
JsonArray foregroundJsonArray = new JsonArray();
|
|
foregroundJsonArray.add(0f);
|
|
foregroundJsonArray.add((float) (-0.05 * tilt));
|
|
locationFeature.addProperty(PROPERTY_FOREGROUND_ICON_OFFSET, foregroundJsonArray);
|
|
|
|
JsonArray backgroundJsonArray = new JsonArray();
|
|
backgroundJsonArray.add(0f);
|
|
backgroundJsonArray.add((float) (0.05 * tilt));
|
|
locationFeature.addProperty(PROPERTY_SHADOW_ICON_OFFSET, backgroundJsonArray);
|
|
|
|
refreshSource();
|
|
}
|
|
|
|
private void updateForegroundBearing(float bearing) {
|
|
setBearingProperty(PROPERTY_GPS_BEARING, bearing);
|
|
}
|
|
|
|
private void setLayerVisibility(@NonNull String layerId, boolean visible) {
|
|
Layer layer = style.getLayer(layerId);
|
|
if (layer != null) {
|
|
String targetVisibility = visible ? VISIBLE : NONE;
|
|
if (!layer.getVisibility().value.equals(targetVisibility)) {
|
|
layer.setProperties(visibility(visible ? VISIBLE : NONE));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void addSymbolLayer(@NonNull String layerId, @NonNull String beforeLayerId) {
|
|
Layer layer = layerSourceProvider.generateLayer(layerId);
|
|
addLayerToMap(layer, beforeLayerId);
|
|
}
|
|
|
|
private void addAccuracyLayer() {
|
|
Layer accuracyLayer = layerSourceProvider.generateAccuracyLayer();
|
|
addLayerToMap(accuracyLayer, BACKGROUND_LAYER);
|
|
}
|
|
|
|
private void addLayerToMap(Layer layer, @NonNull String idBelowLayer) {
|
|
style.addLayerBelow(layer, idBelowLayer);
|
|
layerSet.add(layer.getId());
|
|
}
|
|
|
|
private void addLocationSource() {
|
|
locationSource = layerSourceProvider.generateSource(locationFeature);
|
|
style.addSource(locationSource);
|
|
}
|
|
|
|
private void refreshSource() {
|
|
GeoJsonSource source = style.getSourceAs(LOCATION_SOURCE);
|
|
if (source != null) {
|
|
locationSource.setGeoJson(locationFeature);
|
|
}
|
|
}
|
|
|
|
private void setLocationPoint(Point locationPoint) {
|
|
JsonObject properties = locationFeature.properties();
|
|
if (properties != null) {
|
|
locationFeature = Feature.fromGeometry(locationPoint, properties);
|
|
refreshSource();
|
|
}
|
|
}
|
|
|
|
private void setBearingProperty(@NonNull String propertyId, float bearing) {
|
|
locationFeature.addNumberProperty(propertyId, bearing);
|
|
refreshSource();
|
|
}
|
|
|
|
private void updateAccuracyRadius(float accuracy) {
|
|
locationFeature.addNumberProperty(PROPERTY_ACCURACY_RADIUS, accuracy);
|
|
refreshSource();
|
|
}
|
|
}
|