summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobrun <tobrun.van.nuland@gmail.com>2017-12-20 16:44:21 +0100
committerTobrun <tobrun.van.nuland@gmail.com>2018-02-20 17:08:56 +0100
commit78adfeddb9e81b9dfa8897d85c42ddfd3c1780f2 (patch)
tree0b0346a6151cc2d1afe855e7e235c5ad7ad02cbc
parent374bad18c04ae8fea574f85d2149af8aeffb8dcc (diff)
downloadqtlocation-mapboxgl-upstream/tvn-animated-symbols.tar.gz
[android] - port animated markers activity to symbol layerupstream/tvn-animated-symbols
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java283
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedSymbolLayerActivity.java449
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml2
-rw-r--r--platform/android/scripts/exclude-activity-gen.json2
7 files changed, 459 insertions, 293 deletions
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 5a0493e5bd..9d7e21024c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -69,12 +69,12 @@
android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
- android:name=".activity.annotation.AnimatedMarkerActivity"
- android:description="@string/description_animated_marker"
- android:label="@string/activity_animated_marker">
+ android:name=".activity.annotation.AnimatedSymbolLayerActivity"
+ android:description="@string/description_animated_symbollayer"
+ android:label="@string/activity_animated_symbollayer">
<meta-data
android:name="@string/category"
- android:value="@string/category_annotation"/>
+ android:value="@string/category_style"/>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity"/>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
deleted file mode 100644
index e6db071141..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
+++ /dev/null
@@ -1,283 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.annotation;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.TypeEvaluator;
-import android.animation.ValueAnimator;
-import android.os.Bundle;
-import android.support.annotation.DrawableRes;
-import android.support.v4.content.res.ResourcesCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.animation.AccelerateDecelerateInterpolator;
-
-import com.mapbox.geojson.Point;
-import com.mapbox.mapboxsdk.annotations.Icon;
-import com.mapbox.mapboxsdk.annotations.IconFactory;
-import com.mapbox.mapboxsdk.annotations.Marker;
-import com.mapbox.mapboxsdk.annotations.MarkerView;
-import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
-import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.geometry.LatLngBounds;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
-import com.mapbox.turf.TurfMeasurement;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-/**
- * Test activity showcasing animating MarkerViews.
- */
-public class AnimatedMarkerActivity extends AppCompatActivity {
-
- private MapView mapView;
- private MapboxMap mapboxMap;
-
- private LatLng dupontCircle = new LatLng(38.90962, -77.04341);
-
- private Marker passengerMarker = null;
- private MarkerView carMarker = null;
-
- private Runnable animationRunnable;
-
- private List<MarkerView> markerViews = new ArrayList<>();
- private boolean stopped;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_animated_marker);
-
- mapView = (MapView) findViewById(R.id.mapView);
- mapView.onCreate(savedInstanceState);
- mapView.getMapAsync(mapboxMap -> {
- AnimatedMarkerActivity.this.mapboxMap = mapboxMap;
- setupMap();
-
- animationRunnable = () -> {
- for (int i = 0; i < 10; i++) {
- addRandomCar();
- }
- addPassenger();
- addMainCar();
- };
- mapView.post(animationRunnable);
- });
- }
-
- private void setupMap() {
- CameraPosition cameraPosition = new CameraPosition.Builder()
- .target(dupontCircle)
- .zoom(15)
- .build();
- mapboxMap.setCameraPosition(cameraPosition);
- }
-
- private void addPassenger() {
- if (isActivityStopped()) {
- return;
- }
-
- LatLng randomLatLng = getLatLngInBounds();
-
- if (passengerMarker == null) {
- Icon icon = IconUtils.drawableToIcon(this, R.drawable.ic_directions_run_black,
- ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme()));
- passengerMarker = mapboxMap.addMarker(new MarkerViewOptions()
- .position(randomLatLng)
- .icon(icon));
- } else {
- passengerMarker.setPosition(randomLatLng);
- }
- }
-
- private void addMainCar() {
- if (isActivityStopped()) {
- return;
- }
-
- LatLng randomLatLng = getLatLngInBounds();
-
- if (carMarker == null) {
- carMarker = createCarMarker(randomLatLng, R.drawable.ic_taxi_top,
- markerView -> {
- // Make sure the car marker is selected so that it's always brought to the front (#5285)
- mapboxMap.selectMarker(carMarker);
- animateMoveToPassenger(carMarker);
- });
- markerViews.add(carMarker);
- } else {
- carMarker.setPosition(randomLatLng);
- }
- }
-
- private void animateMoveToPassenger(final MarkerView car) {
- if (isActivityStopped()) {
- return;
- }
-
- ValueAnimator animator = animateMoveMarker(car, passengerMarker.getPosition());
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- addPassenger();
- animateMoveToPassenger(car);
- }
- });
- }
-
- protected void addRandomCar() {
- markerViews.add(createCarMarker(getLatLngInBounds(), R.drawable.ic_car_top,
- markerView -> randomlyMoveMarker(markerView)));
- }
-
- private void randomlyMoveMarker(final MarkerView marker) {
- if (isActivityStopped()) {
- return;
- }
-
- ValueAnimator animator = animateMoveMarker(marker, getLatLngInBounds());
-
- // Add listener to restart animation on end
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- randomlyMoveMarker(marker);
- }
- });
- }
-
- private ValueAnimator animateMoveMarker(final MarkerView marker, LatLng to) {
- marker.setRotation((float) getBearing(marker.getPosition(), to));
-
- final ValueAnimator markerAnimator = ObjectAnimator.ofObject(
- marker, "position", new LatLngEvaluator(), marker.getPosition(), to);
- markerAnimator.setDuration((long) (10 * marker.getPosition().distanceTo(to)));
- markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
-
- // Start
- markerAnimator.start();
-
- return markerAnimator;
- }
-
- private MarkerView createCarMarker(LatLng start, @DrawableRes int carResource,
- MarkerViewManager.OnMarkerViewAddedListener listener) {
- Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this)
- .fromResource(carResource);
-
- // View Markers
- return mapboxMap.addMarker(new MarkerViewOptions()
- .position(start)
- .icon(icon), listener);
-
- // GL Markers
-// return mapboxMap.addMarker(new MarkerOptions()
-// .position(start)
-// .icon(icon));
-
- }
-
- private LatLng getLatLngInBounds() {
- LatLngBounds bounds = mapboxMap.getProjection().getVisibleRegion().latLngBounds;
- Random generator = new Random();
- double randomLat = bounds.getLatSouth() + generator.nextDouble()
- * (bounds.getLatNorth() - bounds.getLatSouth());
- double randomLon = bounds.getLonWest() + generator.nextDouble()
- * (bounds.getLonEast() - bounds.getLonWest());
- return new LatLng(randomLat, randomLon);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- mapView.onStart();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mapView.onResume();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mapView.onPause();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
-
- stopped = true;
-
- // Stop ongoing animations, prevent memory leaks
- if (mapboxMap != null) {
- MarkerViewManager markerViewManager = mapboxMap.getMarkerViewManager();
- for (MarkerView markerView : markerViews) {
- View view = markerViewManager.getView(markerView);
- if (view != null) {
- view.animate().cancel();
- }
- }
- }
-
- // onStop
- mapView.onStop();
- mapView.removeCallbacks(animationRunnable);
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- mapView.onSaveInstanceState(outState);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mapView.onDestroy();
- }
-
- @Override
- public void onLowMemory() {
- super.onLowMemory();
- mapView.onLowMemory();
- }
-
- /**
- * Evaluator for LatLng pairs
- */
- private static class LatLngEvaluator implements TypeEvaluator<LatLng> {
-
- private LatLng latLng = new LatLng();
-
- @Override
- public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
- latLng.setLatitude(startValue.getLatitude()
- + ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
- latLng.setLongitude(startValue.getLongitude()
- + ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
- return latLng;
- }
- }
-
- private double getBearing(LatLng from, LatLng to) {
- return TurfMeasurement.bearing(
- Point.fromLngLat(from.getLongitude(), from.getLatitude()),
- Point.fromLngLat(to.getLongitude(), to.getLatitude())
- );
- }
-
- private boolean isActivityStopped() {
- return stopped;
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedSymbolLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedSymbolLayerActivity.java
new file mode 100644
index 0000000000..97957720fc
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedSymbolLayerActivity.java
@@ -0,0 +1,449 @@
+package com.mapbox.mapboxsdk.testapp.activity.annotation;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TypeEvaluator;
+import android.animation.ValueAnimator;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+
+import com.google.gson.JsonObject;
+import com.mapbox.geojson.Feature;
+import com.mapbox.geojson.FeatureCollection;
+import com.mapbox.geojson.Point;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.turf.TurfMeasurement;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import static com.mapbox.mapboxsdk.style.functions.Function.property;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconRotate;
+
+/**
+ * Test activity showcasing animating MarkerViews.
+ */
+public class AnimatedSymbolLayerActivity extends AppCompatActivity {
+
+ private static final String PASSENGER = "passenger";
+ private static final String PASSENGER_LAYER = "passenger-layer";
+ private static final String PASSENGER_SOURCE = "passenger-source";
+ private static final String TAXI = "taxi";
+ private static final String TAXI_LAYER = "taxi-layer";
+ private static final String TAXI_SOURCE = "taxi-source";
+ private static final String RANDOM_CAR_LAYER = "random-car-layer";
+ private static final String RANDOM_CAR_SOURCE = "random-car-source";
+ private static final String RANDOM_CAR_IMAGE_ID = "random-car";
+ private static final String PROPERTY_BEARING = "bearing";
+ private static final String WATERWAY_LAYER_ID = "waterway-label";
+ private static final int DURATION_RANDOM_MAX = 1500;
+ private static final int DURATION_BASE = 3000;
+
+ private final Random random = new Random();
+
+ private MapView mapView;
+ private MapboxMap mapboxMap;
+
+ private List<Car> randomCars = new ArrayList<>();
+ private GeoJsonSource randomCarSource;
+ private Car taxi;
+ private GeoJsonSource taxiSource;
+ private LatLng passenger;
+
+ private List<Animator> animators = new ArrayList<>();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_animated_marker);
+
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(mapboxMap -> {
+ AnimatedSymbolLayerActivity.this.mapboxMap = mapboxMap;
+ setupCars();
+ animateRandomRoutes();
+ animateTaxi();
+ });
+ }
+
+ private void setupCars() {
+ addRandomCars();
+ addPassenger();
+ addMainCar();
+ }
+
+ private void animateRandomRoutes() {
+ final Car longestDrive = getLongestDrive();
+ final Random random = new Random();
+ for (final Car car : randomCars) {
+ final boolean isLongestDrive = longestDrive.equals(car);
+ ValueAnimator valueAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), car.current, car.next);
+ valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+
+ private LatLng latLng;
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ latLng = (LatLng) animation.getAnimatedValue();
+ car.current = latLng;
+ if (isLongestDrive) {
+ updateRandomCarSource();
+ }
+ }
+ });
+
+ if (isLongestDrive) {
+ valueAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ updateRandomDestinations();
+ animateRandomRoutes();
+ }
+ });
+ }
+
+ valueAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ car.feature.properties().addProperty("bearing", Car.getBearing(car.current, car.next));
+ }
+ });
+
+ int offset = random.nextInt(2) == 0 ? 0 : random.nextInt(1000) + 250;
+ valueAnimator.setStartDelay(offset);
+ valueAnimator.setDuration(car.duration - offset);
+ valueAnimator.setInterpolator(new LinearInterpolator());
+ valueAnimator.start();
+
+ animators.add(valueAnimator);
+ }
+ }
+
+ private void animateTaxi() {
+ ValueAnimator valueAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), taxi.current, taxi.next);
+ valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+
+ private LatLng latLng;
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ latLng = (LatLng) animation.getAnimatedValue();
+ taxi.current = latLng;
+ updateTaxiSource();
+ }
+ });
+
+ valueAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ updatePassenger();
+ animateTaxi();
+ }
+ });
+
+ valueAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ taxi.feature.properties().addProperty("bearing", Car.getBearing(taxi.current, taxi.next));
+ }
+ });
+
+ valueAnimator.setDuration((long) (7 * taxi.current.distanceTo(taxi.next)));
+ valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
+ valueAnimator.start();
+
+ animators.add(valueAnimator);
+ }
+
+ private void updatePassenger() {
+ passenger = getLatLngInBounds();
+ updatePassengerSource();
+ taxi.setNext(passenger);
+ }
+
+ private void updatePassengerSource() {
+ GeoJsonSource source = mapboxMap.getSourceAs(PASSENGER_SOURCE);
+ FeatureCollection featureCollection = FeatureCollection.fromFeatures(new Feature[] {
+ Feature.fromGeometry(
+ Point.fromLngLat(
+ passenger.getLongitude(),
+ passenger.getLatitude()
+ )
+ )
+ });
+ source.setGeoJson(featureCollection);
+ }
+
+ private void updateTaxiSource() {
+ taxi.updateFeature();
+ taxiSource.setGeoJson(taxi.feature);
+ }
+
+ private void updateRandomDestinations() {
+ for (Car randomCar : randomCars) {
+ randomCar.setNext(getLatLngInBounds());
+ }
+ }
+
+ private Car getLongestDrive() {
+ Car longestDrive = null;
+ for (Car randomCar : randomCars) {
+ if (longestDrive == null) {
+ longestDrive = randomCar;
+ } else if (longestDrive.duration < randomCar.duration) {
+ longestDrive = randomCar;
+ }
+ }
+ return longestDrive;
+ }
+
+ private void updateRandomCarSource() {
+ for (Car randomCarsRoute : randomCars) {
+ randomCarsRoute.updateFeature();
+ }
+ randomCarSource.setGeoJson(featuresFromRoutes());
+ }
+
+ private FeatureCollection featuresFromRoutes() {
+ List<Feature> features = new ArrayList<>();
+ for (Car randomCarsRoute : randomCars) {
+ features.add(randomCarsRoute.feature);
+ }
+ return FeatureCollection.fromFeatures(features);
+ }
+
+ private long getDuration() {
+ return random.nextInt(DURATION_RANDOM_MAX) + DURATION_BASE;
+ }
+
+ private void addRandomCars() {
+ LatLng latLng;
+ LatLng next;
+ for (int i = 0; i < 10; i++) {
+ latLng = getLatLngInBounds();
+ next = getLatLngInBounds();
+
+ JsonObject properties = new JsonObject();
+ properties.addProperty(PROPERTY_BEARING, Car.getBearing(latLng, next));
+
+ Feature feature = Feature.fromGeometry(
+ Point.fromLngLat(
+ latLng.getLongitude(),
+ latLng.getLatitude()
+ ), properties);
+
+ randomCars.add(
+ new Car(feature, next, getDuration())
+ );
+ }
+
+ randomCarSource = new GeoJsonSource(RANDOM_CAR_SOURCE, featuresFromRoutes());
+ mapboxMap.addSource(randomCarSource);
+ mapboxMap.addImage(RANDOM_CAR_IMAGE_ID,
+ ((BitmapDrawable) getResources().getDrawable(R.drawable.ic_car_top)).getBitmap());
+
+ SymbolLayer symbolLayer = new SymbolLayer(RANDOM_CAR_LAYER, RANDOM_CAR_SOURCE);
+ symbolLayer.withProperties(
+ iconImage(RANDOM_CAR_IMAGE_ID),
+ iconAllowOverlap(true),
+ iconRotate(
+ property(
+ PROPERTY_BEARING,
+ Stops.<Float>identity()
+ )
+ ),
+ iconIgnorePlacement(true)
+ );
+
+ mapboxMap.addLayerBelow(symbolLayer, WATERWAY_LAYER_ID);
+ }
+
+ private void addPassenger() {
+ passenger = getLatLngInBounds();
+ FeatureCollection featureCollection = FeatureCollection.fromFeatures(new Feature[] {
+ Feature.fromGeometry(
+ Point.fromLngLat(
+ passenger.getLongitude(),
+ passenger.getLatitude()
+ )
+ )
+ });
+
+ mapboxMap.addImage(PASSENGER,
+ ((BitmapDrawable) getResources().getDrawable(R.drawable.icon_burned)).getBitmap());
+
+ GeoJsonSource geoJsonSource = new GeoJsonSource(PASSENGER_SOURCE, featureCollection);
+ mapboxMap.addSource(geoJsonSource);
+
+ SymbolLayer symbolLayer = new SymbolLayer(PASSENGER_LAYER, PASSENGER_SOURCE);
+ symbolLayer.withProperties(
+ iconImage(PASSENGER),
+ iconIgnorePlacement(true),
+ iconAllowOverlap(true)
+ );
+ mapboxMap.addLayerBelow(symbolLayer, RANDOM_CAR_LAYER);
+ }
+
+ private void addMainCar() {
+ LatLng latLng = getLatLngInBounds();
+ JsonObject properties = new JsonObject();
+ properties.addProperty(PROPERTY_BEARING, Car.getBearing(latLng, passenger));
+ Feature feature = Feature.fromGeometry(
+ Point.fromLngLat(
+ latLng.getLongitude(),
+ latLng.getLatitude()), properties);
+ FeatureCollection featureCollection = FeatureCollection.fromFeatures(new Feature[] {feature});
+
+ taxi = new Car(feature, passenger, getDuration());
+ mapboxMap.addImage(TAXI,
+ ((BitmapDrawable) getResources().getDrawable(R.drawable.ic_taxi_top)).getBitmap());
+ taxiSource = new GeoJsonSource(TAXI_SOURCE, featureCollection);
+ mapboxMap.addSource(taxiSource);
+
+ SymbolLayer symbolLayer = new SymbolLayer(TAXI_LAYER, TAXI_SOURCE);
+ symbolLayer.withProperties(
+ iconImage(TAXI),
+ iconRotate(
+ property(
+ PROPERTY_BEARING,
+ Stops.<Float>identity()
+ )
+ ),
+ iconAllowOverlap(true),
+ iconIgnorePlacement(true)
+
+ );
+ mapboxMap.addLayer(symbolLayer);
+ }
+
+ private LatLng getLatLngInBounds() {
+ LatLngBounds bounds = mapboxMap.getProjection().getVisibleRegion().latLngBounds;
+ Random generator = new Random();
+ double randomLat = bounds.getLatSouth() + generator.nextDouble()
+ * (bounds.getLatNorth() - bounds.getLatSouth());
+ double randomLon = bounds.getLonWest() + generator.nextDouble()
+ * (bounds.getLonEast() - bounds.getLonWest());
+ return new LatLng(randomLat, randomLon);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ for (Animator animator : animators) {
+ if (animator != null) {
+ animator.removeAllListeners();
+ animator.cancel();
+ }
+ }
+
+ mapView.onDestroy();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mapView.onLowMemory();
+ }
+
+ /**
+ * Evaluator for LatLng pairs
+ */
+ private static class LatLngEvaluator implements TypeEvaluator<LatLng> {
+
+ private LatLng latLng = new LatLng();
+
+ @Override
+ public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
+ latLng.setLatitude(startValue.getLatitude()
+ + ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
+ latLng.setLongitude(startValue.getLongitude()
+ + ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
+ return latLng;
+ }
+ }
+
+
+ private static class Car {
+ private Feature feature;
+ private LatLng next;
+ private LatLng current;
+ private long duration;
+
+ Car(Feature feature, LatLng next, long duration) {
+ this.feature = feature;
+ Point point = ((Point) feature.geometry());
+ this.current = new LatLng(point.latitude(), point.longitude());
+ this.duration = duration;
+ this.next = next;
+ }
+
+ void setNext(LatLng next) {
+ this.next = next;
+ }
+
+ void updateFeature() {
+ feature = Feature.fromGeometry(Point.fromLngLat(
+ current.getLongitude(),
+ current.getLatitude())
+ );
+ feature.properties().addProperty("bearing", getBearing(current, next));
+ }
+
+ private static float getBearing(LatLng from, LatLng to) {
+ return (float) TurfMeasurement.bearing(
+ Point.fromLngLat(from.getLongitude(), from.getLatitude()),
+ Point.fromLngLat(to.getLongitude(), to.getLatitude())
+ );
+ }
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
index 0566757d58..252af714e7 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
@@ -10,9 +10,9 @@
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:mapbox_cameraTargetLat="51.502615"
- app:mapbox_cameraTargetLng="4.972326"
- app:mapbox_cameraZoom="6"
+ app:mapbox_cameraTargetLat="38.90962"
+ app:mapbox_cameraTargetLng="-77.04341"
+ app:mapbox_cameraZoom="15"
app:mapbox_styleUrl="@string/mapbox_style_light"/>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
index d17ec20546..9d44ada937 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
@@ -24,7 +24,7 @@
<string name="description_offline">Offline Map example</string>
<string name="description_update_metadata">Update metadata example</string>
<string name="description_offline_region_delete">Delete region example</string>
- <string name="description_animated_marker">Animate the position change of a marker</string>
+ <string name="description_animated_symbollayer">Animate the position change of a symbol layer</string>
<string name="description_polyline">Add a polyline to a map</string>
<string name="description_polygon">Add a polygon to a map</string>
<string name="description_scroll_by">Scroll with pixels in x,y direction</string>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
index 0323d7c428..352d7884a6 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
@@ -4,7 +4,7 @@
<string name="activity_map_fragment">Map Fragment</string>
<string name="activity_multimap">Multiple Maps on Screen</string>
<string name="activity_add_bulk_markers">Add Markers In Bulk</string>
- <string name="activity_animated_marker">Animated Markers</string>
+ <string name="activity_animated_symbollayer">Animated SymbolLayer</string>
<string name="activity_dynamic_marker">Dynamic Marker</string>
<string name="activity_polyline">Polyline</string>
<string name="activity_polygon">Polygon</string>
diff --git a/platform/android/scripts/exclude-activity-gen.json b/platform/android/scripts/exclude-activity-gen.json
index c1a6b5bb48..b2278c9d63 100644
--- a/platform/android/scripts/exclude-activity-gen.json
+++ b/platform/android/scripts/exclude-activity-gen.json
@@ -18,7 +18,7 @@
"LocationPickerActivity",
"GeoJsonClusteringActivity",
"RuntimeStyleTestActivity",
- "AnimatedMarkerActivity",
+ "AnimatedSymbolLayerActivity",
"ViewPagerActivity",
"MapFragmentActivity",
"SupportMapFragmentActivity",