From e4a40fe7974462369533722a20d252b753a55347 Mon Sep 17 00:00:00 2001 From: Osana Babayan <32496536+osana@users.noreply.github.com> Date: Thu, 15 Feb 2018 12:02:00 -0500 Subject: [android] bounds can go over the antimeridian / date line. (#10892) --- .../mapboxsdk/constants/GeometryConstants.java | 14 +++ .../mapbox/mapboxsdk/geometry/LatLngBounds.java | 112 ++++++++++++++---- .../mapboxsdk/geometry/LatLngBoundsTest.java | 131 +++++++++++++++++++++ 3 files changed, 236 insertions(+), 21 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java index 1a7544d33a..7a17e500ca 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java @@ -36,6 +36,20 @@ public class GeometryConstants { */ public static final double MIN_LATITUDE = -90; + /** + * This constant represents the latitude span when representing a geolocation. + * + * @since 6.0.0 + */ + public static final double LATITUDE_SPAN = 180; + + /** + * This constant represents the longitude span when representing a geolocation. + * + * @since 6.0.0 + */ + public static final double LONGITUDE_SPAN = 360; + /** * This constant represents the highest latitude value available to represent a geolocation. * diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index cf647224ae..fc8d2ec8f0 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -29,6 +29,10 @@ public class LatLngBounds implements Parcelable { * Construct a new LatLngBounds based on its corners, given in NESW * order. * + * If eastern longitude is smaller than the western one, bounds will include antimeridian. + * For example, if the NE point is (10, -170) and the SW point is (-10, 170), then bounds will span over 20 degrees + * and cross the antimeridian. + * * @param northLatitude Northern Latitude * @param eastLongitude Eastern Longitude * @param southLatitude Southern Latitude @@ -48,10 +52,9 @@ public class LatLngBounds implements Parcelable { * @return the bounds representing the world */ public static LatLngBounds world() { - return new LatLngBounds.Builder() - .include(new LatLng(GeometryConstants.MAX_LATITUDE, GeometryConstants.MAX_LONGITUDE)) - .include(new LatLng(GeometryConstants.MIN_LATITUDE, GeometryConstants.MIN_LONGITUDE)) - .build(); + return LatLngBounds.from( + GeometryConstants.MAX_LATITUDE, GeometryConstants.MAX_LONGITUDE, + GeometryConstants.MIN_LATITUDE, GeometryConstants.MIN_LONGITUDE); } /** @@ -61,8 +64,21 @@ public class LatLngBounds implements Parcelable { * @return LatLng center of this LatLngBounds */ public LatLng getCenter() { - return new LatLng((this.latitudeNorth + this.latitudeSouth) / 2, - (this.longitudeEast + this.longitudeWest) / 2); + double latCenter = (this.latitudeNorth + this.latitudeSouth) / 2.0; + double longCenter; + + if (this.longitudeEast > this.longitudeWest) { + longCenter = (this.longitudeEast + this.longitudeWest) / 2; + } else { + double halfSpan = (GeometryConstants.LONGITUDE_SPAN + this.longitudeEast - this.longitudeWest) / 2.0; + longCenter = this.longitudeWest + halfSpan; + if (longCenter >= GeometryConstants.MAX_LONGITUDE) { + longCenter = this.longitudeEast - halfSpan; + } + return new LatLng(latCenter, longCenter); + } + + return new LatLng(latCenter, longCenter); } /** @@ -163,10 +179,26 @@ public class LatLngBounds implements Parcelable { * @return Span distance */ public double getLongitudeSpan() { - return Math.abs(this.longitudeEast - this.longitudeWest); + double longSpan = Math.abs(this.longitudeEast - this.longitudeWest); + if (this.longitudeEast > this.longitudeWest) { + return longSpan; + } + + // shortest span contains antimeridian + return GeometryConstants.LONGITUDE_SPAN - longSpan; } + static double getLongitudeSpan(final double longEast, final double longWest) { + double longSpan = Math.abs(longEast - longWest); + if (longEast > longWest) { + return longSpan; + } + + // shortest span contains antimeridian + return GeometryConstants.LONGITUDE_SPAN - longSpan; + } + /** * Validate if LatLngBounds is empty, determined if absolute distance is * @@ -196,21 +228,44 @@ public class LatLngBounds implements Parcelable { */ static LatLngBounds fromLatLngs(final List latLngs) { double minLat = GeometryConstants.MAX_LATITUDE; - double minLon = GeometryConstants.MAX_LONGITUDE; double maxLat = GeometryConstants.MIN_LATITUDE; - double maxLon = GeometryConstants.MIN_LONGITUDE; + + double eastLon = latLngs.get(0).getLongitude(); + double westLon = latLngs.get(1).getLongitude(); + double lonSpan = Math.abs(eastLon - westLon); + if (lonSpan < GeometryConstants.LONGITUDE_SPAN / 2) { + if (eastLon < westLon) { + double temp = eastLon; + eastLon = westLon; + westLon = temp; + } + } else { + lonSpan = GeometryConstants.LONGITUDE_SPAN - lonSpan; + if (westLon < eastLon) { + double temp = eastLon; + eastLon = westLon; + westLon = temp; + } + } for (final ILatLng gp : latLngs) { final double latitude = gp.getLatitude(); - final double longitude = gp.getLongitude(); - minLat = Math.min(minLat, latitude); - minLon = Math.min(minLon, longitude); maxLat = Math.max(maxLat, latitude); - maxLon = Math.max(maxLon, longitude); + + final double longitude = gp.getLongitude(); + if (!containsLongitude(eastLon, westLon, longitude)) { + final double eastSpan = getLongitudeSpan(longitude, westLon); + final double westSpan = getLongitudeSpan(eastLon, longitude); + if (eastSpan <= westSpan) { + eastLon = longitude; + } else { + westLon = longitude; + } + } } - return new LatLngBounds(maxLat, maxLon, minLat, minLon); + return new LatLngBounds(maxLat, eastLon, minLat, westLon); } /** @@ -322,6 +377,24 @@ public class LatLngBounds implements Parcelable { return false; } + + private boolean containsLatitude(final double latitude) { + return (latitude <= this.latitudeNorth) + && (latitude >= this.latitudeSouth); + } + + private boolean containsLongitude(final double longitude) { + return containsLongitude(this.longitudeEast, this.longitudeWest, longitude); + } + + static boolean containsLongitude(final double eastLon, final double westLon, final double longitude) { + if (eastLon > westLon) { + return (longitude <= eastLon) + && (longitude >= westLon); + } + return (longitude < eastLon) || (longitude > westLon); + } + /** * Determines whether this LatLngBounds contains a point. * @@ -329,12 +402,8 @@ public class LatLngBounds implements Parcelable { * @return true, if the point is contained within the bounds */ public boolean contains(final ILatLng latLng) { - final double latitude = latLng.getLatitude(); - final double longitude = latLng.getLongitude(); - return ((latitude <= this.latitudeNorth) - && (latitude >= this.latitudeSouth)) - && ((longitude <= this.longitudeEast) - && (longitude >= this.longitudeWest)); + return containsLatitude(latLng.getLatitude()) + && containsLongitude(latLng.getLongitude()); } /** @@ -344,7 +413,8 @@ public class LatLngBounds implements Parcelable { * @return true, if the bounds is contained within the bounds */ public boolean contains(final LatLngBounds other) { - return contains(other.getNorthEast()) && contains(other.getSouthWest()); + return contains(other.getNorthEast()) + && contains(other.getSouthWest()); } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java index e6c1fdd0cf..f03bbdb11c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java @@ -70,6 +70,82 @@ public class LatLngBoundsTest { assertEquals("LatLngSpan should be the same", new LatLngSpan(2, 2), latLngSpan); } + @Test + public void dateLineSpanBuilder1() { + latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, -170)) + .include(new LatLng(-10, 170)) + .build(); + + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be shortest distance", new LatLngSpan(20, 20), + latLngSpan); + } + + @Test + public void dateLineSpanBuilder2() { + latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(-10, -170)) + .include(new LatLng(10, 170)) + .build(); + + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be shortest distance", new LatLngSpan(20, 20), + latLngSpan); + } + + @Test + public void dateLineSpanFrom1() { + latLngBounds = LatLngBounds.from(10, -170, -10, 170); + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be shortest distance", new LatLngSpan(20, 20), + latLngSpan); + } + + @Test + public void dateLineSpanFrom2() { + latLngBounds = LatLngBounds.from(10, 170, -10, -170); + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be shortest distance", new LatLngSpan(20, 340), + latLngSpan); + } + + @Test + public void nearDateLineCenter1() { + latLngBounds = LatLngBounds.from(10, -175, -10, 165); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, 175), center); + } + + @Test + public void nearDateLineCenter2() { + latLngBounds = LatLngBounds.from(10, -165, -10, 175); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, -175), center); + } + + @Test + public void nearDateLineCenter3() { + latLngBounds = LatLngBounds.from(10, -170, -10, 170); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, -180), center); + } + + @Test + public void nearDateLineCenter4() { + latLngBounds = LatLngBounds.from(10, -180, -10, 0); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, 90), center); + } + + @Test + public void nearDateLineCenter5() { + latLngBounds = LatLngBounds.from(10, 180, -10, 0); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, 90), center); + } + + @Test public void center() { LatLng center = latLngBounds.getCenter(); @@ -120,6 +196,46 @@ public class LatLngBoundsTest { assertEquals("LatLngBounds should match", latLngBounds1, latLngBounds2); } + @Test + public void includesOverDateline1() { + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, -170)) + .include(new LatLng(-10, -175)) + .include(new LatLng(0, 170)) + .build(); + + assertEquals("LatLngSpan should be the same", + new LatLngSpan(20, 20), latLngBounds.getSpan()); + } + + @Test + public void includesOverDateline2() { + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, 170)) + .include(new LatLng(-10, 175)) + .include(new LatLng(0, -170)) + .build(); + + assertEquals("LatLngSpan should be the same", + new LatLngSpan(20, 20), latLngBounds.getSpan()); + } + + @Test + public void includesOverDateline3() { + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, 170)) + .include(new LatLng(-10, -170)) + .include(new LatLng(0, -180)) + .include(new LatLng(5, 180)) + .build(); + + assertEquals("LatLngSpan should be the same", + new LatLngSpan(20, 20), latLngBounds.getSpan()); + } + @Test public void containsNot() { assertFalse("LatLng should not be included", latLngBounds.contains(new LatLng(3, 1))); @@ -130,6 +246,21 @@ public class LatLngBoundsTest { assertTrue("LatLngBounds should be contained in the world", LatLngBounds.world().contains(latLngBounds)); } + @Test + public void worldSpan() { + assertEquals("LatLngBounds world span should be 180, 360", + GeometryConstants.LATITUDE_SPAN, LatLngBounds.world().getLatitudeSpan(), DELTA); + assertEquals("LatLngBounds world span should be 180, 360", + GeometryConstants.LONGITUDE_SPAN, LatLngBounds.world().getLongitudeSpan(), DELTA); + } + + @Test + public void emptySpan() { + LatLngBounds latLngBounds = LatLngBounds.from(GeometryConstants.MIN_LATITUDE, GeometryConstants.MAX_LONGITUDE, + GeometryConstants.MIN_LATITUDE, GeometryConstants.MAX_LONGITUDE); + assertTrue("LatLngBounds empty span", latLngBounds.isEmptySpan()); + } + @Test public void containsBounds() { LatLngBounds inner = new LatLngBounds.Builder() -- cgit v1.2.1 From 341eb7645f98fb1835607dbe68b2bd74b0f6ec8a Mon Sep 17 00:00:00 2001 From: Osana Babayan <32496536+osana@users.noreply.github.com> Date: Fri, 16 Feb 2018 09:36:56 -0500 Subject: [android] incorrect LatLngBounds for the VisibleRegion for rotated map smallest bounding box for 4 points cannot be created using LatLngBounds.fromLatLngs() as the order matters in that method and that does not work for rotated map --- .../src/main/java/com/mapbox/mapboxsdk/maps/Projection.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java index 16c73b1ca5..ae559189ad 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java @@ -104,11 +104,12 @@ public class Projection { LatLng bottomLeft = fromScreenLocation(new PointF(left, bottom)); return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, - LatLngBounds.from( - topRight.getLatitude(), - topRight.getLongitude(), - bottomLeft.getLatitude(), - bottomLeft.getLongitude()) + new LatLngBounds.Builder() + .include(topRight) + .include(bottomLeft) + .include(bottomRight) + .include(topLeft) + .build() ); } -- cgit v1.2.1 From d0f66b132f263fda9c0ca40053253fae20cb06ec Mon Sep 17 00:00:00 2001 From: Osana Babayan <32496536+osana@users.noreply.github.com> Date: Mon, 19 Feb 2018 12:08:35 -0500 Subject: [android] added missing delete local references --- .../android/src/geojson/feature_collection.cpp | 25 ++++++++++++--------- platform/android/src/geojson/line_string.cpp | 3 ++- platform/android/src/geojson/multi_polygon.cpp | 2 +- platform/android/src/geojson/point.cpp | 26 ++++++++++++++-------- 4 files changed, 35 insertions(+), 21 deletions(-) (limited to 'platform/android') diff --git a/platform/android/src/geojson/feature_collection.cpp b/platform/android/src/geojson/feature_collection.cpp index 59f1e317e6..06f8f10b9a 100644 --- a/platform/android/src/geojson/feature_collection.cpp +++ b/platform/android/src/geojson/feature_collection.cpp @@ -1,3 +1,4 @@ +#include #include "feature_collection.hpp" #include "feature.hpp" @@ -7,19 +8,23 @@ namespace android { namespace geojson { mbgl::FeatureCollection FeatureCollection::convert(jni::JNIEnv& env, jni::Object jCollection) { - auto jFeatureList = FeatureCollection::features(env, jCollection); - auto jFeatures = java::util::List::toArray(env, jFeatureList); - auto size = size_t(jFeatures.Length(env)); - auto collection = mbgl::FeatureCollection(); - collection.reserve(size); - for (size_t i = 0; i < size; i++) { - auto jFeature = jFeatures.Get(env, i); - collection.push_back(Feature::convert(env, jFeature)); - jni::DeleteLocalRef(env, jFeature); - } + if (jCollection) { + auto jFeatureList = FeatureCollection::features(env, jCollection); + auto jFeatures = java::util::List::toArray(env, jFeatureList); + auto size = size_t(jFeatures.Length(env)); + collection.reserve(size); + for (size_t i = 0; i < size; i++) { + auto jFeature = jFeatures.Get(env, i); + collection.push_back(Feature::convert(env, jFeature)); + jni::DeleteLocalRef(env, jFeature); + } + + jni::DeleteLocalRef(env, jFeatures); + jni::DeleteLocalRef(env, jFeatureList); + } return collection; } diff --git a/platform/android/src/geojson/line_string.cpp b/platform/android/src/geojson/line_string.cpp index 9e99c72c4c..8eebd53550 100644 --- a/platform/android/src/geojson/line_string.cpp +++ b/platform/android/src/geojson/line_string.cpp @@ -23,8 +23,9 @@ mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object(env, jPointList); - auto size = jPointArray.Length(env); + lineString.reserve(size); + for (std::size_t i = 0; i < size; i++) { auto jPoint = jPointArray.Get(env, i); lineString.push_back(Point::convert(env, jPoint)); diff --git a/platform/android/src/geojson/multi_polygon.cpp b/platform/android/src/geojson/multi_polygon.cpp index f4eb0f6b2a..aadba8c8a6 100644 --- a/platform/android/src/geojson/multi_polygon.cpp +++ b/platform/android/src/geojson/multi_polygon.cpp @@ -22,8 +22,8 @@ mapbox::geojson::multi_polygon MultiPolygon::convert(jni::JNIEnv &env, jni::Obje jni::DeleteLocalRef(env, jPositionListsList); } - jni::DeleteLocalRef(env, jPointListsListList); jni::DeleteLocalRef(env, jPointListsListArray); + jni::DeleteLocalRef(env, jPointListsListList); } return multiPolygon; diff --git a/platform/android/src/geojson/point.cpp b/platform/android/src/geojson/point.cpp index 5feb1b8521..d064547145 100644 --- a/platform/android/src/geojson/point.cpp +++ b/platform/android/src/geojson/point.cpp @@ -1,6 +1,8 @@ +#include #include "point.hpp" #include "../java/util.hpp" #include "../java_types.hpp" +#include "../style/value.hpp" namespace mbgl { namespace android { @@ -19,17 +21,23 @@ mapbox::geojson::point Point::convert(jni::JNIEnv &env, jni::Object jPoin } mapbox::geojson::point Point::convert(jni::JNIEnv &env, jni::Object*/> jDoubleList) { - auto jDoubleArray = java::util::List::toArray(env, jDoubleList); + mapbox::geojson::point point; + + if (jDoubleList) { + auto jDoubleArray = java::util::List::toArray(env, jDoubleList); - jni::jdouble lon = jni::CallMethod(env, - jDoubleArray.Get(env, 0), - *java::Number::doubleValueMethodId); - jni::jdouble lat = jni::CallMethod(env, - jDoubleArray.Get(env, 1), - *java::Number::doubleValueMethodId); - mapbox::geojson::point point(lon, lat); - jni::DeleteLocalRef(env, jDoubleArray); + auto lonObject = jDoubleArray.Get(env, 0); + auto latObject = jDoubleArray.Get(env, 1); + point.x = jni::CallMethod(env, lonObject, + *java::Number::doubleValueMethodId); + point.y = jni::CallMethod(env, latObject, + *java::Number::doubleValueMethodId); + + jni::DeleteLocalRef(env, lonObject); + jni::DeleteLocalRef(env, latObject); + jni::DeleteLocalRef(env, jDoubleArray); + } return point; } -- cgit v1.2.1 From 17e5ae84af11006ed8336cd19eff57f65a6a577a Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 19 Feb 2018 19:08:07 +0100 Subject: [android] - check if hosting Activity isn't finishing before showing an dialog --- .../com/mapbox/mapboxsdk/maps/AttributionDialogManager.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java index 2bcbd5ce40..5ccd6bd795 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.maps; +import android.app.Activity; import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.Context; @@ -48,7 +49,17 @@ public class AttributionDialogManager implements View.OnClickListener, DialogInt @Override public void onClick(View view) { attributionSet = new AttributionBuilder(mapboxMap).build(); - showAttributionDialog(getAttributionTitles()); + + boolean isActivityFinishing = false; + if (context instanceof Activity) { + isActivityFinishing = ((Activity) context).isFinishing(); + } + + // check is hosting activity isn't finishing + // https://github.com/mapbox/mapbox-gl-native/issues/11238 + if (!isActivityFinishing) { + showAttributionDialog(getAttributionTitles()); + } } protected void showAttributionDialog(String[] attributionTitles) { -- cgit v1.2.1 From 06213d9145d3b20b63e235cc25678fd76dc296d0 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 17 Jan 2018 14:51:05 +0100 Subject: [android] - add instrumentation tests for FileSource activation/deactivation --- .../com/mapbox/mapboxsdk/storage/FileSource.java | 5 + .../android/MapboxGLAndroidSDKTestApp/build.gradle | 1 + .../com/mapbox/mapboxsdk/maps/OrientationTest.java | 12 +- .../mapboxsdk/testapp/action/WaitAction.java | 39 +++++++ .../testapp/activity/BaseActivityTest.java | 41 ++----- .../testapp/maps/widgets/CompassViewTest.java | 2 +- .../mapboxsdk/testapp/storage/FileSourceTest.java | 129 +++++++++++++++++++++ platform/android/gradle/dependencies.gradle | 1 + platform/android/src/file_source.cpp | 10 +- platform/android/src/file_source.hpp | 2 + 10 files changed, 202 insertions(+), 40 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java index f0cb8d973a..929e4b4279 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java @@ -6,6 +6,8 @@ import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.os.Environment; import android.support.annotation.NonNull; +import android.support.annotation.UiThread; + import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.constants.MapboxConstants; import timber.log.Timber; @@ -43,6 +45,7 @@ public class FileSource { * @param context the context to derive the cache path from * @return the single instance of FileSource */ + @UiThread public static synchronized FileSource getInstance(Context context) { if (INSTANCE == null) { String cachePath = getCachePath(context); @@ -122,6 +125,8 @@ public class FileSource { initialize(Mapbox.getAccessToken(), cachePath, assetManager); } + public native boolean isActivated(); + public native void activate(); public native void deactivate(); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle index caff70e543..6707527bf2 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle +++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle @@ -72,6 +72,7 @@ dependencies { androidTestImplementation dependenciesList.testRules androidTestImplementation dependenciesList.testEspressoCore androidTestImplementation dependenciesList.testEspressoIntents + androidTestImplementation dependenciesList.testEspressoContrib } apply from: "${rootDir}/gradle/gradle-make.gradle" diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java index 7a1fcbf5f3..89397c30eb 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java @@ -16,17 +16,17 @@ public class OrientationTest extends BaseActivityTest { @Test public void testChangeDeviceOrientation() { onView(isRoot()).perform(orientationLandscape()); - waitLoop(2200); + waitAction(2200); onView(isRoot()).perform(orientationPortrait()); - waitLoop(2500); + waitAction(2500); onView(isRoot()).perform(orientationLandscapeReverse()); - waitLoop(500); + waitAction(500); onView(isRoot()).perform(orientationPortraitReverse()); - waitLoop(1250); + waitAction(1250); onView(isRoot()).perform(orientationLandscape()); - waitLoop(750); + waitAction(750); onView(isRoot()).perform(orientationPortrait()); - waitLoop(950); + waitAction(950); onView(isRoot()).perform(orientationLandscapeReverse()); onView(isRoot()).perform(orientationPortraitReverse()); onView(isRoot()).perform(orientationLandscape()); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java new file mode 100644 index 0000000000..26a3a2e4ab --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java @@ -0,0 +1,39 @@ +package com.mapbox.mapboxsdk.testapp.action; + +import android.support.test.espresso.UiController; +import android.support.test.espresso.ViewAction; +import android.view.View; + +import org.hamcrest.Matcher; + +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; + +public final class WaitAction implements ViewAction { + + private static final long DEFAULT_LOOP_TIME = 375; + private final long loopTime; + + public WaitAction() { + this(DEFAULT_LOOP_TIME); + } + + public WaitAction(long loopTime) { + this.loopTime = loopTime; + } + + @Override + public Matcher getConstraints() { + return isDisplayed(); + } + + @Override + public String getDescription() { + return getClass().getSimpleName(); + } + + @Override + public void perform(UiController uiController, View view) { + uiController.loopMainThreadForAtLeast(loopTime); + } +} + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java index 3f32443021..6d90c20a46 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java @@ -6,18 +6,19 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.support.test.espresso.Espresso; import android.support.test.espresso.IdlingResourceTimeoutException; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; import android.support.test.rule.ActivityTestRule; -import android.view.View; + import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.mapboxsdk.testapp.action.WaitAction; import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource; + import junit.framework.Assert; -import org.hamcrest.Matcher; + import org.junit.After; import org.junit.Before; import org.junit.Rule; + import timber.log.Timber; import static android.support.test.espresso.Espresso.onView; @@ -67,12 +68,12 @@ public abstract class BaseActivityTest { onView(withId(id)).check(matches(isDisplayed())); } - protected void waitLoop() { - waitLoop(500); + protected void waitAction() { + waitAction(500); } - protected void waitLoop(long waitTime) { - onView(withId(R.id.mapView)).perform(new LoopAction(waitTime)); + protected void waitAction(long waitTime) { + onView(withId(R.id.mapView)).perform(new WaitAction(waitTime)); } static boolean isConnected(Context context) { @@ -87,29 +88,5 @@ public abstract class BaseActivityTest { Timber.e("@After test: unregister idle resource"); Espresso.unregisterIdlingResources(idlingResource); } - - private class LoopAction implements ViewAction { - - private long loopTime; - - public LoopAction(long loopTime) { - this.loopTime = loopTime; - } - - @Override - public Matcher getConstraints() { - return isDisplayed(); - } - - @Override - public String getDescription() { - return getClass().getSimpleName(); - } - - @Override - public void perform(UiController uiController, View view) { - uiController.loopMainThreadForAtLeast(loopTime); - } - } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java index 2a510b4dc5..26aee2de98 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java @@ -62,7 +62,7 @@ public class CompassViewTest extends BaseActivityTest { .build() ))); onView(withId(R.id.compassView)).perform(click()); - waitLoop(); + waitAction(); onView(withId(R.id.compassView)).check(matches(not(isDisplayed()))); invoke(mapboxMap, (uiController, mapboxMap) -> { CameraPosition cameraPosition = mapboxMap.getCameraPosition(); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java new file mode 100644 index 0000000000..554bc988a6 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java @@ -0,0 +1,129 @@ +package com.mapbox.mapboxsdk.testapp.storage; + +import android.os.Looper; +import android.support.test.espresso.UiController; +import android.support.test.espresso.ViewAction; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.view.View; + +import com.mapbox.mapboxsdk.storage.FileSource; +import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.mapboxsdk.testapp.action.WaitAction; +import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity; + +import org.hamcrest.Matcher; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.Espresso.pressBack; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.isRoot; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscape; +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +@RunWith(AndroidJUnit4.class) +public class FileSourceTest { + + @Rule + public ActivityTestRule rule = new ActivityTestRule<>(FeatureOverviewActivity.class); + + private FileSource fileSource; + + @Before + public void setUp() throws Exception { + onView(withId(R.id.recyclerView)).perform(new FileSourceCreator()); + } + + @Test + public void testDefault() throws Exception { + assertFalse("FileSource should not be active", fileSource.isActivated()); + } + + @Test + public void testActivateDeactivate() throws Exception { + assertFalse("1) FileSource should not be active", fileSource.isActivated()); + onView(withId(R.id.recyclerView)).perform(new FileSourceActivator(true)); + assertTrue("2) FileSource should be active", fileSource.isActivated()); + onView(withId(R.id.recyclerView)).perform(new FileSourceActivator(false)); + assertFalse("3) FileSource should not be active", fileSource.isActivated()); + } + + @Test + public void testOpenCloseMapView() throws Exception { + assertFalse("1) FileSource should not be active", fileSource.isActivated()); + onView(withText("Simple Map")).perform(click()); + onView(withId(R.id.mapView)).perform(new WaitAction()); + assertTrue("2) FileSource should be active", fileSource.isActivated()); + onView(withId(R.id.mapView)).perform(new WaitAction()); + pressBack(); + assertFalse("3) FileSource should not be active", fileSource.isActivated()); + } + + @Test + public void testRotateMapView() throws Exception { + assertFalse("1) FileSource should not be active", fileSource.isActivated()); + onView(withText("Simple Map")).perform(click()); + onView(withId(R.id.mapView)).perform(new WaitAction()); + onView(isRoot()).perform(orientationLandscape()); + onView(withId(R.id.mapView)).perform(new WaitAction()); + assertTrue("2) FileSource should be active", fileSource.isActivated()); + onView(withId(R.id.mapView)).perform(new WaitAction()); + pressBack(); + assertFalse("3) FileSource should not be active", fileSource.isActivated()); + } + + private class FileSourceCreator implements ViewAction { + @Override + public Matcher getConstraints() { + return isDisplayed(); + } + + @Override + public String getDescription() { + return "Creates the filesource instance on the UI thread"; + } + + @Override + public void perform(UiController uiController, View view) { + assertTrue(Looper.myLooper() == Looper.getMainLooper()); + fileSource = FileSource.getInstance(rule.getActivity()); + } + } + + private class FileSourceActivator implements ViewAction { + + private boolean activate; + + FileSourceActivator(boolean activate) { + this.activate = activate; + } + + @Override + public Matcher getConstraints() { + return isDisplayed(); + } + + @Override + public String getDescription() { + return "Creates the filesource instance on the UI thread"; + } + + @Override + public void perform(UiController uiController, View view) { + assertTrue(Looper.myLooper() == Looper.getMainLooper()); + if (activate) { + fileSource.activate(); + } else { + fileSource.deactivate(); + } + } + } +} \ No newline at end of file diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index 4ef4ae2f7d..b1b9a065ad 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -38,6 +38,7 @@ ext { testRules : "com.android.support.test:rules:${versions.testRunner}", testEspressoCore : "com.android.support.test.espresso:espresso-core:${versions.espresso}", testEspressoIntents : "com.android.support.test.espresso:espresso-intents:${versions.espresso}", + testEspressoContrib : "com.android.support.test.espresso:espresso-contrib:${versions.espresso}", supportAnnotations : "com.android.support:support-annotations:${versions.supportLib}", supportAppcompatV7 : "com.android.support:appcompat-v7:${versions.supportLib}", diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp index 6a9d7badb0..728935c03f 100644 --- a/platform/android/src/file_source.cpp +++ b/platform/android/src/file_source.cpp @@ -81,6 +81,13 @@ void FileSource::pause(jni::JNIEnv&) { } } +jni::jboolean FileSource::isResumed(jni::JNIEnv&) { + if (activationCounter) { + return (jboolean) (activationCounter > 0); + } + return (jboolean) false; +} + jni::Class FileSource::javaClass; FileSource* FileSource::getNativePeer(jni::JNIEnv& env, jni::Object jFileSource) { @@ -112,7 +119,8 @@ void FileSource::registerNative(jni::JNIEnv& env) { METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"), METHOD(&FileSource::setResourceTransform, "setResourceTransform"), METHOD(&FileSource::resume, "activate"), - METHOD(&FileSource::pause, "deactivate") + METHOD(&FileSource::pause, "deactivate"), + METHOD(&FileSource::isResumed, "isActivated") ); } diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp index 194f784622..e4295e1b84 100644 --- a/platform/android/src/file_source.hpp +++ b/platform/android/src/file_source.hpp @@ -45,6 +45,8 @@ public: void pause(jni::JNIEnv&); + jni::jboolean isResumed(jni::JNIEnv&); + static jni::Class javaClass; static FileSource* getNativePeer(jni::JNIEnv&, jni::Object); -- cgit v1.2.1 From e5810536bcedfbb83bc2b5aa48fcb7d2ada05e37 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 20 Feb 2018 15:22:44 +0100 Subject: [android] - decouple map padding from overlain views --- .../src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java | 5 ----- 1 file changed, 5 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index 3fd3e1220a..44f106bdd5 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -950,12 +950,7 @@ public final class UiSettings { initMargins[3] = bottom; // convert initial margins with padding - int[] contentPadding = projection.getContentPadding(); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams(); - left += contentPadding[0]; - top += contentPadding[1]; - right += contentPadding[2]; - bottom += contentPadding[3]; layoutParams.setMargins(left, top, right, bottom); // support RTL -- cgit v1.2.1 From c6537adbd1704b81e3182b14ee468e682060fd64 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 20 Feb 2018 16:40:32 +0100 Subject: [android] - don't disable zoom button controller zooming whem zooming gestures are disabled --- .../src/main/java/com/mapbox/mapboxsdk/maps/MapView.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index a8e065c45e..3c5b82c3b0 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -22,6 +22,7 @@ import android.view.ViewTreeObserver; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ZoomButtonsController; + import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.MarkerViewManager; @@ -36,10 +37,7 @@ import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; import com.mapbox.mapboxsdk.storage.FileSource; import com.mapbox.services.android.telemetry.MapboxTelemetry; -import timber.log.Timber; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; @@ -48,6 +46,11 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +import timber.log.Timber; + import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION; import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE; @@ -1004,10 +1007,8 @@ public class MapView extends FrameLayout { // Called when user pushes a zoom button on the ZoomButtonController @Override public void onZoom(boolean zoomIn) { - if (uiSettings.isZoomGesturesEnabled()) { - cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_ANIMATION); - onZoom(zoomIn, mapGestureDetector.getFocalPoint()); - } + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_ANIMATION); + onZoom(zoomIn, mapGestureDetector.getFocalPoint()); } private void onZoom(boolean zoomIn, @Nullable PointF focalPoint) { -- cgit v1.2.1 From c2d9d6a4235d5bce5c10b40b3f8cfaeb331d7878 Mon Sep 17 00:00:00 2001 From: Osana Babayan <32496536+osana@users.noreply.github.com> Date: Wed, 21 Feb 2018 11:01:56 -0500 Subject: [android] jni clean up - missing a couple DeleteLocalRef --- platform/android/src/conversion/collection.hpp | 1 + platform/android/src/file_source.cpp | 5 ++++- platform/android/src/geojson/feature_collection.cpp | 1 - platform/android/src/geojson/point.cpp | 1 - platform/android/src/map/camera_position.cpp | 4 +++- platform/android/src/map/image.cpp | 4 +++- 6 files changed, 11 insertions(+), 5 deletions(-) (limited to 'platform/android') diff --git a/platform/android/src/conversion/collection.hpp b/platform/android/src/conversion/collection.hpp index 549121c7ef..2b953e73f4 100644 --- a/platform/android/src/conversion/collection.hpp +++ b/platform/android/src/conversion/collection.hpp @@ -28,6 +28,7 @@ inline jni::jobject* toArrayList(JNIEnv& env, jni::jarray& array) { inline std::vector toVector(JNIEnv& env, jni::jarray& array) { std::vector vector; std::size_t len = jni::GetArrayLength(env, array); + vector.reserve(len); for (std::size_t i = 0; i < len; i++) { jni::jstring* jstr = reinterpret_cast(jni::GetObjectArrayElement(env, array, i)); diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp index 728935c03f..42c03b0974 100644 --- a/platform/android/src/file_source.cpp +++ b/platform/android/src/file_source.cpp @@ -132,8 +132,11 @@ jni::Class FileSource::ResourceTransformC std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, jni::Object callback, int kind, std::string url_) { static auto method = FileSource::ResourceTransformCallback::javaClass.GetMethod(env, "onURL"); auto url = jni::Make(env, url_); + url = callback.Call(env, method, kind, url); - return jni::Make(env, url); + auto urlStr = jni::Make(env, url); + jni::DeleteLocalRef(env, url); + return urlStr; } } // namespace android diff --git a/platform/android/src/geojson/feature_collection.cpp b/platform/android/src/geojson/feature_collection.cpp index 06f8f10b9a..18a41d48fa 100644 --- a/platform/android/src/geojson/feature_collection.cpp +++ b/platform/android/src/geojson/feature_collection.cpp @@ -1,4 +1,3 @@ -#include #include "feature_collection.hpp" #include "feature.hpp" diff --git a/platform/android/src/geojson/point.cpp b/platform/android/src/geojson/point.cpp index d064547145..e95376cd2e 100644 --- a/platform/android/src/geojson/point.cpp +++ b/platform/android/src/geojson/point.cpp @@ -1,4 +1,3 @@ -#include #include "point.hpp" #include "../java/util.hpp" #include "../java_types.hpp" diff --git a/platform/android/src/map/camera_position.cpp b/platform/android/src/map/camera_position.cpp index 1fc5f9789f..01ffc6530b 100644 --- a/platform/android/src/map/camera_position.cpp +++ b/platform/android/src/map/camera_position.cpp @@ -33,7 +33,9 @@ mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, jni::Obje static auto tilt = CameraPosition::javaClass.GetField(env, "tilt"); static auto zoom = CameraPosition::javaClass.GetField(env, "zoom"); - auto center = LatLng::getLatLng(env, position.Get(env, target)); + auto jtarget = position.Get(env, target); + auto center = LatLng::getLatLng(env, jtarget); + jni::DeleteLocalRef(env, jtarget); return mbgl::CameraOptions { center, diff --git a/platform/android/src/map/image.cpp b/platform/android/src/map/image.cpp index 5f5c90eddd..52e0e0d255 100644 --- a/platform/android/src/map/image.cpp +++ b/platform/android/src/map/image.cpp @@ -16,7 +16,9 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, jni::Object image) { auto width = image.Get(env, widthField); auto pixelRatio = image.Get(env, pixelRatioField); auto pixels = image.Get(env, bufferField); - auto name = jni::Make(env, image.Get(env, nameField)); + auto jName = image.Get(env, nameField); + auto name = jni::Make(env, jName); + jni::DeleteLocalRef(env, jName); jni::NullCheck(env, &pixels); std::size_t size = pixels.Length(env); -- cgit v1.2.1 From fcf5fa6bbb6600c9c00d019b89c6d8c9da0960f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 22 Feb 2018 10:01:48 +0100 Subject: [android] expose ImageSource coordinates setter (#11262) --- .../java/com/mapbox/mapboxsdk/style/sources/ImageSource.java | 11 +++++++++++ platform/android/src/style/sources/image_source.cpp | 8 +++++++- platform/android/src/style/sources/image_source.hpp | 2 ++ 3 files changed, 20 insertions(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java index 84e5e96fa4..b7679b5a16 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java @@ -124,6 +124,15 @@ public class ImageSource extends Source { return nativeGetUrl(); } + /** + * Updates the latitude and longitude of the four corners of the image + * + * @param latLngQuad latitude and longitude of the four corners of the image + */ + public void setCoordinates(LatLngQuad latLngQuad) { + nativeSetCoordinates(latLngQuad); + } + protected native void initialize(String layerId, LatLngQuad payload); protected native void nativeSetUrl(String url); @@ -132,6 +141,8 @@ public class ImageSource extends Source { protected native void nativeSetImage(Bitmap bitmap); + protected native void nativeSetCoordinates(LatLngQuad latLngQuad); + @Override protected native void finalize() throws Throwable; } diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp index 0cd6995969..249387ea51 100644 --- a/platform/android/src/style/sources/image_source.cpp +++ b/platform/android/src/style/sources/image_source.cpp @@ -45,6 +45,11 @@ namespace android { source.as()->setImage(Bitmap::GetImage(env, bitmap)); } + void ImageSource::setCoordinates(jni::JNIEnv& env, jni::Object coordinatesObject) { + source.as()->setCoordinates( + LatLngQuad::getLatLngArray(env, coordinatesObject)); + } + jni::Class ImageSource::javaClass; jni::Object ImageSource::createJavaPeer(jni::JNIEnv& env) { @@ -66,7 +71,8 @@ namespace android { "finalize", METHOD(&ImageSource::setURL, "nativeSetUrl"), METHOD(&ImageSource::getURL, "nativeGetUrl"), - METHOD(&ImageSource::setImage, "nativeSetImage") + METHOD(&ImageSource::setImage, "nativeSetImage"), + METHOD(&ImageSource::setCoordinates, "nativeSetCoordinates") ); } diff --git a/platform/android/src/style/sources/image_source.hpp b/platform/android/src/style/sources/image_source.hpp index f0af28d357..6021a03dc3 100644 --- a/platform/android/src/style/sources/image_source.hpp +++ b/platform/android/src/style/sources/image_source.hpp @@ -30,6 +30,8 @@ public: void setImage(jni::JNIEnv&, jni::Object); + void setCoordinates(jni::JNIEnv&, jni::Object); + private: jni::Object createJavaPeer(jni::JNIEnv&); -- cgit v1.2.1 From dfb9b26e675a152a925fcc5b84c3e14b8b9779d2 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 20 Dec 2017 16:44:21 +0100 Subject: [android] - port animated markers activity to symbol layer --- .../src/main/AndroidManifest.xml | 8 +- .../annotation/AnimatedMarkerActivity.java | 283 ------------- .../annotation/AnimatedSymbolLayerActivity.java | 449 +++++++++++++++++++++ .../main/res/layout/activity_animated_marker.xml | 6 +- .../src/main/res/values/descriptions.xml | 2 +- .../src/main/res/values/titles.xml | 2 +- platform/android/scripts/exclude-activity-gen.json | 2 +- 7 files changed, 459 insertions(+), 293 deletions(-) delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedSymbolLayerActivity.java (limited to 'platform/android') 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"/> + android:name=".activity.annotation.AnimatedSymbolLayerActivity" + android:description="@string/description_animated_symbollayer" + android:label="@string/activity_animated_symbollayer"> + android:value="@string/category_style"/> 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 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 { - - 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 randomCars = new ArrayList<>(); + private GeoJsonSource randomCarSource; + private Car taxi; + private GeoJsonSource taxiSource; + private LatLng passenger; + + private List 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 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.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.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 { + + 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"/> 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 @@ Offline Map example Update metadata example Delete region example - Animate the position change of a marker + Animate the position change of a symbol layer Add a polyline to a map Add a polygon to a map Scroll with pixels in x,y direction 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 @@ Map Fragment Multiple Maps on Screen Add Markers In Bulk - Animated Markers + Animated SymbolLayer Dynamic Marker Polyline Polygon 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", -- cgit v1.2.1 From 5fc3d4ab1e673b25a9f180fb247a216280475335 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 19 Feb 2018 18:33:57 +0200 Subject: [android] custom layer example - fix fragment shader source for opengl es 2 phones --- platform/android/src/example_custom_layer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp index 6d0bd4de4b..01a4aaaeb1 100644 --- a/platform/android/src/example_custom_layer.cpp +++ b/platform/android/src/example_custom_layer.cpp @@ -6,7 +6,7 @@ #include static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }"; -static const GLchar * fragmentShaderSource = "uniform vec4 fill_color; void main() { gl_FragColor = fill_color; }"; +static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; void main() { gl_FragColor = fill_color; }"; class ExampleCustomLayer { public: -- cgit v1.2.1 From 9a3eb808cf4c31d9dbcedf6d9a4bfdfcc60bd520 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 19 Feb 2018 18:34:32 +0200 Subject: [android] custom layer example - add error checking to debug issues more easily --- platform/android/src/example_custom_layer.cpp | 170 +++++++++++++++++++++----- 1 file changed, 142 insertions(+), 28 deletions(-) (limited to 'platform/android') diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp index 01a4aaaeb1..f315d14681 100644 --- a/platform/android/src/example_custom_layer.cpp +++ b/platform/android/src/example_custom_layer.cpp @@ -2,8 +2,111 @@ #include #include - +#include #include +#include + +// DEBUGGING + +const char* stringFromError(GLenum err) { + switch (err) { + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL_INVALID_FRAMEBUFFER_OPERATION"; + + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + +#ifdef GL_TABLE_TOO_LARGE + case GL_TABLE_TOO_LARGE: + return "GL_TABLE_TOO_LARGE"; +#endif + +#ifdef GL_STACK_OVERFLOW + case GL_STACK_OVERFLOW: + return "GL_STACK_OVERFLOW"; +#endif + +#ifdef GL_STACK_UNDERFLOW + case GL_STACK_UNDERFLOW: + return "GL_STACK_UNDERFLOW"; +#endif + +#ifdef GL_CONTEXT_LOST + case GL_CONTEXT_LOST: + return "GL_CONTEXT_LOST"; +#endif + + default: + return "GL_UNKNOWN"; + } +} + +struct Error : std::runtime_error { + using std::runtime_error::runtime_error; +}; + +void checkError(const char *cmd, const char *file, int line) { + + GLenum err = GL_NO_ERROR; + if ((err = glGetError()) != GL_NO_ERROR) { + std::string message = std::string(cmd) + ": Error " + stringFromError(err); + + // Check for further errors + while ((err = glGetError()) != GL_NO_ERROR) { + message += ", "; + message += stringFromError(err); + } + + mbgl::Log::Error(mbgl::Event::General, message + " at " + file + ":" + mbgl::util::toString(line)); + throw Error(message + " at " + file + ":" + mbgl::util::toString(line)); + } +} + +#ifndef NDEBUG +#define GL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() noexcept(false) { checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }()) +#else +#define GL_CHECK_ERROR(cmd) (cmd) +#endif + +void checkLinkStatus(GLuint program) { + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, &isLinked); + if (isLinked == GL_FALSE) { + GLint maxLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + GLchar infoLog[maxLength]; + glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); + mbgl::Log::Info(mbgl::Event::General, &infoLog[0]); + throw Error(infoLog); + } + +} + +void checkCompileStatus(GLuint shader) { + GLint isCompiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); + if (isCompiled == GL_FALSE) { + GLint maxLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + + // The maxLength includes the NULL character + GLchar errorLog[maxLength]; + glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); + mbgl::Log::Error(mbgl::Event::General, &errorLog[0]); + throw Error(errorLog); + } +} + +// /DEBUGGING static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }"; static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; void main() { gl_FragColor = fill_color; }"; @@ -24,37 +127,48 @@ public: void initialize() { mbgl::Log::Info(mbgl::Event::General, "Initialize"); - program = glCreateProgram(); - vertexShader = glCreateShader(GL_VERTEX_SHADER); - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); - glCompileShader(vertexShader); - glAttachShader(program, vertexShader); - glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); - glCompileShader(fragmentShader); - glAttachShader(program, fragmentShader); - glLinkProgram(program); - a_pos = glGetAttribLocation(program, "a_pos"); - fill_color = glGetUniformLocation(program, "fill_color"); - - GLfloat background[] = { -1,-1, 1,-1, -1,1, 1,1 }; - glGenBuffers(1, &buffer); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW); + + // Debug info + int maxAttrib; + GL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttrib)); + mbgl::Log::Info(mbgl::Event::General, "Max vertex attributes: %i", maxAttrib); + + program = GL_CHECK_ERROR(glCreateProgram()); + vertexShader = GL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)); + fragmentShader = GL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER)); + + GL_CHECK_ERROR(glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr)); + GL_CHECK_ERROR(glCompileShader(vertexShader)); + checkCompileStatus(vertexShader); + GL_CHECK_ERROR(glAttachShader(program, vertexShader)); + GL_CHECK_ERROR(glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr)); + GL_CHECK_ERROR(glCompileShader(fragmentShader)); + checkCompileStatus(fragmentShader); + GL_CHECK_ERROR(glAttachShader(program, fragmentShader)); + GL_CHECK_ERROR(glLinkProgram(program)); + checkLinkStatus(program); + + a_pos = GL_CHECK_ERROR(glGetAttribLocation(program, "a_pos")); + fill_color = GL_CHECK_ERROR(glGetUniformLocation(program, "fill_color")); + + GLfloat background[] = { -1, -1, 1, -1, -1, 1, 1, 1 }; + GL_CHECK_ERROR(glGenBuffers(1, &buffer)); + GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); + GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW)); } void render() { mbgl::Log::Info(mbgl::Event::General, "Render"); - glUseProgram(program); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glEnableVertexAttribArray(a_pos); - glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL); - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - glUniform4fv(fill_color, 1, color); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + GL_CHECK_ERROR(glUseProgram(program)); + GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); + GL_CHECK_ERROR(glEnableVertexAttribArray(a_pos)); + GL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL)); + GL_CHECK_ERROR(glDisable(GL_STENCIL_TEST)); + GL_CHECK_ERROR(glDisable(GL_DEPTH_TEST)); + GL_CHECK_ERROR(glUniform4fv(fill_color, 1, color)); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); + } GLuint program = 0; -- cgit v1.2.1 From 7b38ae3cc1455a4fea113567f805db69e5266ea5 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Thu, 22 Feb 2018 16:00:14 +0200 Subject: [android] custom layer example - remove dependencies on mbgl logging and string headers --- platform/android/src/example_custom_layer.cpp | 46 ++++++++++++++------------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'platform/android') diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp index f315d14681..f7b425c40a 100644 --- a/platform/android/src/example_custom_layer.cpp +++ b/platform/android/src/example_custom_layer.cpp @@ -1,13 +1,13 @@ #include #include - -#include -#include +#include +#include #include -#include // DEBUGGING +const char* LOG_TAG = "Custom Layer Example"; + const char* stringFromError(GLenum err) { switch (err) { case GL_INVALID_ENUM: @@ -58,16 +58,17 @@ void checkError(const char *cmd, const char *file, int line) { GLenum err = GL_NO_ERROR; if ((err = glGetError()) != GL_NO_ERROR) { - std::string message = std::string(cmd) + ": Error " + stringFromError(err); + std::ostringstream message; + message << cmd << ": Error " << stringFromError(err); // Check for further errors while ((err = glGetError()) != GL_NO_ERROR) { - message += ", "; - message += stringFromError(err); + message << ", " << stringFromError(err); } - mbgl::Log::Error(mbgl::Event::General, message + " at " + file + ":" + mbgl::util::toString(line)); - throw Error(message + " at " + file + ":" + mbgl::util::toString(line)); + message << " at " << file << ":" << line; + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, message.str().c_str()); + throw Error(message.str()); } } @@ -85,7 +86,7 @@ void checkLinkStatus(GLuint program) { glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); GLchar infoLog[maxLength]; glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); - mbgl::Log::Info(mbgl::Event::General, &infoLog[0]); + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, &infoLog[0]); throw Error(infoLog); } @@ -101,7 +102,7 @@ void checkCompileStatus(GLuint shader) { // The maxLength includes the NULL character GLchar errorLog[maxLength]; glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); - mbgl::Log::Error(mbgl::Event::General, &errorLog[0]); + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, &errorLog[0]); throw Error(errorLog); } } @@ -114,7 +115,7 @@ static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; voi class ExampleCustomLayer { public: ~ExampleCustomLayer() { - mbgl::Log::Info(mbgl::Event::General, "~ExampleCustomLayer"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "~ExampleCustomLayer"); if (program) { glDeleteBuffers(1, &buffer); glDetachShader(program, vertexShader); @@ -126,12 +127,12 @@ public: } void initialize() { - mbgl::Log::Info(mbgl::Event::General, "Initialize"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Initialize"); // Debug info int maxAttrib; GL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttrib)); - mbgl::Log::Info(mbgl::Event::General, "Max vertex attributes: %i", maxAttrib); + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Max vertex attributes: %i", maxAttrib); program = GL_CHECK_ERROR(glCreateProgram()); vertexShader = GL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)); @@ -158,7 +159,7 @@ public: } void render() { - mbgl::Log::Info(mbgl::Event::General, "Render"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Render"); GL_CHECK_ERROR(glUseProgram(program)); GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); @@ -184,12 +185,12 @@ public: GLfloat ExampleCustomLayer::color[] = { 0.0f, 1.0f, 0.0f, 1.0f }; jlong JNICALL nativeCreateContext(JNIEnv*, jobject) { - mbgl::Log::Info(mbgl::Event::General, "nativeCreateContext"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeCreateContext"); return reinterpret_cast(new ExampleCustomLayer()); } void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat blue, jfloat alpha) { - mbgl::Log::Info(mbgl::Event::General, "nativeSetColor: %.2f, %.2f, %.2f, %.2f", red, green, blue, alpha); + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "nativeSetColor: %.2f, %.2f, %.2f, %.2f", red, green, blue, alpha); ExampleCustomLayer::color[0] = red; ExampleCustomLayer::color[1] = green; ExampleCustomLayer::color[2] = blue; @@ -197,26 +198,27 @@ void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat b } void nativeInitialize(void *context) { - mbgl::Log::Info(mbgl::Event::General, "nativeInitialize"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeInitialize"); reinterpret_cast(context)->initialize(); } void nativeRender(void *context, const mbgl::style::CustomLayerRenderParameters& /*parameters*/) { - mbgl::Log::Info(mbgl::Event::General, "nativeRender"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeRender"); reinterpret_cast(context)->render(); } void nativeContextLost(void */*context*/) { - mbgl::Log::Info(mbgl::Event::General, "nativeContextLost"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeContextLost"); } void nativeDeinitialize(void *context) { - mbgl::Log::Info(mbgl::Event::General, "nativeDeinitialize"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeDeinitialize"); delete reinterpret_cast(context); } extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - mbgl::Log::Info(mbgl::Event::General, "OnLoad"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "OnLoad"); + JNIEnv *env = nullptr; vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); -- cgit v1.2.1 From 7905bd68315d8f58c00c07c1ac5756f43de9f6c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 27 Feb 2018 15:51:22 +0100 Subject: [android ] - new gestures library (#11221) * [android] new gesture library - added SNAPSHOT dependency * [android] new gesture library - cleaned up redundant classes * [android] new gesture library - limiting scale when rotating * [android] new gesture library - shove gesture filtering * [android] new gesture library - increase rotation threshold when scaling * [android] new gesture library - minimum angular velocity * [android] new gesture library - exposed gestures execution listeners * [android] new gesture library - notifying new listeners tests * [android] new gesture library - removed tracking setting * [android] new gesture library - resetting focal point with every scale/rotate callback * [android] new gesture library - fixed camera change dispatcher callbacks * [android] new gesture library - cancel velocity animations in maps onStop() * [android] new gesture library - extracted telemetry pushes to a method * [android] new gesture library - deprecated onScrollListener * [android] new gesture library - unified shove listener name --- platform/android/MapboxGLAndroidSDK/build.gradle | 1 + .../gesturedetectors/BaseGestureDetector.java | 160 --- .../gesturedetectors/MoveGestureDetector.java | 185 ---- .../gesturedetectors/RotateGestureDetector.java | 180 ---- .../gesturedetectors/ShoveGestureDetector.java | 214 ---- .../gesturedetectors/TwoFingerGestureDetector.java | 224 ---- .../multitouch/gesturedetectors/package-info.java | 4 - .../mapboxsdk/constants/MapboxConstants.java | 29 +- .../mapbox/mapboxsdk/maps/MapGestureDetector.java | 1096 ++++++++++---------- .../com/mapbox/mapboxsdk/maps/MapKeyListener.java | 8 +- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 73 +- .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 210 +++- .../java/com/mapbox/mapboxsdk/maps/Transform.java | 34 +- .../src/main/res/values/dimens.xml | 9 + .../mapboxsdk/maps/MapTouchListenersTest.java | 132 ++- .../com/mapbox/mapboxsdk/maps/MapboxMapTest.java | 2 +- platform/android/gradle/dependencies.gradle | 24 +- 17 files changed, 981 insertions(+), 1604 deletions(-) delete mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java delete mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java delete mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java delete mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java delete mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java delete mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/package-info.java (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index e2e0881857..9063321648 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -3,6 +3,7 @@ apply plugin: 'com.android.library' dependencies { api dependenciesList.mapboxAndroidTelemetry api dependenciesList.mapboxJavaGeoJSON + api dependenciesList.mapboxAndroidGestures implementation dependenciesList.supportAnnotations implementation dependenciesList.supportFragmentV4 implementation dependenciesList.timber diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java deleted file mode 100644 index b7bcb925a1..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.almeros.android.multitouch.gesturedetectors; - -import android.content.Context; -import android.view.MotionEvent; - -/** - * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie - * (code.almeros.com) - *

- * All rights reserved. - *

- * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - *

- * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY - * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -public abstract class BaseGestureDetector { - protected final Context context; - protected boolean gestureInProgress; - - protected MotionEvent prevEvent; - protected MotionEvent currEvent; - - protected float currPressure; - protected float prevPressure; - protected long timeDelta; - - /** - * This value is the threshold ratio between the previous combined pressure - * and the current combined pressure. When pressure decreases rapidly - * between events the position values can often be imprecise, as it usually - * indicates that the user is in the process of lifting a pointer off of the - * device. This value was tuned experimentally. - */ - protected static final float PRESSURE_THRESHOLD = 0.67f; - - public BaseGestureDetector(Context context) { - this.context = context; - } - - /** - * All gesture detectors need to be called through this method to be able to - * detect gestures. This method delegates work to handler methods - * (handleStartProgressEvent, handleInProgressEvent) implemented in - * extending classes. - * - * @param event MotionEvent - * @return {@code true} as handled - */ - public boolean onTouchEvent(MotionEvent event) { - final int actionCode = event.getAction() & MotionEvent.ACTION_MASK; - if (!gestureInProgress) { - handleStartProgressEvent(actionCode, event); - } else { - handleInProgressEvent(actionCode, event); - } - return true; - } - - /** - * Called when the current event occurred when NO gesture is in progress - * yet. The handling in this implementation may set the gesture in progress - * (via gestureInProgress) or out of progress - * - * @param actionCode Action Code from MotionEvent - * @param event MotionEvent - */ - protected abstract void handleStartProgressEvent(int actionCode, - MotionEvent event); - - /** - * Called when the current event occurred when a gesture IS in progress. The - * handling in this implementation may set the gesture out of progress (via - * gestureInProgress). - * - * @param actionCode Action Code from MotionEvent - * @param event MotionEvent - */ - protected abstract void handleInProgressEvent(int actionCode, - MotionEvent event); - - protected void updateStateByEvent(MotionEvent curr) { - final MotionEvent prev = prevEvent; - - // Reset currEvent - if (currEvent != null) { - currEvent.recycle(); - currEvent = null; - } - currEvent = MotionEvent.obtain(curr); - - // Delta time - timeDelta = curr.getEventTime() - prev.getEventTime(); - - // Pressure - currPressure = curr.getPressure(curr.getActionIndex()); - prevPressure = prev.getPressure(prev.getActionIndex()); - } - - protected void resetState() { - if (prevEvent != null) { - prevEvent.recycle(); - prevEvent = null; - } - if (currEvent != null) { - currEvent.recycle(); - currEvent = null; - } - gestureInProgress = false; - } - - /** - * Returns {@code true} if a gesture is currently in progress. - * - * @return {@code true} if a gesture is currently in progress, {@code false} - * otherwise. - */ - public boolean isInProgress() { - return gestureInProgress; - } - - /** - * Return the time difference in milliseconds between the previous accepted - * GestureDetector event and the current GestureDetector event. - * - * @return Time difference since the last move event in milliseconds. - */ - public long getTimeDelta() { - return timeDelta; - } - - /** - * Return the event time of the current GestureDetector event being - * processed. - * - * @return Current GestureDetector event time in milliseconds. - */ - public long getEventTime() { - return currEvent.getEventTime(); - } - -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java deleted file mode 100644 index bc7dda6159..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java +++ /dev/null @@ -1,185 +0,0 @@ -package com.almeros.android.multitouch.gesturedetectors; - -import android.content.Context; -import android.graphics.PointF; -import android.view.MotionEvent; - -/** - * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie - * (code.almeros.com) - *

- * All rights reserved. - *

- * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - *

- * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY - * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -public class MoveGestureDetector extends BaseGestureDetector { - - /** - * Listener which must be implemented which is used by MoveGestureDetector - * to perform callbacks to any implementing class which is registered to a - * MoveGestureDetector via the constructor. - * - * @see MoveGestureDetector.SimpleOnMoveGestureListener - */ - public interface OnMoveGestureListener { - public boolean onMove(MoveGestureDetector detector); - - public boolean onMoveBegin(MoveGestureDetector detector); - - public void onMoveEnd(MoveGestureDetector detector); - } - - /** - * Helper class which may be extended and where the methods may be - * implemented. This way it is not necessary to implement all methods of - * OnMoveGestureListener. - */ - public static class SimpleOnMoveGestureListener implements - OnMoveGestureListener { - public boolean onMove(MoveGestureDetector detector) { - return false; - } - - public boolean onMoveBegin(MoveGestureDetector detector) { - return true; - } - - public void onMoveEnd(MoveGestureDetector detector) { - // Do nothing, overridden implementation may be used - } - } - - private static final PointF FOCUS_DELTA_ZERO = new PointF(); - - private final OnMoveGestureListener listener; - - private PointF focusExternal = new PointF(); - private PointF focusDeltaExternal = new PointF(); - - public MoveGestureDetector(Context context, OnMoveGestureListener listener) { - super(context); - this.listener = listener; - } - - @Override - protected void handleStartProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_DOWN: - resetState(); // In case we missed an UP/CANCEL event - - prevEvent = MotionEvent.obtain(event); - timeDelta = 0; - - updateStateByEvent(event); - break; - - case MotionEvent.ACTION_MOVE: - gestureInProgress = listener.onMoveBegin(this); - break; - } - } - - @Override - protected void handleInProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - listener.onMoveEnd(this); - resetState(); - break; - - case MotionEvent.ACTION_MOVE: - updateStateByEvent(event); - - // Only accept the event if our relative pressure is within - // a certain limit. This can help filter shaky data as a - // finger is lifted. - if (currPressure / prevPressure > PRESSURE_THRESHOLD) { - final boolean updatePrevious = listener.onMove(this); - if (updatePrevious) { - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(event); - } - } - break; - } - } - - protected void updateStateByEvent(MotionEvent curr) { - super.updateStateByEvent(curr); - - final MotionEvent prev = prevEvent; - - // Focus intenal - PointF currFocusInternal = determineFocalPoint(curr); - PointF prevFocusInternal = determineFocalPoint(prev); - - // Focus external - // - Prevent skipping of focus delta when a finger is added or removed - boolean skipNextMoveEvent = prev.getPointerCount() != curr - .getPointerCount(); - focusDeltaExternal = skipNextMoveEvent ? FOCUS_DELTA_ZERO - : new PointF(currFocusInternal.x - prevFocusInternal.x, - currFocusInternal.y - prevFocusInternal.y); - - // - Don't directly use mFocusInternal (or skipping will occur). Add - // unskipped delta values to focusExternal instead. - focusExternal.x += focusDeltaExternal.x; - focusExternal.y += focusDeltaExternal.y; - } - - /** - * Determine (multi)finger focal point (a.k.a. center point between all - * fingers) - * - * @param motionEvent a {@link MotionEvent} object. - * @return PointF focal point - */ - private PointF determineFocalPoint(MotionEvent motionEvent) { - // Number of fingers on screen - final int pCount = motionEvent.getPointerCount(); - float x = 0.0f; - float y = 0.0f; - - for (int i = 0; i < pCount; i++) { - x += motionEvent.getX(i); - y += motionEvent.getY(i); - } - - return new PointF(x / pCount, y / pCount); - } - - public float getFocusX() { - return focusExternal.x; - } - - public float getFocusY() { - return focusExternal.y; - } - - public PointF getFocusDelta() { - return focusDeltaExternal; - } - -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java deleted file mode 100644 index 8c111a68df..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java +++ /dev/null @@ -1,180 +0,0 @@ -package com.almeros.android.multitouch.gesturedetectors; - -import android.content.Context; -import android.view.MotionEvent; - -/** - * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie - * (code.almeros.com) - *

- * All rights reserved. - *

- * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - *

- * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY - * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -public class RotateGestureDetector extends TwoFingerGestureDetector { - - /** - * Listener which must be implemented which is used by RotateGestureDetector - * to perform callbacks to any implementing class which is registered to a - * RotateGestureDetector via the constructor. - * - * @see RotateGestureDetector.SimpleOnRotateGestureListener - */ - public interface OnRotateGestureListener { - public boolean onRotate(RotateGestureDetector detector); - - public boolean onRotateBegin(RotateGestureDetector detector); - - public void onRotateEnd(RotateGestureDetector detector); - } - - /** - * Helper class which may be extended and where the methods may be - * implemented. This way it is not necessary to implement all methods of - * OnRotateGestureListener. - */ - public static class SimpleOnRotateGestureListener implements - OnRotateGestureListener { - public boolean onRotate(RotateGestureDetector detector) { - return false; - } - - public boolean onRotateBegin(RotateGestureDetector detector) { - return true; - } - - public void onRotateEnd(RotateGestureDetector detector) { - // Do nothing, overridden implementation may be used - } - } - - private final OnRotateGestureListener listener; - private boolean sloppyGesture; - - public RotateGestureDetector(Context context, - OnRotateGestureListener listener) { - super(context); - this.listener = listener; - } - - @Override - protected void handleStartProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_POINTER_DOWN: - // At least the second finger is on screen now - - resetState(); // In case we missed an UP/CANCEL event - prevEvent = MotionEvent.obtain(event); - timeDelta = 0; - - updateStateByEvent(event); - - // See if we have a sloppy gesture - sloppyGesture = isSloppyGesture(event); - if (!sloppyGesture) { - // No, start gesture now - gestureInProgress = listener.onRotateBegin(this); - } - break; - - case MotionEvent.ACTION_MOVE: - if (!sloppyGesture) { - break; - } - - // See if we still have a sloppy gesture - sloppyGesture = isSloppyGesture(event); - if (!sloppyGesture) { - // No, start normal gesture now - gestureInProgress = listener.onRotateBegin(this); - } - - break; - - case MotionEvent.ACTION_POINTER_UP: - if (!sloppyGesture) { - break; - } - - break; - } - } - - @Override - protected void handleInProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_POINTER_UP: - // Gesture ended but - updateStateByEvent(event); - - if (!sloppyGesture) { - listener.onRotateEnd(this); - } - - resetState(); - break; - - case MotionEvent.ACTION_CANCEL: - if (!sloppyGesture) { - listener.onRotateEnd(this); - } - - resetState(); - break; - - case MotionEvent.ACTION_MOVE: - updateStateByEvent(event); - - // Only accept the event if our relative pressure is within - // a certain limit. This can help filter shaky data as a - // finger is lifted. - if (currPressure / prevPressure > PRESSURE_THRESHOLD) { - final boolean updatePrevious = listener.onRotate(this); - if (updatePrevious) { - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(event); - } - } - break; - } - } - - @Override - protected void resetState() { - super.resetState(); - sloppyGesture = false; - } - - /** - * Return the rotation difference from the previous rotate event to the - * current event. - * - * @return The current rotation //difference in degrees. - */ - public float getRotationDegreesDelta() { - double diffRadians = Math.atan2(prevFingerDiffY, prevFingerDiffX) - - Math.atan2(currFingerDiffY, currFingerDiffX); - return (float) (diffRadians * 180.0 / Math.PI); - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java deleted file mode 100644 index 9396578e48..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java +++ /dev/null @@ -1,214 +0,0 @@ -package com.almeros.android.multitouch.gesturedetectors; - -import android.content.Context; -import android.view.MotionEvent; - -/** - * @author Robert Nordan (robert.nordan@norkart.no) - *

- * Copyright (c) 2013, Norkart AS - *

- * All rights reserved. - *

- * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - *

- * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY - * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -public class ShoveGestureDetector extends TwoFingerGestureDetector { - - /** - * Listener which must be implemented which is used by ShoveGestureDetector - * to perform callbacks to any implementing class which is registered to a - * ShoveGestureDetector via the constructor. - * - * @see ShoveGestureDetector.SimpleOnShoveGestureListener - */ - public interface OnShoveGestureListener { - public boolean onShove(ShoveGestureDetector detector); - - public boolean onShoveBegin(ShoveGestureDetector detector); - - public void onShoveEnd(ShoveGestureDetector detector); - } - - /** - * Helper class which may be extended and where the methods may be - * implemented. This way it is not necessary to implement all methods of - * OnShoveGestureListener. - */ - public static class SimpleOnShoveGestureListener implements - OnShoveGestureListener { - public boolean onShove(ShoveGestureDetector detector) { - return false; - } - - public boolean onShoveBegin(ShoveGestureDetector detector) { - return true; - } - - public void onShoveEnd(ShoveGestureDetector detector) { - // Do nothing, overridden implementation may be used - } - } - - private float prevAverageY; - private float currAverageY; - - private final OnShoveGestureListener listener; - private boolean sloppyGesture; - - public ShoveGestureDetector(Context context, OnShoveGestureListener listener) { - super(context); - this.listener = listener; - } - - @Override - protected void handleStartProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_POINTER_DOWN: - // At least the second finger is on screen now - - resetState(); // In case we missed an UP/CANCEL event - prevEvent = MotionEvent.obtain(event); - timeDelta = 0; - - updateStateByEvent(event); - - // See if we have a sloppy gesture - sloppyGesture = isSloppyGesture(event); - if (!sloppyGesture) { - // No, start gesture now - gestureInProgress = listener.onShoveBegin(this); - } - break; - - case MotionEvent.ACTION_MOVE: - if (!sloppyGesture) { - break; - } - - // See if we still have a sloppy gesture - sloppyGesture = isSloppyGesture(event); - if (!sloppyGesture) { - // No, start normal gesture now - gestureInProgress = listener.onShoveBegin(this); - } - - break; - - case MotionEvent.ACTION_POINTER_UP: - if (!sloppyGesture) { - break; - } - - break; - } - } - - @Override - protected void handleInProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_POINTER_UP: - // Gesture ended but - updateStateByEvent(event); - - if (!sloppyGesture) { - listener.onShoveEnd(this); - } - - resetState(); - break; - - case MotionEvent.ACTION_CANCEL: - if (!sloppyGesture) { - listener.onShoveEnd(this); - } - - resetState(); - break; - - case MotionEvent.ACTION_MOVE: - updateStateByEvent(event); - - // Only accept the event if our relative pressure is within - // a certain limit. This can help filter shaky data as a - // finger is lifted. Also check that shove is meaningful. - if (currPressure / prevPressure > PRESSURE_THRESHOLD - && Math.abs(getShovePixelsDelta()) > 0.5f) { - final boolean updatePrevious = listener.onShove(this); - if (updatePrevious) { - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(event); - } - } - break; - } - } - - @Override - protected void resetState() { - super.resetState(); - sloppyGesture = false; - prevAverageY = 0.0f; - currAverageY = 0.0f; - } - - @Override - protected void updateStateByEvent(MotionEvent curr) { - super.updateStateByEvent(curr); - - final MotionEvent prev = prevEvent; - float py0 = prev.getY(0); - float py1 = prev.getY(1); - prevAverageY = (py0 + py1) / 2.0f; - - float cy0 = curr.getY(0); - float cy1 = curr.getY(1); - currAverageY = (cy0 + cy1) / 2.0f; - } - - @Override - protected boolean isSloppyGesture(MotionEvent event) { - boolean sloppy = super.isSloppyGesture(event); - if (sloppy) { - return true; - } - - // If it's not traditionally sloppy, we check if the angle between - // fingers - // is acceptable. - double angle = Math.abs(Math.atan2(currFingerDiffY, currFingerDiffX)); - // about 20 degrees, left or right - return !((0.0f < angle && angle < 0.35f) || 2.79f < angle - && angle < Math.PI); - } - - /** - * Return the distance in pixels from the previous shove event to the - * current event. - * - * @return The current distance in pixels. - */ - public float getShovePixelsDelta() { - return currAverageY - prevAverageY; - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java deleted file mode 100644 index db492b6556..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java +++ /dev/null @@ -1,224 +0,0 @@ -package com.almeros.android.multitouch.gesturedetectors; - -import android.content.Context; -import android.graphics.PointF; -import android.util.DisplayMetrics; -import android.view.MotionEvent; -import android.view.ViewConfiguration; - -/** - * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie - * (code.almeros.com) - *

- * All rights reserved. - *

- * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - *

- * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY - * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -public abstract class TwoFingerGestureDetector extends BaseGestureDetector { - - private final float edgeSlop; - - protected float prevFingerDiffX; - protected float prevFingerDiffY; - protected float currFingerDiffX; - protected float currFingerDiffY; - - private float currLen; - private float prevLen; - - private PointF focus; - - public TwoFingerGestureDetector(Context context) { - super(context); - - ViewConfiguration config = ViewConfiguration.get(context); - - edgeSlop = config.getScaledEdgeSlop(); - } - - @Override - protected abstract void handleStartProgressEvent(int actionCode, - MotionEvent event); - - @Override - protected abstract void handleInProgressEvent(int actionCode, - MotionEvent event); - - protected void updateStateByEvent(MotionEvent curr) { - super.updateStateByEvent(curr); - - final MotionEvent prev = prevEvent; - - currLen = -1; - prevLen = -1; - - // Previous - final float px0 = prev.getX(0); - final float py0 = prev.getY(0); - final float px1 = prev.getX(1); - final float py1 = prev.getY(1); - final float pvx = px1 - px0; - final float pvy = py1 - py0; - prevFingerDiffX = pvx; - prevFingerDiffY = pvy; - - // Current - final float cx0 = curr.getX(0); - final float cy0 = curr.getY(0); - final float cx1 = curr.getX(1); - final float cy1 = curr.getY(1); - final float cvx = cx1 - cx0; - final float cvy = cy1 - cy0; - currFingerDiffX = cvx; - currFingerDiffY = cvy; - focus = determineFocalPoint(curr); - } - - /** - * Return the current distance between the two pointers forming the gesture - * in progress. - * - * @return Distance between pointers in pixels. - */ - public float getCurrentSpan() { - if (currLen == -1) { - final float cvx = currFingerDiffX; - final float cvy = currFingerDiffY; - currLen = (float) Math.sqrt(cvx * cvx + cvy * cvy); - } - return currLen; - } - - /** - * Return the previous distance between the two pointers forming the gesture - * in progress. - * - * @return Previous distance between pointers in pixels. - */ - public float getPreviousSpan() { - if (prevLen == -1) { - final float pvx = prevFingerDiffX; - final float pvy = prevFingerDiffY; - prevLen = (float) Math.sqrt(pvx * pvx + pvy * pvy); - } - return prevLen; - } - - /** - * MotionEvent has no getRawX(int) method; simulate it pending future API - * approval. - * - * @param event Motion Event - * @param pointerIndex Pointer Index - * @return Raw x value or 0 - */ - protected static float getRawX(MotionEvent event, int pointerIndex) { - float offset = event.getRawX() - event.getX(); - if (pointerIndex < event.getPointerCount()) { - return event.getX(pointerIndex) + offset; - } - return 0.0f; - } - - /** - * MotionEvent has no getRawY(int) method; simulate it pending future API - * approval. - * - * @param event Motion Event - * @param pointerIndex Pointer Index - * @return Raw y value or 0 - */ - protected static float getRawY(MotionEvent event, int pointerIndex) { - float offset = event.getRawY() - event.getY(); - if (pointerIndex < event.getPointerCount()) { - return event.getY(pointerIndex) + offset; - } - return 0.0f; - } - - /** - * Check if we have a sloppy gesture. Sloppy gestures can happen if the edge - * of the user's hand is touching the screen, for example. - * - * @param event Motion Event - * @return {@code true} if is sloppy gesture, {@code false} if not - */ - protected boolean isSloppyGesture(MotionEvent event) { - // As orientation can change, query the metrics in touch down - DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - float rightSlopEdge = metrics.widthPixels - edgeSlop; - float bottomSlopEdge = metrics.heightPixels - edgeSlop; - - final float edgeSlop = this.edgeSlop; - - final float x0 = event.getRawX(); - final float y0 = event.getRawY(); - final float x1 = getRawX(event, 1); - final float y1 = getRawY(event, 1); - - boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlopEdge - || y0 > bottomSlopEdge; - boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlopEdge - || y1 > bottomSlopEdge; - - if (p0sloppy && p1sloppy) { - return true; - } else if (p0sloppy) { - return true; - } else if (p1sloppy) { - return true; - } - return false; - } - - /** - * Determine (multi)finger focal point (a.k.a. center point between all - * fingers) - * - * @param motionEvent Motion Event - * @return PointF focal point - */ - public static PointF determineFocalPoint(MotionEvent motionEvent) { - // Number of fingers on screen - final int pCount = motionEvent.getPointerCount(); - float x = 0.0f; - float y = 0.0f; - - for (int i = 0; i < pCount; i++) { - x += motionEvent.getX(i); - y += motionEvent.getY(i); - } - - return new PointF(x / pCount, y / pCount); - } - - public float getFocusX() { - return focus.x; - } - - public float getFocusY() { - return focus.y; - } - -} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/package-info.java deleted file mode 100644 index cff2f086dc..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Do not use this package. Internal use only. - */ -package com.almeros.android.multitouch.gesturedetectors; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index 60362dd2e9..6f263e4635 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -47,6 +47,31 @@ public class MapboxConstants { */ public static final long VELOCITY_THRESHOLD_IGNORE_FLING = 1000; + /** + * Value by which the default rotation threshold will be increased when scaling + */ + public static final float ROTATION_THRESHOLD_INCREASE_WHEN_SCALING = 25f; + + /** + * Time within which user needs to lift fingers for velocity animation to start. + */ + public static final long SCHEDULED_ANIMATION_TIMEOUT = 150L; + + /** + * Minimum angular velocity for rotation animation + */ + public static final float MINIMUM_ANGULAR_VELOCITY = 1.5f; + + /** + * Maximum angular velocity for rotation animation + */ + public static final float MAXIMUM_ANGULAR_VELOCITY = 20f; + + /** + * Factor to calculate tilt change based on pixel change during shove gesture. + */ + public static final float SHOVE_PIXEL_CHANGE_FACTOR = 0.1f; + /** * The currently supported minimum zoom level. */ @@ -78,14 +103,14 @@ public class MapboxConstants { public static final double MINIMUM_DIRECTION = 0; /** - * The currently used minimun scale factor to clamp to when a quick zoom gesture occurs + * The currently used minimum scale factor to clamp to when a quick zoom gesture occurs */ public static final float MINIMUM_SCALE_FACTOR_CLAMP = 0.00f; /** * The currently used maximum scale factor to clamp to when a quick zoom gesture occurs */ - public static final float MAXIMUM_SCALE_FACTOR_CLAMP = 0.45f; + public static final float MAXIMUM_SCALE_FACTOR_CLAMP = 0.15f; /** * Fragment Argument Key for MapboxMapOptions diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index 8047e19809..5f5a10d0d0 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -5,26 +5,31 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.PointF; +import android.os.Handler; import android.support.annotation.Nullable; -import android.support.v4.view.GestureDetectorCompat; -import android.support.v4.view.ScaleGestureDetectorCompat; -import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.view.InputDevice; import android.view.MotionEvent; -import android.view.ScaleGestureDetector; -import android.view.VelocityTracker; -import android.view.ViewConfiguration; - -import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector; -import com.almeros.android.multitouch.gesturedetectors.ShoveGestureDetector; -import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector; +import android.view.animation.DecelerateInterpolator; + +import com.mapbox.android.gestures.AndroidGesturesManager; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.MultiFingerTapGestureDetector; +import com.mapbox.android.gestures.RotateGestureDetector; +import com.mapbox.android.gestures.ShoveGestureDetector; +import com.mapbox.android.gestures.StandardGestureDetector; +import com.mapbox.android.gestures.StandardScaleGestureDetector; import com.mapbox.android.telemetry.Event; import com.mapbox.android.telemetry.MapEventFactory; import com.mapbox.android.telemetry.MapState; +import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.utils.MathUtils; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_ANIMATION; @@ -32,24 +37,15 @@ import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.RE /** * Manages gestures events on a MapView. - *

- * Relies on gesture detection code in almeros.android.multitouch.gesturedetectors. - *

*/ final class MapGestureDetector { private final Transform transform; private final Projection projection; private final UiSettings uiSettings; - private final TrackingSettings trackingSettings; private final AnnotationManager annotationManager; private final CameraChangeDispatcher cameraChangeDispatcher; - private GestureDetectorCompat gestureDetector; - private ScaleGestureDetector scaleGestureDetector; - private RotateGestureDetector rotateGestureDetector; - private ShoveGestureDetector shoveGestureDetector; - // deprecated map touch API private MapboxMap.OnMapClickListener onMapClickListener; private MapboxMap.OnMapLongClickListener onMapLongClickListener; @@ -69,43 +65,73 @@ final class MapGestureDetector { private final CopyOnWriteArrayList onScrollListenerList = new CopyOnWriteArrayList<>(); - private PointF focalPoint; + private final CopyOnWriteArrayList onMoveListenerList + = new CopyOnWriteArrayList<>(); - private boolean twoTap; - private boolean quickZoom; - private boolean tiltGestureOccurred; - private boolean scrollGestureOccurred; + private final CopyOnWriteArrayList onRotateListenerList + = new CopyOnWriteArrayList<>(); + + private final CopyOnWriteArrayList onScaleListenerList + = new CopyOnWriteArrayList<>(); + + private final CopyOnWriteArrayList onShoveListenerList + = new CopyOnWriteArrayList<>(); + + /** + * User-set focal point. + */ + private PointF focalPoint; - private boolean scaleGestureOccurred; - private boolean recentScaleGestureOccurred; - private long scaleBeginTime; + private AndroidGesturesManager gesturesManager; + private boolean executeDoubleTap; - private boolean scaleAnimating; - private boolean rotateAnimating; + private Animator scaleAnimator; + private Animator rotateAnimator; + private final List scheduledAnimators = new ArrayList<>(); - private VelocityTracker velocityTracker; - private boolean wasZoomingIn; - private boolean wasClockwiseRotating; - private boolean rotateGestureOccurred; + /** + * Cancels scheduled velocity animations if user doesn't lift fingers within + * {@link MapboxConstants#SCHEDULED_ANIMATION_TIMEOUT} + */ + private Handler animationsTimeoutHandler = new Handler(); MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings, - TrackingSettings trackingSettings, AnnotationManager annotationManager, - CameraChangeDispatcher cameraChangeDispatcher) { + AnnotationManager annotationManager, CameraChangeDispatcher cameraChangeDispatcher) { this.annotationManager = annotationManager; this.transform = transform; this.projection = projection; this.uiSettings = uiSettings; - this.trackingSettings = trackingSettings; this.cameraChangeDispatcher = cameraChangeDispatcher; - // Touch gesture detectors + // Checking for context != null for testing purposes if (context != null) { - gestureDetector = new GestureDetectorCompat(context, new GestureListener()); - gestureDetector.setIsLongpressEnabled(true); - scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureListener()); - ScaleGestureDetectorCompat.setQuickScaleEnabled(scaleGestureDetector, true); - rotateGestureDetector = new RotateGestureDetector(context, new RotateGestureListener()); - shoveGestureDetector = new ShoveGestureDetector(context, new ShoveGestureListener()); + gesturesManager = new AndroidGesturesManager(context); + + Set shoveScaleSet = new HashSet<>(); + shoveScaleSet.add(AndroidGesturesManager.GESTURE_TYPE_SHOVE); + shoveScaleSet.add(AndroidGesturesManager.GESTURE_TYPE_SCALE); + + Set shoveRotateSet = new HashSet<>(); + shoveRotateSet.add(AndroidGesturesManager.GESTURE_TYPE_SHOVE); + shoveRotateSet.add(AndroidGesturesManager.GESTURE_TYPE_ROTATE); + + Set ScaleLongPressSet = new HashSet<>(); + ScaleLongPressSet.add(AndroidGesturesManager.GESTURE_TYPE_SCALE); + ScaleLongPressSet.add(AndroidGesturesManager.GESTURE_TYPE_LONG_PRESS); + + gesturesManager.setMutuallyExclusiveGestures(shoveScaleSet, shoveRotateSet, ScaleLongPressSet); + + gesturesManager.setStandardGestureListener(new StandardGestureListener()); + gesturesManager.setMoveGestureListener(new MoveGestureListener()); + gesturesManager.setStandardScaleGestureListener(new ScaleGestureListener( + context.getResources().getDimension(R.dimen.mapbox_minimum_scale_velocity) + )); + gesturesManager.setRotateGestureListener(new RotateGestureListener( + context.getResources().getDimension(R.dimen.mapbox_minimum_scale_span_when_rotating), + context.getResources().getDimension(R.dimen.mapbox_minimum_angular_velocity) + )); + gesturesManager.setShoveGestureListener(new ShoveGestureListener()); + gesturesManager.setMultiFingerTapGestureListener(new TapGestureListener()); } } @@ -132,8 +158,9 @@ final class MapGestureDetector { /** * Get the current active gesture focal point. *

- * This could be either the user provided focal point in {@link UiSettings#setFocalPoint(PointF)} or the focal point - * defined as a result of {@link TrackingSettings#setMyLocationEnabled(boolean)}. + * This could be either the user provided focal point in + * {@link UiSettings#setFocalPoint(PointF)}or null. + * If it's null, gestures will use focal pointed returned by the detector. *

* * @return the current active gesture focal point. @@ -149,118 +176,79 @@ final class MapGestureDetector { * Forwards event to the related gesture detectors. *

* - * @param event the MotionEvent + * @param motionEvent the MotionEvent * @return True if touch event is handled */ - boolean onTouchEvent(MotionEvent event) { - // framework can return null motion events in edge cases #9432 - if (event == null) { + boolean onTouchEvent(MotionEvent motionEvent) { + // Framework can return null motion events in edge cases #9432 + if (motionEvent == null) { return false; } // Check and ignore non touch or left clicks - if ((event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { + if ((motionEvent.getButtonState() != 0) && (motionEvent.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { return false; } - // Check two finger gestures first - scaleGestureDetector.onTouchEvent(event); - rotateGestureDetector.onTouchEvent(event); - shoveGestureDetector.onTouchEvent(event); + boolean result = gesturesManager.onTouchEvent(motionEvent); - // Handle two finger tap - switch (event.getActionMasked()) { + switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: - if (velocityTracker == null) { - velocityTracker = VelocityTracker.obtain(); - } else { - velocityTracker.clear(); - } - velocityTracker.addMovement(event); - // First pointer down, reset scaleGestureOccurred, used to avoid triggering a fling after a scale gesture #7666 - recentScaleGestureOccurred = false; + cancelAnimators(); transform.setGestureInProgress(true); break; + case MotionEvent.ACTION_UP: + transform.setGestureInProgress(false); - case MotionEvent.ACTION_POINTER_DOWN: - // Second pointer down - twoTap = event.getPointerCount() == 2 - && uiSettings.isZoomGesturesEnabled(); - if (twoTap) { - // Confirmed 2nd Finger Down - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(event.getX(), event.getY())); - MapState twoFingerTap = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - twoFingerTap.setGesture(Events.TWO_FINGER_TAP); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, twoFingerTap)); - } + // Start all awaiting velocity animations + animationsTimeoutHandler.removeCallbacksAndMessages(null); + for (Animator animator : scheduledAnimators) { + animator.start(); } + scheduledAnimators.clear(); break; - case MotionEvent.ACTION_POINTER_UP: - // Second pointer up + case MotionEvent.ACTION_CANCEL: + scheduledAnimators.clear(); + transform.setGestureInProgress(false); break; + } - case MotionEvent.ACTION_UP: - // First pointer up - long tapInterval = event.getEventTime() - event.getDownTime(); - boolean isTap = tapInterval <= ViewConfiguration.getTapTimeout(); - boolean inProgress = rotateGestureDetector.isInProgress() - || scaleGestureDetector.isInProgress() - || shoveGestureDetector.isInProgress(); - - if (twoTap && isTap && !inProgress) { - if (focalPoint != null) { - transform.zoom(false, focalPoint); - } else { - PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); - transform.zoom(false, focalPoint); - } - twoTap = false; - return true; - } - - // Scroll / Pan Has Stopped - if (scrollGestureOccurred) { - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(event.getX(), event.getY())); - MapState dragend = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_DRAGEND, dragend)); - } - scrollGestureOccurred = false; + return result; + } - if (!scaleAnimating && !rotateAnimating) { - cameraChangeDispatcher.onCameraIdle(); - } - } + void cancelAnimators() { + if (scaleAnimator != null) { + scaleAnimator.cancel(); + } + if (rotateAnimator != null) { + rotateAnimator.cancel(); + } - twoTap = false; - transform.setGestureInProgress(false); - if (velocityTracker != null) { - velocityTracker.recycle(); - } - velocityTracker = null; - break; + animationsTimeoutHandler.removeCallbacksAndMessages(null); + scheduledAnimators.clear(); + } - case MotionEvent.ACTION_CANCEL: - twoTap = false; - transform.setGestureInProgress(false); - if (velocityTracker != null) { - velocityTracker.recycle(); - } - velocityTracker = null; - break; - case MotionEvent.ACTION_MOVE: - if (velocityTracker != null) { - velocityTracker.addMovement(event); - velocityTracker.computeCurrentVelocity(1000); - } - break; + /** + * Posted on main thread with {@link #animationsTimeoutHandler}. Cancels all scheduled animators if needed. + */ + private Runnable cancelAnimatorsRunnable = new Runnable() { + @Override + public void run() { + cancelAnimators(); } + }; - return gestureDetector.onTouchEvent(event); + /** + * Schedules a velocity animator to be executed when user lift fingers, + * unless canceled by the {@link #cancelAnimatorsRunnable}. + * + * @param animator animator ot be scheduled + */ + private void scheduleAnimator(Animator animator) { + scheduledAnimators.add(animator); + animationsTimeoutHandler.removeCallbacksAndMessages(null); + animationsTimeoutHandler.postDelayed(cancelAnimatorsRunnable, MapboxConstants.SCHEDULED_ANIMATION_TIMEOUT); } /** @@ -269,7 +257,7 @@ final class MapGestureDetector { * Examples of such events are mouse scroll events, mouse moves, joystick & trackpad. *

* - * @param event The MotionEvent occured + * @param event The MotionEvent occurred * @return True is the event is handled */ boolean onGenericMotionEvent(MotionEvent event) { @@ -291,7 +279,7 @@ final class MapGestureDetector { float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL); // Scale the map by the appropriate power of two factor - transform.zoomBy(scrollDist, event.getX(), event.getY()); + transform.zoomBy(scrollDist, new PointF(event.getX(), event.getY())); return true; @@ -305,61 +293,14 @@ final class MapGestureDetector { return false; } - /** - * Responsible for handling one finger gestures. - */ - private class GestureListener extends android.view.GestureDetector.SimpleOnGestureListener { - + private final class StandardGestureListener extends StandardGestureDetector.SimpleStandardOnGestureListener { @Override - public boolean onDown(MotionEvent event) { - return true; - } - - @Override - public boolean onDoubleTapEvent(MotionEvent e) { - if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled()) { - return false; - } - - switch (e.getAction()) { - case MotionEvent.ACTION_DOWN: - break; - case MotionEvent.ACTION_MOVE: - break; - case MotionEvent.ACTION_UP: - if (quickZoom) { - cameraChangeDispatcher.onCameraIdle(); - quickZoom = false; - break; - } - - // notify camera change listener - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - - // Single finger double tap - if (focalPoint != null) { - // User provided focal point - transform.zoom(true, focalPoint); - } else { - // Zoom in on gesture - transform.zoom(true, new PointF(e.getX(), e.getY())); - } - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(e.getX(), e.getY())); - MapState doubleTap = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - doubleTap.setGesture(Events.DOUBLE_TAP); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, doubleTap)); - } - break; - } - + public boolean onDown(MotionEvent motionEvent) { return true; } @Override public boolean onSingleTapUp(MotionEvent motionEvent) { - // Cancel any animation transform.cancelTransitions(); return true; } @@ -378,31 +319,51 @@ final class MapGestureDetector { notifyOnMapClickListeners(tapPoint); } - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(motionEvent.getX(), motionEvent.getY())); - MapState singleTap = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - singleTap.setGesture(Events.SINGLE_TAP); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, singleTap)); - } + sendTelemetryEvent(Events.SINGLE_TAP, new PointF(motionEvent.getX(), motionEvent.getY())); return true; } @Override - public void onLongPress(MotionEvent motionEvent) { - PointF longClickPoint = new PointF(motionEvent.getX(), motionEvent.getY()); + public boolean onDoubleTapEvent(MotionEvent motionEvent) { + int action = motionEvent.getActionMasked(); + if (action == MotionEvent.ACTION_DOWN) { + executeDoubleTap = true; + } + if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) { + if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled() || !executeDoubleTap) { + return false; + } + + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - if (!quickZoom) { - notifyOnMapLongClickListeners(longClickPoint); + // Single finger double tap + if (focalPoint != null) { + // User provided focal point + transform.zoomIn(focalPoint); + } else { + // Zoom in on gesture + transform.zoomIn(new PointF(motionEvent.getX(), motionEvent.getY())); + } + + sendTelemetryEvent(Events.DOUBLE_TAP, new PointF(motionEvent.getX(), motionEvent.getY())); + + return true; } + return super.onDoubleTapEvent(motionEvent); + } + + @Override + public void onLongPress(MotionEvent motionEvent) { + PointF longClickPoint = new PointF(motionEvent.getX(), motionEvent.getY()); + notifyOnMapLongClickListeners(longClickPoint); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if ((!trackingSettings.isScrollGestureCurrentlyEnabled()) || recentScaleGestureOccurred) { + if ((!uiSettings.isScrollGesturesEnabled())) { // don't allow a fling is scroll is disabled - // and ignore when a scale gesture has occurred return false; } @@ -415,11 +376,7 @@ final class MapGestureDetector { return false; } - trackingSettings.resetTrackingModesIfRequired(true, false, false); - - // cancel any animation transform.cancelTransitions(); - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); // tilt results in a bigger translation, limiting input for #5281 @@ -435,230 +392,149 @@ final class MapGestureDetector { transform.moveBy(offsetX, offsetY, animationTime); notifyOnFlingListeners(); + return true; } + } - // Called for drags + private final class MoveGestureListener extends MoveGestureDetector.SimpleOnMoveGestureListener { @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + public boolean onMoveBegin(MoveGestureDetector detector) { + if (!uiSettings.isScrollGesturesEnabled()) { return false; } - if (tiltGestureOccurred) { - return false; - } + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - if (!scrollGestureOccurred) { - scrollGestureOccurred = true; + sendTelemetryEvent(Events.PAN, detector.getFocalPoint()); - // Cancel any animation - if (!scaleGestureOccurred) { - transform.cancelTransitions(); - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - } + notifyOnMoveBeginListeners(detector); - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(e1.getX(), e1.getY())); - MapState pan = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - pan.setGesture(Events.PAN); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, pan)); - } - } + return true; + } - // reset tracking if needed - trackingSettings.resetTrackingModesIfRequired(true, false, false); + @Override + public boolean onMove(MoveGestureDetector detector, float distanceX, float distanceY) { + // dispatching start even once more if another detector ended, and this one didn't + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); // Scroll the map transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/); notifyOnScrollListeners(); + notifyOnMoveListeners(detector); return true; } - } - - void notifyOnMapClickListeners(PointF tapPoint) { - // deprecated API - if (onMapClickListener != null) { - onMapClickListener.onMapClick(projection.fromScreenLocation(tapPoint)); - } - // new API - for (MapboxMap.OnMapClickListener listener : onMapClickListenerList) { - listener.onMapClick(projection.fromScreenLocation(tapPoint)); + @Override + public void onMoveEnd(MoveGestureDetector detector, float velocityX, float velocityY) { + cameraChangeDispatcher.onCameraIdle(); + notifyOnMoveEndListeners(detector); } } - void notifyOnMapLongClickListeners(PointF longClickPoint) { - // deprecated API - if (onMapLongClickListener != null) { - onMapLongClickListener.onMapLongClick(projection.fromScreenLocation(longClickPoint)); - } + private final class ScaleGestureListener extends StandardScaleGestureDetector.SimpleStandardOnScaleGestureListener { - // new API - for (MapboxMap.OnMapLongClickListener listener : onMapLongClickListenerList) { - listener.onMapLongClick(projection.fromScreenLocation(longClickPoint)); - } - } + private final float minimumVelocity; - void notifyOnFlingListeners() { - // deprecated API - if (onFlingListener != null) { - onFlingListener.onFling(); - } + private PointF scaleFocalPoint; + private boolean quickZoom; - // new API - for (MapboxMap.OnFlingListener listener : onFlingListenerList) { - listener.onFling(); + ScaleGestureListener(float minimumVelocity) { + this.minimumVelocity = minimumVelocity; } - } - void notifyOnScrollListeners() { - //deprecated API - if (onScrollListener != null) { - onScrollListener.onScroll(); - } - - // new API - for (MapboxMap.OnScrollListener listener : onScrollListenerList) { - listener.onScroll(); - } - } - - /** - * Responsible for handling two finger gestures and double-tap drag gestures. - */ - private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - - private static final int ANIMATION_TIME_MULTIPLIER = 77; - private static final double ZOOM_DISTANCE_DIVIDER = 5; - - private float scaleFactor = 1.0f; - private PointF scalePointBegin; - - // Called when two fingers first touch the screen @Override - public boolean onScaleBegin(ScaleGestureDetector detector) { + public boolean onScaleBegin(StandardScaleGestureDetector detector) { if (!uiSettings.isZoomGesturesEnabled()) { return false; } - recentScaleGestureOccurred = true; - scalePointBegin = new PointF(detector.getFocusX(), detector.getFocusY()); - scaleBeginTime = detector.getEventTime(); - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(detector.getFocusX(), detector.getFocusY())); - MapState pinch = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - pinch.setGesture(Events.PINCH); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, pinch)); + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + + quickZoom = detector.getPointersCount() == 1; + if (quickZoom) { + // when quickzoom, dismiss double tap and disable move gesture + executeDoubleTap = false; + gesturesManager.getMoveGestureDetector().setEnabled(false); } + + // increase rotate angle threshold when scale is detected first + gesturesManager.getRotateGestureDetector().setAngleThreshold( + gesturesManager.getRotateGestureDetector().getDefaultAngleThreshold() + + MapboxConstants.ROTATION_THRESHOLD_INCREASE_WHEN_SCALING + ); + + // setting focalPoint in #onScaleBegin() as well, because #onScale() might not get called before #onScaleEnd() + setScaleFocalPoint(detector); + + sendTelemetryEvent(Events.PINCH, scaleFocalPoint); + + notifyOnScaleBeginListeners(detector); + return true; } - // Called each time a finger moves - // Called for pinch zooms and quickzooms/quickscales @Override - public boolean onScale(ScaleGestureDetector detector) { - if (!uiSettings.isZoomGesturesEnabled()) { - return super.onScale(detector); - } + public boolean onScale(StandardScaleGestureDetector detector) { + // dispatching start even once more if another detector ended, and this one didn't + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); - wasZoomingIn = (Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2)) > 0; - if (tiltGestureOccurred) { - return false; - } - - // Ignore short touches in case it is a tap - // Also ignore small scales - long time = detector.getEventTime(); - long interval = time - scaleBeginTime; - if (!scaleGestureOccurred && (interval <= ViewConfiguration.getTapTimeout())) { - return false; - } - - // If scale is large enough ignore a tap - scaleFactor *= detector.getScaleFactor(); - if ((scaleFactor > 1.1f) || (scaleFactor < 0.9f)) { - // notify camera change listener - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - scaleGestureOccurred = true; - } + setScaleFocalPoint(detector); - if (!scaleGestureOccurred) { - return false; - } + float scaleFactor = detector.getScaleFactor(); + double zoomBy = getNewZoom(scaleFactor, quickZoom); + transform.zoomBy(zoomBy, scaleFocalPoint); - // Gesture is a quickzoom if there aren't two fingers - if (!quickZoom && !twoTap) { - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - } - quickZoom = !twoTap; + notifyOnScaleListeners(detector); - // make an assumption here; if the zoom center is specified by the gesture, it's NOT going - // to be in the center of the map. Therefore the zoom will translate the map center, so tracking - // should be disabled. - trackingSettings.resetTrackingModesIfRequired(!quickZoom, false, false); - // Scale the map - if (focalPoint != null) { - // arround user provided focal point - transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2), focalPoint.x, focalPoint.y); - } else if (quickZoom) { - cameraChangeDispatcher.onCameraMove(); - // clamp scale factors we feed to core #7514 - float scaleFactor = detector.getScaleFactor(); - // around center map - double zoomBy = Math.log(scaleFactor) / Math.log(Math.PI / 2); - boolean negative = zoomBy < 0; - zoomBy = MathUtils.clamp(Math.abs(zoomBy), - MapboxConstants.MINIMUM_SCALE_FACTOR_CLAMP, - MapboxConstants.MAXIMUM_SCALE_FACTOR_CLAMP); - transform.zoomBy(negative ? -zoomBy : zoomBy, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - recentScaleGestureOccurred = true; - } else { - // around gesture - transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2), - scalePointBegin.x, scalePointBegin.y); - } return true; } - // Called when fingers leave screen @Override - public void onScaleEnd(final ScaleGestureDetector detector) { - if (velocityTracker == null) { - return; - } + public void onScaleEnd(StandardScaleGestureDetector detector, float velocityX, float velocityY) { + cameraChangeDispatcher.onCameraIdle(); - if (rotateGestureOccurred || quickZoom) { - reset(); - return; + if (quickZoom) { + //if quickzoom, re-enabling move gesture detector + gesturesManager.getMoveGestureDetector().setEnabled(true); } - double velocityXY = Math.abs(velocityTracker.getYVelocity()) + Math.abs(velocityTracker.getXVelocity()); - if (velocityXY > MapboxConstants.VELOCITY_THRESHOLD_IGNORE_FLING / 2) { - scaleAnimating = true; - double zoomAddition = calculateScale(velocityXY); + // resetting default angle threshold + gesturesManager.getRotateGestureDetector().setAngleThreshold( + gesturesManager.getRotateGestureDetector().getDefaultAngleThreshold() + ); + + float velocityXY = Math.abs(velocityX) + Math.abs(velocityY); + if (velocityXY > minimumVelocity) { + double zoomAddition = calculateScale(velocityXY, detector.isScalingOut()); double currentZoom = transform.getRawZoom(); - long animationTime = (long) (Math.log(velocityXY) * ANIMATION_TIME_MULTIPLIER); - createScaleAnimator(currentZoom, zoomAddition, animationTime).start(); - } else if (!scaleAnimating) { - reset(); + long animationTime = (long) (Math.abs(zoomAddition) * 1000 / 4); + scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, animationTime); + scheduleAnimator(scaleAnimator); } + + notifyOnScaleEndListeners(detector); } - private void reset() { - scaleAnimating = false; - scaleGestureOccurred = false; - scaleBeginTime = 0; - scaleFactor = 1.0f; - cameraChangeDispatcher.onCameraIdle(); + private void setScaleFocalPoint(StandardScaleGestureDetector detector) { + if (focalPoint != null) { + // around user provided focal point + scaleFocalPoint = focalPoint; + } else if (quickZoom) { + // around center + scaleFocalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + } else { + // around gesture + scaleFocalPoint = detector.getFocalPoint(); + } } - private double calculateScale(double velocityXY) { - double zoomAddition = (float) (Math.log(velocityXY) / ZOOM_DISTANCE_DIVIDER); - if (!wasZoomingIn) { + private double calculateScale(double velocityXY, boolean isScalingOut) { + double zoomAddition = (float) Math.log(velocityXY / 1000 + 1); + if (isScalingOut) { zoomAddition = -zoomAddition; } return zoomAddition; @@ -667,272 +543,387 @@ final class MapGestureDetector { private Animator createScaleAnimator(double currentZoom, double zoomAddition, long animationTime) { ValueAnimator animator = ValueAnimator.ofFloat((float) currentZoom, (float) (currentZoom + zoomAddition)); animator.setDuration(animationTime); - animator.setInterpolator(new FastOutSlowInInterpolator()); + animator.setInterpolator(new DecelerateInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - transform.setZoom((Float) animation.getAnimatedValue(), scalePointBegin, 0, true); + transform.setZoom((Float) animation.getAnimatedValue(), scaleFocalPoint, 0); } }); + animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { + transform.cancelTransitions(); cameraChangeDispatcher.onCameraMoveStarted(REASON_API_ANIMATION); } @Override public void onAnimationCancel(Animator animation) { - reset(); + transform.cancelTransitions(); } @Override public void onAnimationEnd(Animator animation) { - reset(); + cameraChangeDispatcher.onCameraIdle(); } }); return animator; } - } - /** - * Responsible for handling rotation gestures. - */ - private class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { + private double getNewZoom(float scaleFactor, boolean quickZoom) { + double zoomBy = Math.log(scaleFactor) / Math.log(Math.PI / 2); + if (quickZoom) { + // clamp scale factors we feed to core #7514 + boolean negative = zoomBy < 0; + zoomBy = MathUtils.clamp(Math.abs(zoomBy), + MapboxConstants.MINIMUM_SCALE_FACTOR_CLAMP, + MapboxConstants.MAXIMUM_SCALE_FACTOR_CLAMP); + return negative ? -zoomBy : zoomBy; + } + return zoomBy; + } + } - private static final float ROTATE_INVOKE_ANGLE = 15.30f; - private static final float ROTATE_LIMITATION_ANGLE = 3.35f; - private static final float ROTATE_LIMITATION_DURATION = ROTATE_LIMITATION_ANGLE * 1.85f; + private final class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { + private PointF rotateFocalPoint; + private final float minimumScaleSpanWhenRotating; + private final float minimumAngularVelocity; - private long beginTime = 0; - private boolean started = false; + RotateGestureListener(float minimumScaleSpanWhenRotating, float minimumAngularVelocity) { + this.minimumScaleSpanWhenRotating = minimumScaleSpanWhenRotating; + this.minimumAngularVelocity = minimumAngularVelocity; + } - // Called when two fingers first touch the screen @Override public boolean onRotateBegin(RotateGestureDetector detector) { - if (!trackingSettings.isRotateGestureCurrentlyEnabled()) { + if (!uiSettings.isRotateGesturesEnabled()) { return false; } - // notify camera change listener + transform.cancelTransitions(); cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - beginTime = detector.getEventTime(); - return true; - } + // when rotation starts, interrupting scale and increasing the threshold + // to make rotation without scaling easier + gesturesManager.getStandardScaleGestureDetector().setSpanSinceStartThreshold(minimumScaleSpanWhenRotating); + gesturesManager.getStandardScaleGestureDetector().interrupt(); - // Called each time one of the two fingers moves - // Called for rotation - @Override - public boolean onRotate(RotateGestureDetector detector) { - if (!trackingSettings.isRotateGestureCurrentlyEnabled() || tiltGestureOccurred) { - return false; - } + // setting in #onRotateBegin() as well, because #onRotate() might not get called before #onRotateEnd() + setRotateFocalPoint(detector); - // If rotate is large enough ignore a tap - // Also is zoom already started, don't rotate - float angle = detector.getRotationDegreesDelta(); - if (Math.abs(angle) >= ROTATE_INVOKE_ANGLE) { - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(detector.getFocusX(), detector.getFocusY())); - MapState rotation = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - rotation.setGesture(Events.ROTATION); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, rotation)); - } - started = true; - } + sendTelemetryEvent(Events.ROTATION, rotateFocalPoint); - if (!started) { - return false; - } + notifyOnRotateBeginListeners(detector); - wasClockwiseRotating = detector.getRotationDegreesDelta() > 0; - if (scaleBeginTime != 0) { - rotateGestureOccurred = true; - } + return true; + } - // rotation constitutes translation of anything except the center of - // rotation, so cancel both location and bearing tracking if required - trackingSettings.resetTrackingModesIfRequired(true, true, false); + @Override + public boolean onRotate(RotateGestureDetector detector, float rotationDegreesSinceLast, + float rotationDegreesSinceFirst) { + // dispatching start even once more if another detector ended, and this one didn't + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); + + setRotateFocalPoint(detector); // Calculate map bearing value - double bearing = transform.getRawBearing() + angle; + double bearing = transform.getRawBearing() + rotationDegreesSinceLast; // Rotate the map - if (focalPoint != null) { - // User provided focal point - transform.setBearing(bearing, focalPoint.x, focalPoint.y); - } else { - // around gesture - transform.setBearing(bearing, detector.getFocusX(), detector.getFocusY()); - } + transform.setBearing(bearing, rotateFocalPoint.x, rotateFocalPoint.y); + + notifyOnRotateListeners(detector); + return true; } - // Called when the fingers leave the screen @Override - public void onRotateEnd(RotateGestureDetector detector) { - long interval = detector.getEventTime() - beginTime; - if ((!started && (interval <= ViewConfiguration.getTapTimeout())) || scaleAnimating || interval > 500) { - reset(); + public void onRotateEnd(RotateGestureDetector detector, float velocityX, float velocityY, float angularVelocity) { + cameraChangeDispatcher.onCameraIdle(); + + // resetting default scale threshold values + gesturesManager.getStandardScaleGestureDetector().setSpanSinceStartThreshold( + gesturesManager.getStandardScaleGestureDetector().getDefaultSpanSinceStartThreshold()); + + if (Math.abs(angularVelocity) < minimumAngularVelocity) { return; } - double angularVelocity = calculateVelocityVector(detector); - if (Math.abs(angularVelocity) > 0.001 && rotateGestureOccurred && !rotateAnimating) { - animateRotateVelocity(); - } else if (!rotateAnimating) { - reset(); - } - } + boolean negative = angularVelocity < 0; + angularVelocity = (float) Math.pow(angularVelocity, 2); + angularVelocity = MathUtils.clamp( + angularVelocity, MapboxConstants.MINIMUM_ANGULAR_VELOCITY, MapboxConstants.MAXIMUM_ANGULAR_VELOCITY); - private void reset() { - beginTime = 0; - started = false; - rotateAnimating = false; - rotateGestureOccurred = false; + long animationTime = (long) (Math.log(angularVelocity + 1) * 500); - if (!twoTap) { - cameraChangeDispatcher.onCameraIdle(); + if (negative) { + angularVelocity = -angularVelocity; } - } - private void animateRotateVelocity() { - rotateAnimating = true; - double currentRotation = transform.getRawBearing(); - double rotateAdditionDegrees = calculateVelocityInDegrees(); - createAnimator(currentRotation, rotateAdditionDegrees).start(); - } + rotateAnimator = createRotateAnimator(angularVelocity, animationTime); + scheduleAnimator(rotateAnimator); - private double calculateVelocityVector(RotateGestureDetector detector) { - return ((detector.getFocusX() * velocityTracker.getYVelocity()) - + (detector.getFocusY() * velocityTracker.getXVelocity())) - / (Math.pow(detector.getFocusX(), 2) + Math.pow(detector.getFocusY(), 2)); + notifyOnRotateEndListeners(detector); } - private double calculateVelocityInDegrees() { - double angleRadians = Math.atan2(velocityTracker.getXVelocity(), velocityTracker.getYVelocity()); - double angle = angleRadians / (Math.PI / 180); - if (angle <= 0) { - angle += 360; - } - - // limit the angle - angle = angle / ROTATE_LIMITATION_ANGLE; - - // correct direction - if (!wasClockwiseRotating) { - angle = -angle; + private void setRotateFocalPoint(RotateGestureDetector detector) { + if (focalPoint != null) { + // User provided focal point + rotateFocalPoint = focalPoint; + } else { + // around gesture + rotateFocalPoint = detector.getFocalPoint(); } - - return angle; } - private Animator createAnimator(double currentRotation, double rotateAdditionDegrees) { - ValueAnimator animator = ValueAnimator.ofFloat( - (float) currentRotation, - (float) (currentRotation + rotateAdditionDegrees) - ); - animator.setDuration((long) (Math.abs(rotateAdditionDegrees) * ROTATE_LIMITATION_DURATION)); + private Animator createRotateAnimator(float angularVelocity, long animationTime) { + ValueAnimator animator = ValueAnimator.ofFloat(angularVelocity, 0f); + animator.setDuration(animationTime); + animator.setInterpolator(new DecelerateInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - transform.setBearing((Float) animation.getAnimatedValue()); + transform.setBearing( + transform.getRawBearing() + (float) animation.getAnimatedValue(), + rotateFocalPoint.x, rotateFocalPoint.y, + 0L + ); } }); + animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { + transform.cancelTransitions(); cameraChangeDispatcher.onCameraMoveStarted(REASON_API_ANIMATION); } @Override public void onAnimationCancel(Animator animation) { - reset(); + cameraChangeDispatcher.onCameraIdle(); } @Override public void onAnimationEnd(Animator animation) { - reset(); + cameraChangeDispatcher.onCameraIdle(); } }); + return animator; } } - /** - * Responsible for handling 2 finger shove gestures. - */ - private class ShoveGestureListener implements ShoveGestureDetector.OnShoveGestureListener { - - private long beginTime = 0; - private float totalDelta = 0.0f; - + private final class ShoveGestureListener extends ShoveGestureDetector.SimpleOnShoveGestureListener { @Override public boolean onShoveBegin(ShoveGestureDetector detector) { if (!uiSettings.isTiltGesturesEnabled()) { return false; } - // notify camera change listener + transform.cancelTransitions(); cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + + sendTelemetryEvent(Events.PITCH, detector.getFocalPoint()); + + // disabling move gesture during shove + gesturesManager.getMoveGestureDetector().setEnabled(false); + + notifyOnShoveBeginListeners(detector); + return true; } @Override - public void onShoveEnd(ShoveGestureDetector detector) { - beginTime = 0; - totalDelta = 0.0f; - tiltGestureOccurred = false; + public boolean onShove(ShoveGestureDetector detector, float deltaPixelsSinceLast, float deltaPixelsSinceStart) { + // dispatching start even once more if another detector ended, and this one didn't + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); + + // Get tilt value (scale and clamp) + double pitch = transform.getTilt(); + pitch -= MapboxConstants.SHOVE_PIXEL_CHANGE_FACTOR * deltaPixelsSinceLast; + pitch = MathUtils.clamp(pitch, MapboxConstants.MINIMUM_TILT, MapboxConstants.MAXIMUM_TILT); + + // Tilt the map + transform.setTilt(pitch); + + notifyOnShoveListeners(detector); + + return true; } @Override - public boolean onShove(ShoveGestureDetector detector) { - if (!uiSettings.isTiltGesturesEnabled()) { - return false; - } + public void onShoveEnd(ShoveGestureDetector detector, float velocityX, float velocityY) { + cameraChangeDispatcher.onCameraIdle(); - // Ignore short touches in case it is a tap - // Also ignore small tilt - long time = detector.getEventTime(); - long interval = time - beginTime; - if (!tiltGestureOccurred && (interval <= ViewConfiguration.getTapTimeout())) { - return false; - } + // re-enabling move gesture + gesturesManager.getMoveGestureDetector().setEnabled(true); - // If tilt is large enough ignore a tap - // Also if zoom already started, don't tilt - totalDelta += detector.getShovePixelsDelta(); - if (!tiltGestureOccurred && ((totalDelta > 10.0f) || (totalDelta < -10.0f))) { - tiltGestureOccurred = true; - beginTime = detector.getEventTime(); - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(detector.getFocusX(), detector.getFocusY())); - MapState pitch = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - pitch.setGesture(Events.PITCH); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, pitch)); - } - } + notifyOnShoveEndListeners(detector); + } + } - if (!tiltGestureOccurred) { + private final class TapGestureListener implements MultiFingerTapGestureDetector.OnMultiFingerTapGestureListener { + @Override + public boolean onMultiFingerTap(MultiFingerTapGestureDetector detector, int pointersCount) { + if (!uiSettings.isZoomGesturesEnabled() || pointersCount != 2) { return false; } - // Get tilt value (scale and clamp) - double pitch = transform.getTilt(); - pitch -= 0.1 * detector.getShovePixelsDelta(); - pitch = Math.max(MapboxConstants.MINIMUM_TILT, Math.min(MapboxConstants.MAXIMUM_TILT, pitch)); + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + + if (focalPoint != null) { + transform.zoomOut(focalPoint); + } else { + transform.zoomOut(detector.getFocalPoint()); + } - // Tilt the map - transform.setTilt(pitch); return true; } } + private void sendTelemetryEvent(String eventType, PointF focalPoint) { + if (isZoomValid(transform)) { + MapEventFactory mapEventFactory = new MapEventFactory(); + LatLng latLng = projection.fromScreenLocation(focalPoint); + MapState state = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); + state.setGesture(eventType); + Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, state)); + } + } + + private boolean isZoomValid(Transform transform) { + if (transform == null) { + return false; + } + double mapZoom = transform.getZoom(); + return mapZoom >= MapboxConstants.MINIMUM_ZOOM && mapZoom <= MapboxConstants.MAXIMUM_ZOOM; + } + + void notifyOnMapClickListeners(PointF tapPoint) { + // deprecated API + if (onMapClickListener != null) { + onMapClickListener.onMapClick(projection.fromScreenLocation(tapPoint)); + } + + // new API + for (MapboxMap.OnMapClickListener listener : onMapClickListenerList) { + listener.onMapClick(projection.fromScreenLocation(tapPoint)); + } + } + + void notifyOnMapLongClickListeners(PointF longClickPoint) { + // deprecated API + if (onMapLongClickListener != null) { + onMapLongClickListener.onMapLongClick(projection.fromScreenLocation(longClickPoint)); + } + + // new API + for (MapboxMap.OnMapLongClickListener listener : onMapLongClickListenerList) { + listener.onMapLongClick(projection.fromScreenLocation(longClickPoint)); + } + } + + void notifyOnFlingListeners() { + // deprecated API + if (onFlingListener != null) { + onFlingListener.onFling(); + } + + // new API + for (MapboxMap.OnFlingListener listener : onFlingListenerList) { + listener.onFling(); + } + } + + void notifyOnScrollListeners() { + //deprecated API + if (onScrollListener != null) { + onScrollListener.onScroll(); + } + + // new API + for (MapboxMap.OnScrollListener listener : onScrollListenerList) { + listener.onScroll(); + } + } + + void notifyOnMoveBeginListeners(MoveGestureDetector detector) { + for (MapboxMap.OnMoveListener listener : onMoveListenerList) { + listener.onMoveBegin(detector); + } + } + + void notifyOnMoveListeners(MoveGestureDetector detector) { + for (MapboxMap.OnMoveListener listener : onMoveListenerList) { + listener.onMove(detector); + } + } + + void notifyOnMoveEndListeners(MoveGestureDetector detector) { + for (MapboxMap.OnMoveListener listener : onMoveListenerList) { + listener.onMoveEnd(detector); + } + } + + void notifyOnRotateBeginListeners(RotateGestureDetector detector) { + for (MapboxMap.OnRotateListener listener : onRotateListenerList) { + listener.onRotateBegin(detector); + } + } + + void notifyOnRotateListeners(RotateGestureDetector detector) { + for (MapboxMap.OnRotateListener listener : onRotateListenerList) { + listener.onRotate(detector); + } + } + + void notifyOnRotateEndListeners(RotateGestureDetector detector) { + for (MapboxMap.OnRotateListener listener : onRotateListenerList) { + listener.onRotateEnd(detector); + } + } + + void notifyOnScaleBeginListeners(StandardScaleGestureDetector detector) { + for (MapboxMap.OnScaleListener listener : onScaleListenerList) { + listener.onScaleBegin(detector); + } + } + + void notifyOnScaleListeners(StandardScaleGestureDetector detector) { + for (MapboxMap.OnScaleListener listener : onScaleListenerList) { + listener.onScale(detector); + } + } + + void notifyOnScaleEndListeners(StandardScaleGestureDetector detector) { + for (MapboxMap.OnScaleListener listener : onScaleListenerList) { + listener.onScaleEnd(detector); + } + } + + void notifyOnShoveBeginListeners(ShoveGestureDetector detector) { + for (MapboxMap.OnShoveListener listener : onShoveListenerList) { + listener.onShoveBegin(detector); + } + } + + void notifyOnShoveListeners(ShoveGestureDetector detector) { + for (MapboxMap.OnShoveListener listener : onShoveListenerList) { + listener.onShove(detector); + } + } + + void notifyOnShoveEndListeners(ShoveGestureDetector detector) { + for (MapboxMap.OnShoveListener listener : onShoveListenerList) { + listener.onShoveEnd(detector); + } + } + void setOnMapClickListener(MapboxMap.OnMapClickListener onMapClickListener) { this.onMapClickListener = onMapClickListener; } @@ -981,14 +972,43 @@ final class MapGestureDetector { onScrollListenerList.remove(onScrollListener); } - private boolean isZoomValid(Transform transform) { - if (transform == null) { - return false; - } - double mapZoom = transform.getZoom(); - if (mapZoom < MapboxConstants.MINIMUM_ZOOM || mapZoom > MapboxConstants.MAXIMUM_ZOOM) { - return false; - } - return true; + void addOnMoveListener(MapboxMap.OnMoveListener listener) { + onMoveListenerList.add(listener); + } + + void removeOnMoveListener(MapboxMap.OnMoveListener listener) { + onMoveListenerList.remove(listener); + } + + void addOnRotateListener(MapboxMap.OnRotateListener listener) { + onRotateListenerList.add(listener); + } + + void removeOnRotateListener(MapboxMap.OnRotateListener listener) { + onRotateListenerList.remove(listener); + } + + void addOnScaleListener(MapboxMap.OnScaleListener listener) { + onScaleListenerList.add(listener); + } + + void removeOnScaleListener(MapboxMap.OnScaleListener listener) { + onScaleListenerList.remove(listener); + } + + void addShoveListener(MapboxMap.OnShoveListener listener) { + onShoveListenerList.add(listener); + } + + void removeShoveListener(MapboxMap.OnShoveListener listener) { + onShoveListenerList.remove(listener); + } + + AndroidGesturesManager getGesturesManager() { + return gesturesManager; + } + + void setGesturesManager(AndroidGesturesManager gesturesManager) { + this.gesturesManager = gesturesManager; } -} +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java index d1f01a30f7..9bd9499fff 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java @@ -128,7 +128,7 @@ final class MapKeyListener { // Zoom out PointF focalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - transform.zoom(false, focalPoint); + transform.zoomOut(focalPoint); return true; default: @@ -164,7 +164,7 @@ final class MapKeyListener { // Zoom in PointF focalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - transform.zoom(true, focalPoint); + transform.zoomIn(focalPoint); return true; } @@ -219,7 +219,7 @@ final class MapKeyListener { if (currentTrackballLongPressTimeOut != null) { // Zoom in PointF focalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - transform.zoom(true, focalPoint); + transform.zoomIn(focalPoint); } return true; @@ -261,7 +261,7 @@ final class MapKeyListener { if (!cancelled) { // Zoom out PointF pointF = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - transform.zoom(false, pointF); + transform.zoomOut(pointF); // Ensure the up action is not run currentTrackballLongPressTimeOut = null; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 990c56cb51..90feb228ab 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -23,6 +23,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ZoomButtonsController; +import com.mapbox.android.gestures.AndroidGesturesManager; import com.mapbox.android.telemetry.AppUserTurnstile; import com.mapbox.android.telemetry.Event; import com.mapbox.android.telemetry.MapEventFactory; @@ -42,8 +43,6 @@ import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; import com.mapbox.mapboxsdk.storage.FileSource; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; @@ -52,6 +51,9 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + import timber.log.Timber; import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION; @@ -149,7 +151,7 @@ public class MapView extends FrameLayout { focalPointInvalidator.addListener(createFocalPointChangeListener()); // callback for registering touch listeners - RegisterTouchListener registerTouchListener = new RegisterTouchListener(); + GesturesManagerInteractionListener registerTouchListener = new GesturesManagerInteractionListener(); // callback for zooming in the camera CameraZoomInvalidator zoomInvalidator = new CameraZoomInvalidator(); @@ -184,7 +186,7 @@ public class MapView extends FrameLayout { mapCallback.attachMapboxMap(mapboxMap); // user input - mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings, + mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, annotationManager, cameraChangeDispatcher); mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings); @@ -388,6 +390,7 @@ public class MapView extends FrameLayout { public void onStop() { if (mapboxMap != null) { // map was destroyed before it was started + mapGestureDetector.cancelAnimators(); mapboxMap.onStop(); } @@ -921,7 +924,7 @@ public class MapView extends FrameLayout { } } - private class RegisterTouchListener implements MapboxMap.OnRegisterTouchListener { + private class GesturesManagerInteractionListener implements MapboxMap.OnGesturesManagerInteractionListener { @Override public void onSetMapClickListener(MapboxMap.OnMapClickListener listener) { @@ -982,6 +985,56 @@ public class MapView extends FrameLayout { public void onRemoveFlingListener(MapboxMap.OnFlingListener listener) { mapGestureDetector.removeOnFlingListener(listener); } + + @Override + public void onAddMoveListener(MapboxMap.OnMoveListener listener) { + mapGestureDetector.addOnMoveListener(listener); + } + + @Override + public void onRemoveMoveListener(MapboxMap.OnMoveListener listener) { + mapGestureDetector.removeOnMoveListener(listener); + } + + @Override + public void onAddRotateListener(MapboxMap.OnRotateListener listener) { + mapGestureDetector.addOnRotateListener(listener); + } + + @Override + public void onRemoveRotateListener(MapboxMap.OnRotateListener listener) { + mapGestureDetector.removeOnRotateListener(listener); + } + + @Override + public void onAddScaleListener(MapboxMap.OnScaleListener listener) { + mapGestureDetector.addOnScaleListener(listener); + } + + @Override + public void onRemoveScaleListener(MapboxMap.OnScaleListener listener) { + mapGestureDetector.removeOnScaleListener(listener); + } + + @Override + public void onAddShoveListener(MapboxMap.OnShoveListener listener) { + mapGestureDetector.addShoveListener(listener); + } + + @Override + public void onRemoveShoveListener(MapboxMap.OnShoveListener listener) { + mapGestureDetector.removeShoveListener(listener); + } + + @Override + public AndroidGesturesManager getGesturesManager() { + return mapGestureDetector.getGesturesManager(); + } + + @Override + public void setGesturesManager(AndroidGesturesManager gesturesManager) { + mapGestureDetector.setGesturesManager(gesturesManager); + } } private static class MapZoomControllerListener implements ZoomButtonsController.OnZoomListener { @@ -1019,11 +1072,13 @@ public class MapView extends FrameLayout { } private void onZoom(boolean zoomIn, @Nullable PointF focalPoint) { - if (focalPoint != null) { - transform.zoom(zoomIn, focalPoint); + if (focalPoint == null) { + focalPoint = new PointF(mapWidth / 2, mapHeight / 2); + } + if (zoomIn) { + transform.zoomIn(focalPoint); } else { - PointF centerPoint = new PointF(mapWidth / 2, mapHeight / 2); - transform.zoom(zoomIn, centerPoint); + transform.zoomOut(focalPoint); } } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 2fd9a9010c..cbd3842a02 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -16,6 +16,12 @@ import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; +import com.mapbox.android.core.location.LocationEngine; +import com.mapbox.android.gestures.AndroidGesturesManager; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.RotateGestureDetector; +import com.mapbox.android.gestures.ShoveGestureDetector; +import com.mapbox.android.gestures.StandardScaleGestureDetector; import com.mapbox.geojson.Feature; import com.mapbox.geojson.Geometry; import com.mapbox.mapboxsdk.annotations.Annotation; @@ -43,7 +49,6 @@ import com.mapbox.mapboxsdk.style.layers.Filter; import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.light.Light; import com.mapbox.mapboxsdk.style.sources.Source; -import com.mapbox.android.core.location.LocationEngine; import java.lang.reflect.ParameterizedType; import java.util.HashMap; @@ -73,13 +78,13 @@ public final class MapboxMap { private final MyLocationViewSettings myLocationViewSettings; private final CameraChangeDispatcher cameraChangeDispatcher; - private final OnRegisterTouchListener onRegisterTouchListener; + private final OnGesturesManagerInteractionListener onGesturesManagerInteractionListener; private MapboxMap.OnFpsChangedListener onFpsChangedListener; private PointF focalPoint; MapboxMap(NativeMapView map, Transform transform, UiSettings ui, TrackingSettings tracking, - MyLocationViewSettings myLocationView, Projection projection, OnRegisterTouchListener listener, + MyLocationViewSettings myLocationView, Projection projection, OnGesturesManagerInteractionListener listener, AnnotationManager annotations, CameraChangeDispatcher cameraChangeDispatcher) { this.nativeMapView = map; this.uiSettings = ui; @@ -88,7 +93,7 @@ public final class MapboxMap { this.myLocationViewSettings = myLocationView; this.annotationManager = annotations.bind(this); this.transform = transform; - this.onRegisterTouchListener = listener; + this.onGesturesManagerInteractionListener = listener; this.cameraChangeDispatcher = cameraChangeDispatcher; } @@ -1882,12 +1887,11 @@ public final class MapboxMap { * * @param listener The callback that's invoked when the map is scrolled. * To unset the callback, use null. - * * @deprecated Use {@link #addOnScrollListener(OnScrollListener)} instead. */ @Deprecated public void setOnScrollListener(@Nullable OnScrollListener listener) { - onRegisterTouchListener.onSetScrollListener(listener); + onGesturesManagerInteractionListener.onSetScrollListener(listener); } /** @@ -1895,10 +1899,9 @@ public final class MapboxMap { * * @param listener The callback that's invoked when the map is scrolled. * To unset the callback, use null. - * */ public void addOnScrollListener(@Nullable OnScrollListener listener) { - onRegisterTouchListener.onAddScrollListener(listener); + onGesturesManagerInteractionListener.onAddScrollListener(listener); } /** @@ -1906,10 +1909,9 @@ public final class MapboxMap { * * @param listener The callback that's invoked when the map is scrolled. * To unset the callback, use null. - * */ public void removeOnScrollListener(@Nullable OnScrollListener listener) { - onRegisterTouchListener.onRemoveScrollListener(listener); + onGesturesManagerInteractionListener.onRemoveScrollListener(listener); } /** @@ -1917,12 +1919,11 @@ public final class MapboxMap { * * @param listener The callback that's invoked when the map is flinged. * To unset the callback, use null. - * * @deprecated Use {@link #addOnFlingListener(OnFlingListener)} instead. */ @Deprecated public void setOnFlingListener(@Nullable OnFlingListener listener) { - onRegisterTouchListener.onSetFlingListener(listener); + onGesturesManagerInteractionListener.onSetFlingListener(listener); } /** @@ -1932,7 +1933,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void addOnFlingListener(@Nullable OnFlingListener listener) { - onRegisterTouchListener.onAddFlingListener(listener); + onGesturesManagerInteractionListener.onAddFlingListener(listener); } /** @@ -1942,7 +1943,98 @@ public final class MapboxMap { * To unset the callback, use null. */ public void removeOnFlingListener(@Nullable OnFlingListener listener) { - onRegisterTouchListener.onRemoveFlingListener(listener); + onGesturesManagerInteractionListener.onRemoveFlingListener(listener); + } + + /** + * Adds a callback that's invoked when the map is moved. + * + * @param listener The callback that's invoked when the map is moved. + */ + public void addOnMoveListener(OnMoveListener listener) { + onGesturesManagerInteractionListener.onAddMoveListener(listener); + } + + /** + * Removes a callback that's invoked when the map is moved. + * + * @param listener The callback that's invoked when the map is moved. + */ + public void removeOnMoveListener(OnMoveListener listener) { + onGesturesManagerInteractionListener.onRemoveMoveListener(listener); + } + + /** + * Adds a callback that's invoked when the map is rotated. + * + * @param listener The callback that's invoked when the map is rotated. + */ + public void addOnRotateListener(OnRotateListener listener) { + onGesturesManagerInteractionListener.onAddRotateListener(listener); + } + + /** + * Removes a callback that's invoked when the map is rotated. + * + * @param listener The callback that's invoked when the map is rotated. + */ + public void removeOnRotateListener(OnRotateListener listener) { + onGesturesManagerInteractionListener.onRemoveRotateListener(listener); + } + + /** + * Adds a callback that's invoked when the map is scaled. + * + * @param listener The callback that's invoked when the map is scaled. + */ + public void addOnScaleListener(OnScaleListener listener) { + onGesturesManagerInteractionListener.onAddScaleListener(listener); + } + + /** + * Removes a callback that's invoked when the map is scaled. + * + * @param listener The callback that's invoked when the map is scaled. + */ + public void removeOnScaleListener(OnScaleListener listener) { + onGesturesManagerInteractionListener.onRemoveScaleListener(listener); + } + + /** + * Adds a callback that's invoked when the map is tilted. + * + * @param listener The callback that's invoked when the map is tilted. + */ + public void addOnShoveListener(OnShoveListener listener) { + onGesturesManagerInteractionListener.onAddShoveListener(listener); + } + + /** + * Remove a callback that's invoked when the map is tilted. + * + * @param listener The callback that's invoked when the map is tilted. + */ + public void removeOnShoveListener(OnShoveListener listener) { + onGesturesManagerInteractionListener.onRemoveShoveListener(listener); + } + + /** + * Sets a custom {@link AndroidGesturesManager} to handle {@link android.view.MotionEvent}s registered by the map. + * + * @param androidGesturesManager Gestures manager that interprets gestures based on the motion events. + * @see mapbox-gestures-android library + */ + public void setGesturesManager(AndroidGesturesManager androidGesturesManager) { + onGesturesManagerInteractionListener.setGesturesManager(androidGesturesManager); + } + + /** + * Get current {@link AndroidGesturesManager} that handles {@link android.view.MotionEvent}s registered by the map. + * + * @return Current gestures manager. + */ + public AndroidGesturesManager getGesturesManager() { + return onGesturesManagerInteractionListener.getGesturesManager(); } /** @@ -1950,12 +2042,11 @@ public final class MapboxMap { * * @param listener The callback that's invoked when the user clicks on the map view. * To unset the callback, use null. - * * @deprecated Use {@link #addOnMapClickListener(OnMapClickListener)} instead. */ @Deprecated public void setOnMapClickListener(@Nullable OnMapClickListener listener) { - onRegisterTouchListener.onSetMapClickListener(listener); + onGesturesManagerInteractionListener.onSetMapClickListener(listener); } /** @@ -1965,7 +2056,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void addOnMapClickListener(@Nullable OnMapClickListener listener) { - onRegisterTouchListener.onAddMapClickListener(listener); + onGesturesManagerInteractionListener.onAddMapClickListener(listener); } /** @@ -1975,7 +2066,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void removeOnMapClickListener(@Nullable OnMapClickListener listener) { - onRegisterTouchListener.onRemoveMapClickListener(listener); + onGesturesManagerInteractionListener.onRemoveMapClickListener(listener); } /** @@ -1983,12 +2074,11 @@ public final class MapboxMap { * * @param listener The callback that's invoked when the user long clicks on the map view. * To unset the callback, use null. - * * @deprecated Use {@link #addOnMapLongClickListener(OnMapLongClickListener)} instead. */ @Deprecated public void setOnMapLongClickListener(@Nullable OnMapLongClickListener listener) { - onRegisterTouchListener.onSetMapLongClickListener(listener); + onGesturesManagerInteractionListener.onSetMapLongClickListener(listener); } /** @@ -1998,7 +2088,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void addOnMapLongClickListener(@Nullable OnMapLongClickListener listener) { - onRegisterTouchListener.onAddMapLongClickListener(listener); + onGesturesManagerInteractionListener.onAddMapLongClickListener(listener); } /** @@ -2008,7 +2098,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void removeOnMapLongClickListener(@Nullable OnMapLongClickListener listener) { - onRegisterTouchListener.onRemoveMapLongClickListener(listener); + onGesturesManagerInteractionListener.onRemoveMapLongClickListener(listener); } /** @@ -2267,7 +2357,9 @@ public final class MapboxMap { * Interface definition for a callback to be invoked when the map is scrolled. * * @see MapboxMap#setOnScrollListener(OnScrollListener) + * @deprecated Use {@link OnMoveListener} instead. */ + @Deprecated public interface OnScrollListener { /** * Called when the map is scrolled. @@ -2275,6 +2367,58 @@ public final class MapboxMap { void onScroll(); } + /** + * Interface definition for a callback to be invoked when the map is moved. + * + * @see MapboxMap#addOnMoveListener(OnMoveListener) + */ + public interface OnMoveListener { + void onMoveBegin(MoveGestureDetector detector); + + void onMove(MoveGestureDetector detector); + + void onMoveEnd(MoveGestureDetector detector); + } + + /** + * Interface definition for a callback to be invoked when the map is rotated. + * + * @see MapboxMap#addOnRotateListener(OnRotateListener) + */ + public interface OnRotateListener { + void onRotateBegin(RotateGestureDetector detector); + + void onRotate(RotateGestureDetector detector); + + void onRotateEnd(RotateGestureDetector detector); + } + + /** + * Interface definition for a callback to be invoked when the map is scaled. + * + * @see MapboxMap#addOnScaleListener(OnScaleListener) + */ + public interface OnScaleListener { + void onScaleBegin(StandardScaleGestureDetector detector); + + void onScale(StandardScaleGestureDetector detector); + + void onScaleEnd(StandardScaleGestureDetector detector); + } + + /** + * Interface definition for a callback to be invoked when the map is tilted. + * + * @see MapboxMap#addOnShoveListener(OnShoveListener) + */ + public interface OnShoveListener { + void onShoveBegin(ShoveGestureDetector detector); + + void onShove(ShoveGestureDetector detector); + + void onShoveEnd(ShoveGestureDetector detector); + } + /** * Interface definition for a callback to be invoked when the camera changes position. * @@ -2377,7 +2521,7 @@ public final class MapboxMap { * Interface definition for a callback to be invoked when a user registers an listener that is * related to touch and click events. */ - interface OnRegisterTouchListener { + interface OnGesturesManagerInteractionListener { void onSetMapClickListener(OnMapClickListener listener); void onAddMapClickListener(OnMapClickListener listener); @@ -2401,6 +2545,26 @@ public final class MapboxMap { void onAddFlingListener(OnFlingListener listener); void onRemoveFlingListener(OnFlingListener listener); + + void onAddMoveListener(OnMoveListener listener); + + void onRemoveMoveListener(OnMoveListener listener); + + void onAddRotateListener(OnRotateListener listener); + + void onRemoveRotateListener(OnRotateListener listener); + + void onAddScaleListener(OnScaleListener listener); + + void onRemoveScaleListener(OnScaleListener listener); + + void onAddShoveListener(OnShoveListener listener); + + void onRemoveShoveListener(OnShoveListener listener); + + AndroidGesturesManager getGesturesManager(); + + void setGesturesManager(AndroidGesturesManager gesturesManager); } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java index 84a601039f..43c943a16f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java @@ -205,6 +205,8 @@ final class Transform implements MapView.OnMapChangedListener { // cancel ongoing transitions mapView.cancelTransitions(); + + cameraChangeDispatcher.onCameraIdle(); } @UiThread @@ -235,39 +237,37 @@ final class Transform implements MapView.OnMapChangedListener { return mapView.getZoom(); } - void zoom(boolean zoomIn, @NonNull PointF focalPoint) { + void zoomIn(@NonNull PointF focalPoint) { CameraPosition cameraPosition = invalidateCameraPosition(); if (cameraPosition != null) { - int newZoom = (int) Math.round(cameraPosition.zoom + (zoomIn ? 1 : -1)); - setZoom(newZoom, focalPoint, MapboxConstants.ANIMATION_DURATION, false); - } else { - // we are not transforming, notify about being idle - cameraChangeDispatcher.onCameraIdle(); + int newZoom = (int) Math.round(cameraPosition.zoom + 1); + setZoom(newZoom, focalPoint, MapboxConstants.ANIMATION_DURATION); } } - void zoom(double zoomAddition, @NonNull PointF focalPoint, long duration) { + void zoomOut(@NonNull PointF focalPoint) { CameraPosition cameraPosition = invalidateCameraPosition(); if (cameraPosition != null) { - int newZoom = (int) Math.round(cameraPosition.zoom + zoomAddition); - setZoom(newZoom, focalPoint, duration, false); - } else { - // we are not transforming, notify about being idle - cameraChangeDispatcher.onCameraIdle(); + int newZoom = (int) Math.round(cameraPosition.zoom - 1); + setZoom(newZoom, focalPoint, MapboxConstants.ANIMATION_DURATION); } } + void zoomBy(double zoomAddition, @NonNull PointF focalPoint) { + setZoom(mapView.getZoom() + zoomAddition, focalPoint, 0); + } + void setZoom(double zoom, @NonNull PointF focalPoint) { - setZoom(zoom, focalPoint, 0, false); + setZoom(zoom, focalPoint, 0); } - void setZoom(double zoom, @NonNull PointF focalPoint, long duration, final boolean isAnimator) { + void setZoom(double zoom, @NonNull PointF focalPoint, long duration) { if (mapView != null) { mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() { @Override public void onMapChanged(int change) { if (change == MapView.REGION_DID_CHANGE_ANIMATED) { - if (!isAnimator) { + if (duration > 0) { cameraChangeDispatcher.onCameraIdle(); } mapView.removeOnMapChangedListener(this); @@ -361,10 +361,6 @@ final class Transform implements MapView.OnMapChangedListener { } } - void zoomBy(double z, float x, float y) { - mapView.setZoom(mapView.getZoom() + z, new PointF(x, y), 0); - } - void moveBy(double offsetX, double offsetY, long duration) { if (duration > 0) { mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml index 1c6a265587..00fc05cf6d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml @@ -6,4 +6,13 @@ 8dp 92dp 18dp + + + 150dp + + + 100dp + + + 0.025dp diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java index eeb00355bd..5de55f47c9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java @@ -2,8 +2,13 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.PointF; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.RotateGestureDetector; +import com.mapbox.android.gestures.ShoveGestureDetector; +import com.mapbox.android.gestures.StandardScaleGestureDetector; import com.mapbox.mapboxsdk.geometry.LatLng; +import org.junit.Before; import org.junit.Test; import static org.mockito.Mockito.mock; @@ -13,16 +18,23 @@ import static org.mockito.Mockito.when; public class MapTouchListenersTest { - @Test - public void onMapClickListenerTest() throws Exception { - LatLng latLng = new LatLng(); - PointF pointF = new PointF(); + private MapGestureDetector mapGestureDetector; + private LatLng latLng; + private PointF pointF; + + @Before + public void setUp() throws Exception { + latLng = new LatLng(); + pointF = new PointF(); Projection projection = mock(Projection.class); when(projection.fromScreenLocation(pointF)).thenReturn(latLng); - MapGestureDetector mapGestureDetector = new MapGestureDetector(null, - null, projection, null, null, null, null); + mapGestureDetector = new MapGestureDetector(null, + null, projection, null, null, null); + } + @Test + public void onMapClickListenerTest() throws Exception { MapboxMap.OnMapClickListener listener = mock(MapboxMap.OnMapClickListener.class); mapGestureDetector.addOnMapClickListener(listener); mapGestureDetector.notifyOnMapClickListeners(pointF); @@ -35,14 +47,6 @@ public class MapTouchListenersTest { @Test public void onMapLongClickListenerTest() throws Exception { - LatLng latLng = new LatLng(); - PointF pointF = new PointF(); - - Projection projection = mock(Projection.class); - when(projection.fromScreenLocation(pointF)).thenReturn(latLng); - MapGestureDetector mapGestureDetector = new MapGestureDetector(null, - null, projection, null, null, null, null); - MapboxMap.OnMapLongClickListener listener = mock(MapboxMap.OnMapLongClickListener.class); mapGestureDetector.addOnMapLongClickListener(listener); mapGestureDetector.notifyOnMapLongClickListeners(pointF); @@ -55,14 +59,6 @@ public class MapTouchListenersTest { @Test public void onFlingListenerTest() throws Exception { - LatLng latLng = new LatLng(); - PointF pointF = new PointF(); - - Projection projection = mock(Projection.class); - when(projection.fromScreenLocation(pointF)).thenReturn(latLng); - MapGestureDetector mapGestureDetector = new MapGestureDetector(null, - null, projection, null, null, null, null); - MapboxMap.OnFlingListener listener = mock(MapboxMap.OnFlingListener.class); mapGestureDetector.addOnFlingListener(listener); mapGestureDetector.notifyOnFlingListeners(); @@ -75,14 +71,6 @@ public class MapTouchListenersTest { @Test public void onScrollListenerTest() throws Exception { - LatLng latLng = new LatLng(); - PointF pointF = new PointF(); - - Projection projection = mock(Projection.class); - when(projection.fromScreenLocation(pointF)).thenReturn(latLng); - MapGestureDetector mapGestureDetector = new MapGestureDetector(null, - null, projection, null, null, null, null); - MapboxMap.OnScrollListener listener = mock(MapboxMap.OnScrollListener.class); mapGestureDetector.addOnScrollListener(listener); mapGestureDetector.notifyOnScrollListeners(); @@ -92,4 +80,88 @@ public class MapTouchListenersTest { mapGestureDetector.notifyOnScrollListeners(); verify(listener, times(1)).onScroll(); } + + @Test + public void onMoveListenerTest() throws Exception { + MapboxMap.OnMoveListener listener = mock(MapboxMap.OnMoveListener.class); + MoveGestureDetector detector = mock(MoveGestureDetector.class); + mapGestureDetector.addOnMoveListener(listener); + mapGestureDetector.notifyOnMoveBeginListeners(detector); + mapGestureDetector.notifyOnMoveListeners(detector); + mapGestureDetector.notifyOnMoveEndListeners(detector); + verify(listener, times(1)).onMoveBegin(detector); + verify(listener, times(1)).onMove(detector); + verify(listener, times(1)).onMoveEnd(detector); + + mapGestureDetector.removeOnMoveListener(listener); + mapGestureDetector.notifyOnMoveBeginListeners(detector); + mapGestureDetector.notifyOnMoveListeners(detector); + mapGestureDetector.notifyOnMoveEndListeners(detector); + verify(listener, times(1)).onMoveBegin(detector); + verify(listener, times(1)).onMove(detector); + verify(listener, times(1)).onMoveEnd(detector); + } + + @Test + public void onRotateListenerTest() throws Exception { + MapboxMap.OnRotateListener listener = mock(MapboxMap.OnRotateListener.class); + RotateGestureDetector detector = mock(RotateGestureDetector.class); + mapGestureDetector.addOnRotateListener(listener); + mapGestureDetector.notifyOnRotateBeginListeners(detector); + mapGestureDetector.notifyOnRotateListeners(detector); + mapGestureDetector.notifyOnRotateEndListeners(detector); + verify(listener, times(1)).onRotateBegin(detector); + verify(listener, times(1)).onRotate(detector); + verify(listener, times(1)).onRotateEnd(detector); + + mapGestureDetector.removeOnRotateListener(listener); + mapGestureDetector.notifyOnRotateBeginListeners(detector); + mapGestureDetector.notifyOnRotateListeners(detector); + mapGestureDetector.notifyOnRotateEndListeners(detector); + verify(listener, times(1)).onRotateBegin(detector); + verify(listener, times(1)).onRotate(detector); + verify(listener, times(1)).onRotateEnd(detector); + } + + @Test + public void onScaleListenerTest() throws Exception { + MapboxMap.OnScaleListener listener = mock(MapboxMap.OnScaleListener.class); + StandardScaleGestureDetector detector = mock(StandardScaleGestureDetector.class); + mapGestureDetector.addOnScaleListener(listener); + mapGestureDetector.notifyOnScaleBeginListeners(detector); + mapGestureDetector.notifyOnScaleListeners(detector); + mapGestureDetector.notifyOnScaleEndListeners(detector); + verify(listener, times(1)).onScaleBegin(detector); + verify(listener, times(1)).onScale(detector); + verify(listener, times(1)).onScaleEnd(detector); + + mapGestureDetector.removeOnScaleListener(listener); + mapGestureDetector.notifyOnScaleBeginListeners(detector); + mapGestureDetector.notifyOnScaleListeners(detector); + mapGestureDetector.notifyOnScaleEndListeners(detector); + verify(listener, times(1)).onScaleBegin(detector); + verify(listener, times(1)).onScale(detector); + verify(listener, times(1)).onScaleEnd(detector); + } + + @Test + public void onShoveListenerTest() throws Exception { + MapboxMap.OnShoveListener listener = mock(MapboxMap.OnShoveListener.class); + ShoveGestureDetector detector = mock(ShoveGestureDetector.class); + mapGestureDetector.addShoveListener(listener); + mapGestureDetector.notifyOnShoveBeginListeners(detector); + mapGestureDetector.notifyOnShoveListeners(detector); + mapGestureDetector.notifyOnShoveEndListeners(detector); + verify(listener, times(1)).onShoveBegin(detector); + verify(listener, times(1)).onShove(detector); + verify(listener, times(1)).onShoveEnd(detector); + + mapGestureDetector.removeShoveListener(listener); + mapGestureDetector.notifyOnShoveBeginListeners(detector); + mapGestureDetector.notifyOnShoveListeners(detector); + mapGestureDetector.notifyOnShoveEndListeners(detector); + verify(listener, times(1)).onShoveBegin(detector); + verify(listener, times(1)).onShove(detector); + verify(listener, times(1)).onShoveEnd(detector); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java index 5e9f94db28..d61947f00e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java @@ -23,7 +23,7 @@ public class MapboxMapTest { mock(TrackingSettings.class), mock(MyLocationViewSettings.class), mock(Projection.class), - mock(MapboxMap.OnRegisterTouchListener.class), + mock(MapboxMap.OnGesturesManagerInteractionListener.class), mock(AnnotationManager.class), mock(CameraChangeDispatcher.class)); } diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index b1b9a065ad..695cca3a29 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -8,24 +8,26 @@ ext { ] versions = [ - mapboxServices: '3.0.0-beta.2', + mapboxServices : '3.0.0-beta.2', mapboxTelemetry: '3.0.0-beta.1', - supportLib : '25.4.0', - espresso : '3.0.1', - testRunner : '1.0.1', - leakCanary : '1.5.1', - lost : '3.0.4', - junit : '4.12', - mockito : '2.10.0', - robolectric : '3.5.1', - timber : '4.5.1', - okhttp : '3.9.1' + mapboxGestures : '0.1.0-20180227.133736-12', + supportLib : '25.4.0', + espresso : '3.0.1', + testRunner : '1.0.1', + leakCanary : '1.5.1', + lost : '3.0.4', + junit : '4.12', + mockito : '2.10.0', + robolectric : '3.5.1', + timber : '4.5.1', + okhttp : '3.9.1' ] dependenciesList = [ mapboxJavaServices : "com.mapbox.mapboxsdk:mapbox-sdk-services:${versions.mapboxServices}", mapboxJavaGeoJSON : "com.mapbox.mapboxsdk:mapbox-sdk-geojson:${versions.mapboxServices}", mapboxAndroidTelemetry: "com.mapbox.mapboxsdk:mapbox-android-telemetry:${versions.mapboxTelemetry}", + mapboxAndroidGestures : "com.mapbox.mapboxsdk:mapbox-android-gestures:${versions.mapboxGestures}@aar", // for testApp mapboxJavaTurf : "com.mapbox.mapboxsdk:mapbox-sdk-turf:${versions.mapboxServices}", -- cgit v1.2.1 From 20c79d9e71a660a6d3b4e377b033f0d68a5327fa Mon Sep 17 00:00:00 2001 From: Cameron Mace Date: Wed, 28 Feb 2018 14:38:26 -0500 Subject: upgraded telem version (#11338) * upgraded telem version * use telem method instead of Okhttp * use telem util in test --- .../src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java | 6 +++--- .../test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java | 5 ++--- platform/android/dependencies.gradle | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java index caee493e6f..129e75965e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java @@ -1,6 +1,5 @@ package com.mapbox.mapboxsdk.http; - import android.content.Context; import android.content.pm.PackageInfo; import android.os.Build; @@ -27,9 +26,10 @@ import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import okhttp3.internal.Util; import timber.log.Timber; +import static com.mapbox.services.android.telemetry.utils.TelemetryUtils.toHumanReadableAscii; + import static android.util.Log.DEBUG; import static android.util.Log.INFO; import static android.util.Log.WARN; @@ -204,7 +204,7 @@ class HTTPRequest implements Callback { private String getUserAgent() { if (USER_AGENT_STRING == null) { - return USER_AGENT_STRING = Util.toHumanReadableAscii( + return USER_AGENT_STRING = toHumanReadableAscii( String.format("%s %s (%s) Android/%s (%s)", getApplicationIdentifier(), BuildConfig.MAPBOX_VERSION_STRING, diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java index 94a6dc2194..5b54496329 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java @@ -2,8 +2,7 @@ package com.mapbox.mapboxsdk.telemetry; import org.junit.Test; -import okhttp3.internal.Util; - +import static com.mapbox.services.android.telemetry.utils.TelemetryUtils.toHumanReadableAscii; import static junit.framework.Assert.assertEquals; public class HttpTransportTest { @@ -15,6 +14,6 @@ public class HttpTransportTest { final String asciiVersion = "Sveriges Fj?ll/1.0/1 MapboxEventsAndroid/4.0.0-SNAPSHOT"; assertEquals("asciiVersion and swedishUserAgent should match", asciiVersion, - Util.toHumanReadableAscii(swedishUserAgent)); + toHumanReadableAscii(swedishUserAgent)); } } diff --git a/platform/android/dependencies.gradle b/platform/android/dependencies.gradle index 541b3c5236..f3ec2f5a25 100644 --- a/platform/android/dependencies.gradle +++ b/platform/android/dependencies.gradle @@ -7,7 +7,7 @@ ext { versionCode = 11 versionName = "5.0.0" - mapboxServicesVersion = "2.2.9" + mapboxServicesVersion = "2.2.10" supportLibVersion = "25.4.0" espressoVersion = '3.0.1' testRunnerVersion = '1.0.1' -- cgit v1.2.1 From 7623ed99bcf8cd6a1034ffac6cdef87e2268762a Mon Sep 17 00:00:00 2001 From: osana Date: Mon, 19 Feb 2018 22:55:43 -0500 Subject: [android] jni clean up - missing a couple DeleteLocalRef --- platform/android/src/conversion/collection.hpp | 1 + platform/android/src/file_source.cpp | 5 ++++- platform/android/src/map/camera_position.cpp | 4 +++- platform/android/src/map/image.cpp | 4 +++- 4 files changed, 11 insertions(+), 3 deletions(-) (limited to 'platform/android') diff --git a/platform/android/src/conversion/collection.hpp b/platform/android/src/conversion/collection.hpp index 549121c7ef..2b953e73f4 100644 --- a/platform/android/src/conversion/collection.hpp +++ b/platform/android/src/conversion/collection.hpp @@ -28,6 +28,7 @@ inline jni::jobject* toArrayList(JNIEnv& env, jni::jarray& array) { inline std::vector toVector(JNIEnv& env, jni::jarray& array) { std::vector vector; std::size_t len = jni::GetArrayLength(env, array); + vector.reserve(len); for (std::size_t i = 0; i < len; i++) { jni::jstring* jstr = reinterpret_cast(jni::GetObjectArrayElement(env, array, i)); diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp index 6a9d7badb0..612619a30b 100644 --- a/platform/android/src/file_source.cpp +++ b/platform/android/src/file_source.cpp @@ -124,8 +124,11 @@ jni::Class FileSource::ResourceTransformC std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, jni::Object callback, int kind, std::string url_) { static auto method = FileSource::ResourceTransformCallback::javaClass.GetMethod(env, "onURL"); auto url = jni::Make(env, url_); + url = callback.Call(env, method, kind, url); - return jni::Make(env, url); + auto urlStr = jni::Make(env, url); + jni::DeleteLocalRef(env, url); + return urlStr; } } // namespace android diff --git a/platform/android/src/map/camera_position.cpp b/platform/android/src/map/camera_position.cpp index 1fc5f9789f..01ffc6530b 100644 --- a/platform/android/src/map/camera_position.cpp +++ b/platform/android/src/map/camera_position.cpp @@ -33,7 +33,9 @@ mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, jni::Obje static auto tilt = CameraPosition::javaClass.GetField(env, "tilt"); static auto zoom = CameraPosition::javaClass.GetField(env, "zoom"); - auto center = LatLng::getLatLng(env, position.Get(env, target)); + auto jtarget = position.Get(env, target); + auto center = LatLng::getLatLng(env, jtarget); + jni::DeleteLocalRef(env, jtarget); return mbgl::CameraOptions { center, diff --git a/platform/android/src/map/image.cpp b/platform/android/src/map/image.cpp index 5f5c90eddd..52e0e0d255 100644 --- a/platform/android/src/map/image.cpp +++ b/platform/android/src/map/image.cpp @@ -16,7 +16,9 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, jni::Object image) { auto width = image.Get(env, widthField); auto pixelRatio = image.Get(env, pixelRatioField); auto pixels = image.Get(env, bufferField); - auto name = jni::Make(env, image.Get(env, nameField)); + auto jName = image.Get(env, nameField); + auto name = jni::Make(env, jName); + jni::DeleteLocalRef(env, jName); jni::NullCheck(env, &pixels); std::size_t size = pixels.Length(env); -- cgit v1.2.1 From 0fe1219bfd5dc93f6cf256cb247f58496022d2c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 22 Feb 2018 10:01:48 +0100 Subject: [android] expose ImageSource coordinates setter (#11262) --- .../java/com/mapbox/mapboxsdk/style/sources/ImageSource.java | 11 +++++++++++ platform/android/src/style/sources/image_source.cpp | 8 +++++++- platform/android/src/style/sources/image_source.hpp | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java index 84e5e96fa4..b7679b5a16 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java @@ -124,6 +124,15 @@ public class ImageSource extends Source { return nativeGetUrl(); } + /** + * Updates the latitude and longitude of the four corners of the image + * + * @param latLngQuad latitude and longitude of the four corners of the image + */ + public void setCoordinates(LatLngQuad latLngQuad) { + nativeSetCoordinates(latLngQuad); + } + protected native void initialize(String layerId, LatLngQuad payload); protected native void nativeSetUrl(String url); @@ -132,6 +141,8 @@ public class ImageSource extends Source { protected native void nativeSetImage(Bitmap bitmap); + protected native void nativeSetCoordinates(LatLngQuad latLngQuad); + @Override protected native void finalize() throws Throwable; } diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp index d46b367c53..e28a7862f8 100644 --- a/platform/android/src/style/sources/image_source.cpp +++ b/platform/android/src/style/sources/image_source.cpp @@ -43,6 +43,11 @@ namespace android { source.as()->setImage(Bitmap::GetImage(env, bitmap)); } + void ImageSource::setCoordinates(jni::JNIEnv& env, jni::Object coordinatesObject) { + source.as()->setCoordinates( + LatLngQuad::getLatLngArray(env, coordinatesObject)); + } + jni::Class ImageSource::javaClass; jni::jobject* ImageSource::createJavaPeer(jni::JNIEnv& env) { @@ -64,7 +69,8 @@ namespace android { "finalize", METHOD(&ImageSource::setURL, "nativeSetUrl"), METHOD(&ImageSource::getURL, "nativeGetUrl"), - METHOD(&ImageSource::setImage, "nativeSetImage") + METHOD(&ImageSource::setImage, "nativeSetImage"), + METHOD(&ImageSource::setCoordinates, "nativeSetCoordinates") ); } diff --git a/platform/android/src/style/sources/image_source.hpp b/platform/android/src/style/sources/image_source.hpp index 9787a7294f..c600580119 100644 --- a/platform/android/src/style/sources/image_source.hpp +++ b/platform/android/src/style/sources/image_source.hpp @@ -29,6 +29,7 @@ public: jni::String getURL(jni::JNIEnv&); void setImage(jni::JNIEnv&, jni::Object); + void setCoordinates(jni::JNIEnv&, jni::Object); jni::jobject* createJavaPeer(jni::JNIEnv&); -- cgit v1.2.1 From 54c3fcdec86a46649fa22af169d88fc377554157 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 19 Feb 2018 19:08:07 +0100 Subject: [android] - check if hosting Activity isn't finishing before showing an dialog --- .../com/mapbox/mapboxsdk/maps/AttributionDialogManager.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java index 2956d864e6..48de768e64 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.maps; +import android.app.Activity; import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.Context; @@ -49,7 +50,17 @@ class AttributionDialogManager implements View.OnClickListener, DialogInterface. @Override public void onClick(View view) { attributionSet = new AttributionBuilder(mapboxMap).build(); - showAttributionDialog(); + + boolean isActivityFinishing = false; + if (context instanceof Activity) { + isActivityFinishing = ((Activity) context).isFinishing(); + } + + // check is hosting activity isn't finishing + // https://github.com/mapbox/mapbox-gl-native/issues/11238 + if (!isActivityFinishing) { + showAttributionDialog(); + } } private void showAttributionDialog() { -- cgit v1.2.1 From c84670e683f2e58aaa74fe3c236f6368950e2dab Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 19 Feb 2018 18:33:57 +0200 Subject: [android] custom layer example - fix fragment shader source for opengl es 2 phones --- platform/android/src/example_custom_layer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp index 1ed68d0835..4467cd5e23 100644 --- a/platform/android/src/example_custom_layer.cpp +++ b/platform/android/src/example_custom_layer.cpp @@ -6,7 +6,7 @@ #include static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }"; -static const GLchar * fragmentShaderSource = "uniform vec4 fill_color; void main() { gl_FragColor = fill_color; }"; +static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; void main() { gl_FragColor = fill_color; }"; class ExampleCustomLayer { public: -- cgit v1.2.1 From 7fc676ed417ab509374f59a1e081605495cadcb3 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 19 Feb 2018 18:34:32 +0200 Subject: [android] custom layer example - add error checking to debug issues more easily --- platform/android/src/example_custom_layer.cpp | 170 +++++++++++++++++++++----- 1 file changed, 142 insertions(+), 28 deletions(-) (limited to 'platform/android') diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp index 4467cd5e23..4d1954f095 100644 --- a/platform/android/src/example_custom_layer.cpp +++ b/platform/android/src/example_custom_layer.cpp @@ -2,8 +2,111 @@ #include #include - +#include #include +#include + +// DEBUGGING + +const char* stringFromError(GLenum err) { + switch (err) { + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL_INVALID_FRAMEBUFFER_OPERATION"; + + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + +#ifdef GL_TABLE_TOO_LARGE + case GL_TABLE_TOO_LARGE: + return "GL_TABLE_TOO_LARGE"; +#endif + +#ifdef GL_STACK_OVERFLOW + case GL_STACK_OVERFLOW: + return "GL_STACK_OVERFLOW"; +#endif + +#ifdef GL_STACK_UNDERFLOW + case GL_STACK_UNDERFLOW: + return "GL_STACK_UNDERFLOW"; +#endif + +#ifdef GL_CONTEXT_LOST + case GL_CONTEXT_LOST: + return "GL_CONTEXT_LOST"; +#endif + + default: + return "GL_UNKNOWN"; + } +} + +struct Error : std::runtime_error { + using std::runtime_error::runtime_error; +}; + +void checkError(const char *cmd, const char *file, int line) { + + GLenum err = GL_NO_ERROR; + if ((err = glGetError()) != GL_NO_ERROR) { + std::string message = std::string(cmd) + ": Error " + stringFromError(err); + + // Check for further errors + while ((err = glGetError()) != GL_NO_ERROR) { + message += ", "; + message += stringFromError(err); + } + + mbgl::Log::Error(mbgl::Event::General, message + " at " + file + ":" + mbgl::util::toString(line)); + throw Error(message + " at " + file + ":" + mbgl::util::toString(line)); + } +} + +#ifndef NDEBUG +#define GL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() noexcept(false) { checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }()) +#else +#define GL_CHECK_ERROR(cmd) (cmd) +#endif + +void checkLinkStatus(GLuint program) { + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, &isLinked); + if (isLinked == GL_FALSE) { + GLint maxLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + GLchar infoLog[maxLength]; + glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); + mbgl::Log::Info(mbgl::Event::General, &infoLog[0]); + throw Error(infoLog); + } + +} + +void checkCompileStatus(GLuint shader) { + GLint isCompiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); + if (isCompiled == GL_FALSE) { + GLint maxLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + + // The maxLength includes the NULL character + GLchar errorLog[maxLength]; + glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); + mbgl::Log::Error(mbgl::Event::General, &errorLog[0]); + throw Error(errorLog); + } +} + +// /DEBUGGING static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }"; static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; void main() { gl_FragColor = fill_color; }"; @@ -24,37 +127,48 @@ public: void initialize() { mbgl::Log::Info(mbgl::Event::General, "Initialize"); - program = glCreateProgram(); - vertexShader = glCreateShader(GL_VERTEX_SHADER); - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); - glCompileShader(vertexShader); - glAttachShader(program, vertexShader); - glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); - glCompileShader(fragmentShader); - glAttachShader(program, fragmentShader); - glLinkProgram(program); - a_pos = glGetAttribLocation(program, "a_pos"); - fill_color = glGetUniformLocation(program, "fill_color"); - - GLfloat background[] = { -1,-1, 1,-1, -1,1, 1,1 }; - glGenBuffers(1, &buffer); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW); + + // Debug info + int maxAttrib; + GL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttrib)); + mbgl::Log::Info(mbgl::Event::General, "Max vertex attributes: %i", maxAttrib); + + program = GL_CHECK_ERROR(glCreateProgram()); + vertexShader = GL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)); + fragmentShader = GL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER)); + + GL_CHECK_ERROR(glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr)); + GL_CHECK_ERROR(glCompileShader(vertexShader)); + checkCompileStatus(vertexShader); + GL_CHECK_ERROR(glAttachShader(program, vertexShader)); + GL_CHECK_ERROR(glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr)); + GL_CHECK_ERROR(glCompileShader(fragmentShader)); + checkCompileStatus(fragmentShader); + GL_CHECK_ERROR(glAttachShader(program, fragmentShader)); + GL_CHECK_ERROR(glLinkProgram(program)); + checkLinkStatus(program); + + a_pos = GL_CHECK_ERROR(glGetAttribLocation(program, "a_pos")); + fill_color = GL_CHECK_ERROR(glGetUniformLocation(program, "fill_color")); + + GLfloat background[] = { -1, -1, 1, -1, -1, 1, 1, 1 }; + GL_CHECK_ERROR(glGenBuffers(1, &buffer)); + GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); + GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW)); } void render() { mbgl::Log::Info(mbgl::Event::General, "Render"); - glUseProgram(program); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glEnableVertexAttribArray(a_pos); - glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL); - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - glUniform4fv(fill_color, 1, color); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + GL_CHECK_ERROR(glUseProgram(program)); + GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); + GL_CHECK_ERROR(glEnableVertexAttribArray(a_pos)); + GL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL)); + GL_CHECK_ERROR(glDisable(GL_STENCIL_TEST)); + GL_CHECK_ERROR(glDisable(GL_DEPTH_TEST)); + GL_CHECK_ERROR(glUniform4fv(fill_color, 1, color)); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); + } GLuint program = 0; -- cgit v1.2.1 From 4b32228cc2fbf7f6dc720edd32a17bc4c7f44071 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Thu, 22 Feb 2018 16:00:14 +0200 Subject: [android] custom layer example - remove dependencies on mbgl logging and string headers --- platform/android/src/example_custom_layer.cpp | 49 ++++++++++++++------------- 1 file changed, 26 insertions(+), 23 deletions(-) (limited to 'platform/android') diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp index 4d1954f095..46fcd96ffa 100644 --- a/platform/android/src/example_custom_layer.cpp +++ b/platform/android/src/example_custom_layer.cpp @@ -1,13 +1,13 @@ #include #include - -#include -#include +#include +#include #include -#include // DEBUGGING +const char* LOG_TAG = "Custom Layer Example"; + const char* stringFromError(GLenum err) { switch (err) { case GL_INVALID_ENUM: @@ -58,16 +58,17 @@ void checkError(const char *cmd, const char *file, int line) { GLenum err = GL_NO_ERROR; if ((err = glGetError()) != GL_NO_ERROR) { - std::string message = std::string(cmd) + ": Error " + stringFromError(err); + std::ostringstream message; + message << cmd << ": Error " << stringFromError(err); // Check for further errors while ((err = glGetError()) != GL_NO_ERROR) { - message += ", "; - message += stringFromError(err); + message << ", " << stringFromError(err); } - mbgl::Log::Error(mbgl::Event::General, message + " at " + file + ":" + mbgl::util::toString(line)); - throw Error(message + " at " + file + ":" + mbgl::util::toString(line)); + message << " at " << file << ":" << line; + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, message.str().c_str()); + throw Error(message.str()); } } @@ -85,7 +86,7 @@ void checkLinkStatus(GLuint program) { glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); GLchar infoLog[maxLength]; glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); - mbgl::Log::Info(mbgl::Event::General, &infoLog[0]); + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, &infoLog[0]); throw Error(infoLog); } @@ -101,7 +102,7 @@ void checkCompileStatus(GLuint shader) { // The maxLength includes the NULL character GLchar errorLog[maxLength]; glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); - mbgl::Log::Error(mbgl::Event::General, &errorLog[0]); + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, &errorLog[0]); throw Error(errorLog); } } @@ -114,7 +115,7 @@ static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; voi class ExampleCustomLayer { public: ~ExampleCustomLayer() { - mbgl::Log::Info(mbgl::Event::General, "~ExampleCustomLayer"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "~ExampleCustomLayer"); if (program) { glDeleteBuffers(1, &buffer); glDetachShader(program, vertexShader); @@ -126,12 +127,12 @@ public: } void initialize() { - mbgl::Log::Info(mbgl::Event::General, "Initialize"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Initialize"); // Debug info int maxAttrib; GL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttrib)); - mbgl::Log::Info(mbgl::Event::General, "Max vertex attributes: %i", maxAttrib); + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Max vertex attributes: %i", maxAttrib); program = GL_CHECK_ERROR(glCreateProgram()); vertexShader = GL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)); @@ -158,7 +159,7 @@ public: } void render() { - mbgl::Log::Info(mbgl::Event::General, "Render"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Render"); GL_CHECK_ERROR(glUseProgram(program)); GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); @@ -184,12 +185,12 @@ public: GLfloat ExampleCustomLayer::color[] = { 0.0f, 1.0f, 0.0f, 1.0f }; jlong JNICALL nativeCreateContext(JNIEnv*, jobject) { - mbgl::Log::Info(mbgl::Event::General, "nativeCreateContext"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeCreateContext"); return reinterpret_cast(new ExampleCustomLayer()); } void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat blue, jfloat alpha) { - mbgl::Log::Info(mbgl::Event::General, "nativeSetColor: %.2f, %.2f, %.2f, %.2f", red, green, blue, alpha); + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "nativeSetColor: %.2f, %.2f, %.2f, %.2f", red, green, blue, alpha); ExampleCustomLayer::color[0] = red; ExampleCustomLayer::color[1] = green; ExampleCustomLayer::color[2] = blue; @@ -197,26 +198,28 @@ void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat b } void nativeInitialize(void *context) { - mbgl::Log::Info(mbgl::Event::General, "nativeInitialize"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeInitialize"); reinterpret_cast(context)->initialize(); } void nativeRender(void *context, const mbgl::style::CustomLayerRenderParameters& /*parameters*/) { - mbgl::Log::Info(mbgl::Event::General, "nativeRender"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeRender"); reinterpret_cast(context)->render(); } void nativeContextLost(void */*context*/) { - mbgl::Log::Info(mbgl::Event::General, "nativeContextLost"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeContextLost"); } -void nativeDenitialize(void *context) { - mbgl::Log::Info(mbgl::Event::General, "nativeDeinitialize"); + +void nativeDeinitialize(void *context) { + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeDeinitialize"); delete reinterpret_cast(context); } extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - mbgl::Log::Info(mbgl::Event::General, "OnLoad"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "OnLoad"); + JNIEnv *env = nullptr; vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); -- cgit v1.2.1 From 90cce8d9ce09ccbd828341e924b94caaf8f30899 Mon Sep 17 00:00:00 2001 From: Osana Babayan <32496536+osana@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:25:11 -0500 Subject: [android] incorrect latlngBounds in the VisibleRegion with map is rotated smallest bounding box for 4 points cannot (#11226) be created using LatLngBounds.fromLatLngs() as the order matters in that method and that does not work for rotated map --- .../src/main/java/com/mapbox/mapboxsdk/maps/Projection.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java index 16c73b1ca5..ae559189ad 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java @@ -104,11 +104,12 @@ public class Projection { LatLng bottomLeft = fromScreenLocation(new PointF(left, bottom)); return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, - LatLngBounds.from( - topRight.getLatitude(), - topRight.getLongitude(), - bottomLeft.getLatitude(), - bottomLeft.getLongitude()) + new LatLngBounds.Builder() + .include(topRight) + .include(bottomLeft) + .include(bottomRight) + .include(topLeft) + .build() ); } -- cgit v1.2.1 From a8b8c5defac6e6c08ef161b32f52496148573d01 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 1 Mar 2018 10:06:48 +0100 Subject: [android] - update changelog for v5.5.0 --- platform/android/CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 7827bc129f..d0d29eabf6 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,18 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 5.5.0 - March 1, 2018 + - TileJSON Bounds allows values inclusive of world extents [#11178](https://github.com/mapbox/mapbox-gl-native/pull/11178) + - LatLngBounds returned by VisibleRegion when map is rotated [#11226](https://github.com/mapbox/mapbox-gl-native/pull/11226) + - Custom Layer fixes & black list VAO on mali t720 [#11239](https://github.com/mapbox/mapbox-gl-native/pull/11239) + - Check if Activity isn't finishing before showing dialog [#11244](https://github.com/mapbox/mapbox-gl-native/pull/11244) + - Decouple MapPadding from overlain views [#11258](https://github.com/mapbox/mapbox-gl-native/pull/11258) + - Don't disable zoom button controller zooming with gesture disabled zoom [#11259](https://github.com/mapbox/mapbox-gl-native/pull/11259) + - Expose ImageSource coordinates setter [#11262](https://github.com/mapbox/mapbox-gl-native/pull/11262) + - Add missing DeleteLocalRefs [#11272](https://github.com/mapbox/mapbox-gl-native/pull/11272) + - Continue loading style even if we mutate it [#11294](https://github.com/mapbox/mapbox-gl-native/pull/11294) + - Update telemetry version for OkHttp [#11338](https://github.com/mapbox/mapbox-gl-native/pull/11338) + ## 5.4.1 - February 9, 2018 - Don't recreate TextureView surface as part of view resizing, solves OOM crashes [#11148](https://github.com/mapbox/mapbox-gl-native/pull/11148) - Don't invoke OnLowMemory before map is ready, solves startup crash on low memory devices [#11109](https://github.com/mapbox/mapbox-gl-native/pull/11109) -- cgit v1.2.1 From 6e4846044531128b8984f351d367a7185325565d Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 1 Mar 2018 10:10:25 +0100 Subject: [android] - release android v5.5.0 --- platform/android/MapboxGLAndroidSDK/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties index 8839f21d8f..36252fc90e 100644 --- a/platform/android/MapboxGLAndroidSDK/gradle.properties +++ b/platform/android/MapboxGLAndroidSDK/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.mapbox.mapboxsdk -VERSION_NAME=5.4.2-SNAPSHOT +VERSION_NAME=5.5.0 POM_DESCRIPTION=Mapbox GL Android SDK POM_URL=https://github.com/mapbox/mapbox-gl-native -- cgit v1.2.1 From 72393707d34fd7c4c0fa81b66b40805f29411aed Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 1 Mar 2018 10:44:29 +0100 Subject: [android] - fix custom layer example --- platform/android/src/example_custom_layer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp index 46fcd96ffa..be8e830412 100644 --- a/platform/android/src/example_custom_layer.cpp +++ b/platform/android/src/example_custom_layer.cpp @@ -249,7 +249,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { env->SetStaticLongField(customLayerClass, env->GetStaticFieldID(customLayerClass, "DeinitializeFunction", "J"), - reinterpret_cast(nativeDenitialize)); + reinterpret_cast(nativeDeinitialize)); return JNI_VERSION_1_6; } -- cgit v1.2.1 From 40039f6b430b4730aed8c52c28de3a855b8425ea Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 1 Mar 2018 11:25:18 +0100 Subject: [android] - reset release configuration --- platform/android/MapboxGLAndroidSDK/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties index 36252fc90e..f5dc431d40 100644 --- a/platform/android/MapboxGLAndroidSDK/gradle.properties +++ b/platform/android/MapboxGLAndroidSDK/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.mapbox.mapboxsdk -VERSION_NAME=5.5.0 +VERSION_NAME=5.5.1-SNAPSHOT POM_DESCRIPTION=Mapbox GL Android SDK POM_URL=https://github.com/mapbox/mapbox-gl-native -- cgit v1.2.1 From 9412f058f900f6ca0d1ea833f39eda2983b51259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Fri, 2 Mar 2018 11:04:02 +0100 Subject: [android] updated changelog to reflect 6.0.0-beta.3 changes (cherry picked from commit 7c0c884) --- platform/android/CHANGELOG.md | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index fa9b1d29cc..60d3dc6b70 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,10 +2,29 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## master - - - HeatmapLayer [#11046](https://github.com/mapbox/mapbox-gl-native/pull/11046) - +## 6.0.0-beta.3 - March 2, 2018 + - Added missing local reference deletes [#11243](https://github.com/mapbox/mapbox-gl-native/pull/11243), [#11272](https://github.com/mapbox/mapbox-gl-native/pull/11272) + - Remove obsolete camera api [#11201](https://github.com/mapbox/mapbox-gl-native/pull/11201) + - Fix UTF-8 encoding, add missing package-info.java files [#11261](https://github.com/mapbox/mapbox-gl-native/pull/11261) + - Rework expression api [#11210](https://github.com/mapbox/mapbox-gl-native/pull/11210) + - LatLngBounds fixes [#11333](https://github.com/mapbox/mapbox-gl-native/pull/11333), [#11307](https://github.com/mapbox/mapbox-gl-native/pull/11307), [#11308](https://github.com/mapbox/mapbox-gl-native/pull/11308), [#11309](https://github.com/mapbox/mapbox-gl-native/pull/11309), [#11226](https://github.com/mapbox/mapbox-gl-native/pull/11226) + - New gestures library [#11221](https://github.com/mapbox/mapbox-gl-native/pull/11221) + - Expose ImageSource coordinates setter [#11262](https://github.com/mapbox/mapbox-gl-native/pull/11262) + - Add heatmap color property [#11220](https://github.com/mapbox/mapbox-gl-native/pull/11220) + - Add support for mapzen terrarium raster-dem encoding [#11339](https://github.com/mapbox/mapbox-gl-native/pull/11339) + +## 5.5.0 - March 1, 2018 + - TileJSON Bounds allows values inclusive of world extents [#11178](https://github.com/mapbox/mapbox-gl-native/pull/11178) + - LatLngBounds returned by VisibleRegion when map is rotated [#11226](https://github.com/mapbox/mapbox-gl-native/pull/11226) + - Custom Layer fixes & black list VAO on mali t720 [#11239](https://github.com/mapbox/mapbox-gl-native/pull/11239) + - Check if Activity isn't finishing before showing dialog [#11244](https://github.com/mapbox/mapbox-gl-native/pull/11244) + - Decouple MapPadding from overlain views [#11258](https://github.com/mapbox/mapbox-gl-native/pull/11258) + - Don't disable zoom button controller zooming with gesture disabled zoom [#11259](https://github.com/mapbox/mapbox-gl-native/pull/11259) + - Expose ImageSource coordinates setter [#11262](https://github.com/mapbox/mapbox-gl-native/pull/11262) + - Add missing DeleteLocalRefs [#11272](https://github.com/mapbox/mapbox-gl-native/pull/11272) + - Continue loading style even if we mutate it [#11294](https://github.com/mapbox/mapbox-gl-native/pull/11294) + - Update telemetry version for OkHttp [#11338](https://github.com/mapbox/mapbox-gl-native/pull/11338) + ## 6.0.0-beta.2 - February 13, 2018 - Deprecate LocationEngine [#11185](https://github.com/mapbox/mapbox-gl-native/pull/11185) - Remove LOST from SDK [11186](https://github.com/mapbox/mapbox-gl-native/pull/11186) -- cgit v1.2.1 From ae0e583590ce8d7a564c8d9cb7c0fcee5515125e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 5 Mar 2018 14:22:06 +0100 Subject: [android] fix CameraAnimatorActivity home button (#11383) --- .../testapp/activity/camera/CameraAnimatorActivity.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java index f25fd6ab27..176d713a4b 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java @@ -164,9 +164,12 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe if (mapboxMap == null) { return false; } - findViewById(R.id.fab).setVisibility(View.GONE); - resetCameraPosition(); - playAnimation(item.getItemId()); + + if (item.getItemId() != android.R.id.home) { + findViewById(R.id.fab).setVisibility(View.GONE); + resetCameraPosition(); + playAnimation(item.getItemId()); + } return super.onOptionsItemSelected(item); } -- cgit v1.2.1 From d7808b3a77bce6d2c8221ea624ef5b78616b760c Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Tue, 6 Mar 2018 06:09:47 -0800 Subject: Android readme snapshot dependency line cleanup (#11071) * Snapshot dependency line cleanup * Matching version nums * changed compile to implementation --- platform/android/README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'platform/android') diff --git a/platform/android/README.md b/platform/android/README.md index 1dbdeee343..4e9d55f8c8 100644 --- a/platform/android/README.md +++ b/platform/android/README.md @@ -89,15 +89,14 @@ More information about building and distributing this project in [DISTRIBUTE.md] #### Using the SDK snapshot -Instead of using the latest stable release of the Maps SDK for Android, you can use a "snapshot" or the beta version if there is one available. Our snapshots are built every time a Github pull request adds code to this repository's `master` branch. If you'd like to use a snapshot build, your Android project's gradle file should have -SNAPSHOT appended to the SDK version number. For example `5.2.0-SNAPSHOT` or: +Instead of using the latest stable release of the Maps SDK for Android, you can use a "snapshot" or the beta version if there is one available. Our snapshots are built every time a Github pull request adds code to this repository's `master` branch. If you'd like to use a snapshot build, your Android project's gradle file should have -SNAPSHOT appended to the SDK version number. For example, the `5.2.0-SNAPSHOT` would look like: ```java // Mapbox SDK dependency -compile('com.mapbox.mapboxsdk:mapbox-android-sdk:5.2.0-SNAPSHOT@aar') { - transitive = true -} +implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:5.2.0-SNAPSHOT' ``` -You need to have the section below in your build.gradle root folder to be able to resolve the SNAPSHOT dependencies: + +You also need to have the section below in your build.gradle root folder to be able to resolve the SNAPSHOT dependencies: ``` allprojects { repositories { -- cgit v1.2.1 From 268a4d7404d30dc4f866711e3fd1e778892bbe35 Mon Sep 17 00:00:00 2001 From: Cameron Mace Date: Wed, 7 Mar 2018 10:45:39 -0500 Subject: Update README.md (#11408) Update splash image --- platform/android/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/README.md b/platform/android/README.md index 4e9d55f8c8..31e0a94f2c 100644 --- a/platform/android/README.md +++ b/platform/android/README.md @@ -12,7 +12,7 @@ Alright. So, actually, you may be in the wrong place. From here on in, this READ **To install and use the Mapbox Maps SDK for Android in an application, see the [Mapbox Maps SDK for Android website](https://www.mapbox.com/install/android/).** -[![](https://www.mapbox.com/android-sdk/images/splash.png)](https://www.mapbox.com/android-sdk/) +[![](https://www.mapbox.com/android-docs/assets/overview-map-sdk-322-9abe118316efb5910b6101e222a2e57c.png)](https://www.mapbox.com/android-sdk/) ### Setup environment -- cgit v1.2.1 From 553efa38e3591ce62863d4d74222710f8e3c2337 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 20 Mar 2018 17:18:42 +0100 Subject: [android] - update changelog for v6.0.0-beta.4 (#11486) --- platform/android/CHANGELOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 60d3dc6b70..bae36142f5 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,28 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 6.0.0-beta.4 - March 20, 2018 + - Gesture library 0.1.0 stable [#11483](https://github.com/mapbox/mapbox-gl-native/pull/11483) + - Filters with expressions [#11429](https://github.com/mapbox/mapbox-gl-native/pull/11429) + - Telemetry 3.0.0-beta.2 [#11474](https://github.com/mapbox/mapbox-gl-native/pull/11474) + - High level JNI conversion for geojson [#11471](https://github.com/mapbox/mapbox-gl-native/pull/11471) + - Update to MAS 3.0.0-beta.4 [#11468](https://github.com/mapbox/mapbox-gl-native/pull/11468) + - Support for expression literal on arrays [#11457](https://github.com/mapbox/mapbox-gl-native/pull/11457) + - Fix telemetry integration for two finger tap gesture [#11460](https://github.com/mapbox/mapbox-gl-native/pull/11460) + - Revisit proguard configuration [#11434](https://github.com/mapbox/mapbox-gl-native/pull/11434) + - Expressions accessor support [#11352](https://github.com/mapbox/mapbox-gl-native/pull/11352) + - Calculate camera's LatLng for bounds without map padding [#11410](https://github.com/mapbox/mapbox-gl-native/pull/11410) + - Check for null on http body request [#11413](https://github.com/mapbox/mapbox-gl-native/pull/11413) + - Expose more gesture settings [#11407](https://github.com/mapbox/mapbox-gl-native/pull/11407) + - Revert java 8 language support [#11398](https://github.com/mapbox/mapbox-gl-native/pull/11398) + - Update to MAS 3.0.0-beta.3 [#11373](https://github.com/mapbox/mapbox-gl-native/pull/11373) + - Rework match expression to style specification syntax [#11388](https://github.com/mapbox/mapbox-gl-native/pull/11388) + - Update javadoc configuration for Gradle 4.4 [#11384](https://github.com/mapbox/mapbox-gl-native/pull/11384) + - Rework zoomIn and zoomOut to use ValueAnimators [#11382](https://github.com/mapbox/mapbox-gl-native/pull/11382) + - Delete LocalRef when converting Image.java [#11350](https://github.com/mapbox/mapbox-gl-native/pull/11350) + - Use float for pixelratio when creating a snapshotter [#11367](https://github.com/mapbox/mapbox-gl-native/pull/11367) + - Validate width/height when creating a snapshot [#11364](https://github.com/mapbox/mapbox-gl-native/pull/11364) + ## 6.0.0-beta.3 - March 2, 2018 - Added missing local reference deletes [#11243](https://github.com/mapbox/mapbox-gl-native/pull/11243), [#11272](https://github.com/mapbox/mapbox-gl-native/pull/11272) - Remove obsolete camera api [#11201](https://github.com/mapbox/mapbox-gl-native/pull/11201) -- cgit v1.2.1 From 006d2ab1d5f65242d9e53e9d804c01ac2d450537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 5 Apr 2018 14:03:44 +0200 Subject: CP missing changelog entries to master (#11596) * [android] - update changelog v5.5.1 (cherry picked from commit b411eed) * [android] Updated changelog for 6.0.0-beta.5 release (cherry picked from commit 73c0159) * Release android v6.0.0 beta.6 (#11592) * [android] updated changelog for 6.0.0-beta.6 (cherry picked from commit d5a3e5b) --- platform/android/CHANGELOG.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index bae36142f5..534f628c37 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,33 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 6.0.0-beta.6 - April 4, 2018 + - Fix race condition crash for heavily modified annotations [#11551](https://github.com/mapbox/mapbox-gl-native/pull/11551) + - Throw exception when converting PropertyValue with an expression [#11572](https://github.com/mapbox/mapbox-gl-native/pull/11572) + - Invalidate camera position before delivering onMapReady [#11585](https://github.com/mapbox/mapbox-gl-native/pull/11585) + - Rework logical condition convenience expressions [#11555](https://github.com/mapbox/mapbox-gl-native/pull/11555) + - Telemetry library version update to 3.0.0-beta.4 [#11590](https://github.com/mapbox/mapbox-gl-native/pull/11590) + +## 6.0.0-beta.5 - March 27, 2018 + - Avoid flashing on pitched overzoomed tiles [#11488](https://github.com/mapbox/mapbox-gl-native/pull/11488) + - Literal array conversion of primitive arrays [#11500](https://github.com/mapbox/mapbox-gl-native/pull/11500) + - Make default output from step more descriptive [#11501](https://github.com/mapbox/mapbox-gl-native/pull/11501) + - Expose public Telemetry API [#11503](https://github.com/mapbox/mapbox-gl-native/pull/11503) + - Convert Android int colors with to-color expression [#11506](https://github.com/mapbox/mapbox-gl-native/pull/11506) + - Prevent default style reload when string style json was set [#11520](https://github.com/mapbox/mapbox-gl-native/pull/11520) + - String, number and bool Expressions with multiple values [#11512](https://github.com/mapbox/mapbox-gl-native/pull/11512) + - Telemetry library 3.0.0-beta.3 [#11534](https://github.com/mapbox/mapbox-gl-native/pull/11534) + - Gestures library v0.2.0 [#11535](https://github.com/mapbox/mapbox-gl-native/pull/11535) + +## 5.5.1 - March 26, 2018 + - Verify optional access of FileSource deactivation [#11480](https://github.com/mapbox/mapbox-gl-native/pull/11480) + - Prevent default style loading when style json was set [#11519](https://github.com/mapbox/mapbox-gl-native/pull/11519) + - Delete local reference when convering Image.java [#11350](https://github.com/mapbox/mapbox-gl-native/pull/11350) + - Use float for pixel ratio when creating a snapshotter [#11367](https://github.com/mapbox/mapbox-gl-native/pull/11367) + - Validate if width and height aren't 0 when creating a snapshot [#11364](https://github.com/mapbox/mapbox-gl-native/pull/11364) + - Null check body of http request [#11413](https://github.com/mapbox/mapbox-gl-native/pull/11413) + - Clamp TileJSON bounds [#11425](https://github.com/mapbox/mapbox-gl-native/pull/11425) + ## 6.0.0-beta.4 - March 20, 2018 - Gesture library 0.1.0 stable [#11483](https://github.com/mapbox/mapbox-gl-native/pull/11483) - Filters with expressions [#11429](https://github.com/mapbox/mapbox-gl-native/pull/11429) -- cgit v1.2.1 From 61bb9be1e3c3e290d88453ae91d7e26c9dab4009 Mon Sep 17 00:00:00 2001 From: Antonio Zugaldia Date: Tue, 10 Apr 2018 10:58:58 -0400 Subject: [android] Adds gradle-dependency-graph-generator-plugin to Android project (#11603) * adds gradle-dependency-graph-generator-plugin to the project * keep script in sync with https://github.com/mapbox/mapbox-android-demo/pull/671 * adds a makefile rule for dependency generation --- platform/android/MapboxGLAndroidSDK/.gitignore | 1 + platform/android/MapboxGLAndroidSDK/build.gradle | 1 + .../gradle/gradle-dependencies-graph.gradle | 29 ++++++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 platform/android/MapboxGLAndroidSDK/.gitignore create mode 100644 platform/android/gradle/gradle-dependencies-graph.gradle (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/.gitignore b/platform/android/MapboxGLAndroidSDK/.gitignore new file mode 100644 index 0000000000..c24bd2563a --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/.gitignore @@ -0,0 +1 @@ +dependency-graph-mapbox-libraries.png diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 9063321648..2bf452e964 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -150,3 +150,4 @@ apply from: "${rootDir}/gradle/gradle-javadoc.gradle" apply from: "${rootDir}/gradle/gradle-publish.gradle" apply from: "${rootDir}/gradle/gradle-checkstyle.gradle" apply from: "${rootDir}/gradle/gradle-tests-staticblockremover.gradle" +apply from: "${rootDir}/gradle/gradle-dependencies-graph.gradle" diff --git a/platform/android/gradle/gradle-dependencies-graph.gradle b/platform/android/gradle/gradle-dependencies-graph.gradle new file mode 100644 index 0000000000..5cbc7b974f --- /dev/null +++ b/platform/android/gradle/gradle-dependencies-graph.gradle @@ -0,0 +1,29 @@ +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath "com.vanniktech:gradle-dependency-graph-generator-plugin:0.3.0" + } +} + +import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorPlugin +import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension.Generator +import com.vanniktech.dependency.graph.generator.dot.GraphFormattingOptions +import com.vanniktech.dependency.graph.generator.dot.Color +import com.vanniktech.dependency.graph.generator.dot.Shape +import com.vanniktech.dependency.graph.generator.dot.Style + +plugins.apply(DependencyGraphGeneratorPlugin) + +def mapboxGenerator = new Generator( + "mapboxLibraries", // Suffix for our Gradle task. + "", // Root suffix that we don't want in this case. + { dependency -> dependency.getModuleGroup().startsWith("com.mapbox.mapboxsdk") }, // Only want Mapbox libs. + { dependency -> true }, // Include transitive dependencies. +) + +dependencyGraphGenerator { + generators = [mapboxGenerator] +} -- cgit v1.2.1 From 21af83789d90e0acaa413145b370e31f22012bbe Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 10 Apr 2018 16:43:11 +0200 Subject: [android] - update changelog for v5.5.2 --- platform/android/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 534f628c37..db9f91d034 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,14 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 5.5.2 - April 10, 2018 + - Correct animation scale point [#11643](https://github.com/mapbox/mapbox-gl-native/pull/11643) + - Re-bind uniform locations after re-linking program [#11583](https://github.com/mapbox/mapbox-gl-native/pull/11583) + - Invalidate camera position before delivering onMapReady [#11585](https://github.com/mapbox/mapbox-gl-native/pull/11585) + - Null java peer callback [#11358](https://github.com/mapbox/mapbox-gl-native/pull/11358) + - Add missing delete local reference [#11608](https://github.com/mapbox/mapbox-gl-native/pull/11608) + - Release local refs [#11599](https://github.com/mapbox/mapbox-gl-native/pull/11599) + ## 6.0.0-beta.6 - April 4, 2018 - Fix race condition crash for heavily modified annotations [#11551](https://github.com/mapbox/mapbox-gl-native/pull/11551) - Throw exception when converting PropertyValue with an expression [#11572](https://github.com/mapbox/mapbox-gl-native/pull/11572) -- cgit v1.2.1 From 7c1d79fb95882003a7424a181bcdfb95bbfe23a9 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 17 Apr 2018 09:35:37 +0200 Subject: [android] - changelog entry for v6.0.0 --- platform/android/CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index db9f91d034..dfec87ea1f 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,25 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 6.0.0 - April 17, 2018 + - Bump telemetry version to 3.0.1 [#11700](https://github.com/mapbox/mapbox-gl-native/pull/11700) + - Update layer when changing its min/max zoom [#11687](https://github.com/mapbox/mapbox-gl-native/pull/11687) + +## 6.0.0-beta.7 - April 12, 2018 + - Add abs, round, floor, ceil expression operators [#11653](https://github.com/mapbox/mapbox-gl-native/pull/11653) + - LatLngBounds correct center calculation [#11650](https://github.com/mapbox/mapbox-gl-native/pull/11650) + - Bump telemetry to 3.0.0 final [#11658](https://github.com/mapbox/mapbox-gl-native/pull/11658) + - Correctly calculate LatLngBounds [#11647](https://github.com/mapbox/mapbox-gl-native/pull/11647) + - Add convenience step expression [#11641](https://github.com/mapbox/mapbox-gl-native/pull/11641) + - Add javadoc examples for Android [#11540](https://github.com/mapbox/mapbox-gl-native/pull/11540) + - Add paused state to map renderer, don't render snapshots after onPause [#11358](https://github.com/mapbox/mapbox-gl-native/pull/11358) + - Rework internal expression conversion [#11490](https://github.com/mapbox/mapbox-gl-native/pull/11490) + - Fixed gesture event listeners javadoc [#11630](https://github.com/mapbox/mapbox-gl-native/pull/11630) + - Add delete local reference on jni strings [#11608](https://github.com/mapbox/mapbox-gl-native/pull/11608) + - Release local references early [#11599](https://github.com/mapbox/mapbox-gl-native/pull/11599) + - Re-bind uniform locations after re-linking program [#11618](https://github.com/mapbox/mapbox-gl-native/pull/11618) + - Bump mapbox-sdk-services to 3.0.1 [#11593](https://github.com/mapbox/mapbox-gl-native/pull/11593) + ## 5.5.2 - April 10, 2018 - Correct animation scale point [#11643](https://github.com/mapbox/mapbox-gl-native/pull/11643) - Re-bind uniform locations after re-linking program [#11583](https://github.com/mapbox/mapbox-gl-native/pull/11583) -- cgit v1.2.1 From 2bb785dad2489d04db179fa9cf65514640db0a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 18 Apr 2018 10:29:08 +0200 Subject: [android] - updated changelog for 6.0.1 (#11715) (cherry picked from commit 0256f15) --- platform/android/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index dfec87ea1f..246b5828c4 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 6.0.1 - April 17, 2018 + - Bump telemetry version to 3.0.2 [#11710](https://github.com/mapbox/mapbox-gl-native/pull/11710) + ## 6.0.0 - April 17, 2018 - Bump telemetry version to 3.0.1 [#11700](https://github.com/mapbox/mapbox-gl-native/pull/11700) - Update layer when changing its min/max zoom [#11687](https://github.com/mapbox/mapbox-gl-native/pull/11687) -- cgit v1.2.1 From c5625f988a37b6876c4ef5fc8d9de295ee28ed44 Mon Sep 17 00:00:00 2001 From: Fabian Guerra Date: Mon, 23 Apr 2018 17:59:17 -0400 Subject: [ios, android] Resolve merge conflicts. --- platform/android/MapboxGLAndroidSDK/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties index bdfc444454..84aeabef1a 100644 --- a/platform/android/MapboxGLAndroidSDK/gradle.properties +++ b/platform/android/MapboxGLAndroidSDK/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.mapbox.mapboxsdk -VERSION_NAME=6.1.0-SNAPSHOT +VERSION_NAME=7.0.0-SNAPSHOT POM_DESCRIPTION=Mapbox GL Android SDK POM_URL=https://github.com/mapbox/mapbox-gl-native -- cgit v1.2.1 From eb39c80604935deb666907f90ddc31f50865f828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 24 Apr 2018 11:31:29 +0200 Subject: [android] - unwrap LatLngBounds for the shortest path when passing to core (#11759) --- .../mapbox/mapboxsdk/geometry/LatLngBounds.java | 45 ++++++++++++++++++---- .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 13 +++++-- .../mapboxsdk/geometry/LatLngBoundsTest.java | 22 ++++++++++- 3 files changed, 66 insertions(+), 14 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index 05187cf333..eec0d566bb 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -28,7 +28,7 @@ public class LatLngBounds implements Parcelable { /** * Construct a new LatLngBounds based on its corners, given in NESW * order. - * + *

* If eastern longitude is smaller than the western one, bounds will include antimeridian. * For example, if the NE point is (10, -170) and the SW point is (-10, 170), then bounds will span over 20 degrees * and cross the antimeridian. @@ -46,6 +46,11 @@ public class LatLngBounds implements Parcelable { this.longitudeWest = westLongitude; } + LatLngBounds(LatLngBounds latLngBounds) { + this(latLngBounds.latitudeNorth, latLngBounds.longitudeEast, + latLngBounds.latitudeSouth, latLngBounds.longitudeWest); + } + /** * Returns the world bounds. * @@ -75,7 +80,6 @@ public class LatLngBounds implements Parcelable { if (longCenter >= GeometryConstants.MAX_LONGITUDE) { longCenter = this.longitudeEast - halfSpan; } - return new LatLng(latCenter, longCenter); } return new LatLng(latCenter, longCenter); @@ -188,7 +192,6 @@ public class LatLngBounds implements Parcelable { return GeometryConstants.LONGITUDE_SPAN - longSpan; } - static double getLongitudeSpan(final double longEast, final double longWest) { double longSpan = Math.abs(longEast - longWest); if (longEast >= longWest) { @@ -199,6 +202,25 @@ public class LatLngBounds implements Parcelable { return GeometryConstants.LONGITUDE_SPAN - longSpan; } + /** + * If bounds cross the antimeridian, unwrap west longitude for the shortest path. + * + * @return unwrapped bounds + */ + public LatLngBounds unwrapBounds() { + double unwrapedLonWest = longitudeWest; + if (longitudeEast < longitudeWest) { + if (longitudeWest > 0 && longitudeEast < 0) { + unwrapedLonWest -= GeometryConstants.LONGITUDE_SPAN; + } else if (longitudeWest < 0 && longitudeEast > 0) { + unwrapedLonWest += GeometryConstants.LONGITUDE_SPAN; + } + return unwrapped(latitudeNorth, longitudeEast, latitudeSouth, unwrapedLonWest); + } else { + return new LatLngBounds(this); + } + } + /** * Validate if LatLngBounds is empty, determined if absolute distance is * @@ -279,12 +301,11 @@ public class LatLngBounds implements Parcelable { /** * Constructs a LatLngBounds from doubles representing a LatLng pair. - * + *

* This values of latNorth and latSouth should be in the range of [-90, 90], * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, * otherwise IllegalArgumentException will be thrown. * latNorth should be greater or equal latSouth, otherwise IllegalArgumentException will be thrown. - * *

* This method doesn't recalculate most east or most west boundaries. * Note that lonEast and lonWest will be wrapped to be in the range of [-180, 180], @@ -318,12 +339,20 @@ public class LatLngBounds implements Parcelable { throw new IllegalArgumentException("LatSouth cannot be less than latNorth"); } + return wrapped(latNorth, lonEast, latSouth, lonWest); + } + + static LatLngBounds wrapped(double latNorth, double lonEast, double latSouth, double lonWest) { lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); return new LatLngBounds(latNorth, lonEast, latSouth, lonWest); } + static LatLngBounds unwrapped(double latNorth, double lonEast, double latSouth, double lonWest) { + return new LatLngBounds(latNorth, lonEast, latSouth, lonWest); + } + private static double lat_(int z, int y) { double n = Math.PI - 2.0 * Math.PI * y / Math.pow(2.0, z); return Math.toDegrees(Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))); @@ -335,14 +364,14 @@ public class LatLngBounds implements Parcelable { /** * Constructs a LatLngBounds from a Tile identifier. - * + *

* Returned bounds will have latitude in the range of Mercator projection. - * @see GeometryConstants#MIN_MERCATOR_LATITUDE - * @see GeometryConstants#MAX_MERCATOR_LATITUDE * * @param z Tile zoom level. * @param x Tile X coordinate. * @param y Tile Y coordinate. + * @see GeometryConstants#MIN_MERCATOR_LATITUDE + * @see GeometryConstants#MAX_MERCATOR_LATITUDE */ public static LatLngBounds from(int z, int x, int y) { return new LatLngBounds(lat_(z, y), lon_(z, x + 1), lat_(z, y + 1), lon_(z, x)); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 5e36dd0f78..745485e2d2 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -1540,7 +1540,12 @@ public final class MapboxMap { * @param latLngBounds the bounds to constrain the map with */ public void setLatLngBoundsForCameraTarget(@Nullable LatLngBounds latLngBounds) { - nativeMapView.setLatLngBounds(latLngBounds); + if (latLngBounds == null) { + nativeMapView.setLatLngBounds(latLngBounds); + } else { + //unwrapping the bounds to generate the right convex hull in core + nativeMapView.setLatLngBounds(latLngBounds.unwrapBounds()); + } } /** @@ -1550,9 +1555,9 @@ public final class MapboxMap { * @param padding the padding to apply to the bounds * @return the camera position that fits the bounds and padding */ - public CameraPosition getCameraForLatLngBounds(@Nullable LatLngBounds latLngBounds, int[] padding) { - // get padded camera position from LatLngBounds - return nativeMapView.getCameraForLatLngBounds(latLngBounds, padding); + public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, int[] padding) { + // get padded camera position from LatLngBounds, unwrapping the bounds to generate the right convex hull in core + return nativeMapView.getCameraForLatLngBounds(latLngBounds.unwrapBounds(), padding); } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java index e072f07fb9..c1e497af32 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java @@ -524,7 +524,6 @@ public class LatLngBoundsTest { LatLngBounds.from(0, Double.POSITIVE_INFINITY, -20, -20); } - @Test public void testConstructorChecksSouthLatitudeNaN() { exception.expect(IllegalArgumentException.class); @@ -543,7 +542,7 @@ public class LatLngBoundsTest { public void testConstructorChecksSouthLatitudeGreaterThan90() { exception.expect(IllegalArgumentException.class); exception.expectMessage("latitude must be between -90 and 90"); - LatLngBounds.from(20, 20,95, 0); + LatLngBounds.from(20, 20, 95, 0); } @Test @@ -566,4 +565,23 @@ public class LatLngBoundsTest { exception.expectMessage("LatSouth cannot be less than latNorth"); LatLngBounds.from(0, 20, 20, 0); } + + @Test + public void testCopyConstructor() { + LatLngBounds bounds = LatLngBounds.from(50, 10, -20, -30); + LatLngBounds copyBounds = new LatLngBounds(bounds); + assertEquals(bounds, copyBounds); + } + + @Test + public void testUnwrapBounds() { + LatLngBounds bounds = LatLngBounds.from(16.5, -172.8, -35.127709, 172.6); + LatLngBounds unwrappedBounds = bounds.unwrapBounds(); + assertEquals(bounds.getCenter().wrap(), unwrappedBounds.getCenter().wrap()); + assertEquals(bounds.getSpan(), unwrappedBounds.getSpan()); + assertTrue(unwrappedBounds.getLonEast() < 0 && unwrappedBounds.getLonWest() < 0); + + LatLngBounds bounds2 = LatLngBounds.from(16.5, -162.8, -35.127709, -177.4); + assertEquals(bounds2, bounds2.unwrapBounds()); + } } -- cgit v1.2.1 From 60cce56d46cb52c73fcb14d3917c1c47c328b72e Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Thu, 19 Apr 2018 13:06:42 -0700 Subject: Bump GL JS pin to get tests for global symbol querying. - Pulls over an update to line.vertex.glsl (looks like a no-op?) - Add test ignores for collator, is-supported-script, line-gradient - Exclude collator, is-supported-script, line-gradient from code generation. --- .../mapboxsdk/style/layers/PropertyFactory.java | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java index 4289deeda3..1dd8eddab9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java @@ -166,7 +166,7 @@ public class PropertyFactory { } /** - * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). + * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels. * * @param value a String value * @return property wrapper around String @@ -176,7 +176,7 @@ public class PropertyFactory { } /** - * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). + * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels. * * @param expression an expression statement * @return property wrapper around an expression statement @@ -356,7 +356,7 @@ public class PropertyFactory { } /** - * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width. + * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width. Note that GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to the expected scale. Also note that zoom-dependent expressions will be evaluated only at integer zoom levels. * * @param value a Float[] value * @return property wrapper around Float[] @@ -366,7 +366,7 @@ public class PropertyFactory { } /** - * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width. + * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width. Note that GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to the expected scale. Also note that zoom-dependent expressions will be evaluated only at integer zoom levels. * * @param expression an expression statement * @return property wrapper around an expression statement @@ -376,7 +376,7 @@ public class PropertyFactory { } /** - * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512). + * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels. * * @param value a String value * @return property wrapper around String @@ -386,7 +386,7 @@ public class PropertyFactory { } /** - * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512). + * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels. * * @param expression an expression statement * @return property wrapper around an expression statement @@ -1156,7 +1156,7 @@ public class PropertyFactory { } /** - * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). + * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels. * * @param value a String value * @return property wrapper around String @@ -1166,7 +1166,7 @@ public class PropertyFactory { } /** - * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). + * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels. * * @param expression an expression statement * @return property wrapper around an expression statement @@ -1536,7 +1536,7 @@ public class PropertyFactory { } /** - * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). + * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels. * * @param value a String value * @return property wrapper around String @@ -1546,7 +1546,7 @@ public class PropertyFactory { } /** - * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). + * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels. * * @param expression an expression statement * @return property wrapper around an expression statement -- cgit v1.2.1 From cf4b4e728c26e444514f6ba792c207692350eb57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 30 Apr 2018 18:32:37 +0200 Subject: [android] - checking is renderer is not destroyed before delivering the snapshot --- .../mapboxsdk/maps/renderer/MapRenderer.java | 8 ++------ platform/android/src/map_renderer.cpp | 23 +++++++--------------- platform/android/src/map_renderer.hpp | 6 +----- 3 files changed, 10 insertions(+), 27 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java index f1c70325a0..fcee5bd179 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java @@ -37,11 +37,11 @@ public abstract class MapRenderer implements MapRendererScheduler { } public void onPause() { - nativeOnPause(); + // Implement if needed } public void onResume() { - nativeOnResume(); + // Implement if needed } public void onStop() { @@ -124,10 +124,6 @@ public abstract class MapRenderer implements MapRendererScheduler { private native void nativeRender(); - private native void nativeOnResume(); - - private native void nativeOnPause(); - private long frames; private long timeElapsed; diff --git a/platform/android/src/map_renderer.cpp b/platform/android/src/map_renderer.cpp index f7e16b7091..ba6fdc63b0 100644 --- a/platform/android/src/map_renderer.cpp +++ b/platform/android/src/map_renderer.cpp @@ -29,6 +29,7 @@ MapRenderer::MapRenderer(jni::JNIEnv& _env, jni::Object obj, MapRenderer::~MapRenderer() = default; void MapRenderer::reset() { + destroyed = true; // Make sure to destroy the renderer on the GL Thread auto self = ActorRef(*this, mailbox); self.ask(&MapRenderer::resetRenderer).wait(); @@ -88,8 +89,10 @@ void MapRenderer::requestSnapshot(SnapshotCallback callback) { self.invoke( &MapRenderer::scheduleSnapshot, std::make_unique([&, callback=std::move(callback), runloop=util::RunLoop::Get()](PremultipliedImage image) { - runloop->invoke([callback=std::move(callback), image=std::move(image)]() mutable { - callback(std::move(image)); + runloop->invoke([callback=std::move(callback), image=std::move(image), renderer=std::move(this)]() mutable { + if (renderer && !renderer->destroyed) { + callback(std::move(image)); + } }); snapshotCallback.reset(); }) @@ -136,7 +139,7 @@ void MapRenderer::render(JNIEnv&) { renderer->render(*params); // Deliver the snapshot if requested - if (snapshotCallback && !paused) { + if (snapshotCallback) { snapshotCallback->operator()(backend->readFramebuffer()); snapshotCallback.reset(); } @@ -174,14 +177,6 @@ void MapRenderer::onSurfaceChanged(JNIEnv&, jint width, jint height) { requestRender(); } -void MapRenderer::onResume(JNIEnv&) { - paused = false; -} - -void MapRenderer::onPause(JNIEnv&) { - paused = true; -} - // Static methods // jni::Class MapRenderer::javaClass; @@ -200,11 +195,7 @@ void MapRenderer::registerNative(jni::JNIEnv& env) { METHOD(&MapRenderer::onSurfaceCreated, "nativeOnSurfaceCreated"), METHOD(&MapRenderer::onSurfaceChanged, - "nativeOnSurfaceChanged"), - METHOD(&MapRenderer::onResume, - "nativeOnResume"), - METHOD(&MapRenderer::onPause, - "nativeOnPause")); + "nativeOnSurfaceChanged")); } MapRenderer& MapRenderer::getNativePeer(JNIEnv& env, jni::Object jObject) { diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp index 5fb5ef1a61..97d2db4a91 100644 --- a/platform/android/src/map_renderer.hpp +++ b/platform/android/src/map_renderer.hpp @@ -98,10 +98,6 @@ private: void onSurfaceChanged(JNIEnv&, jint width, jint height); - void onResume(JNIEnv&); - - void onPause(JNIEnv&); - private: GenericUniqueWeakObject javaPeer; @@ -124,7 +120,7 @@ private: std::mutex updateMutex; bool framebufferSizeChanged = false; - std::atomic paused {false}; + std::atomic destroyed {false}; std::unique_ptr snapshotCallback; }; -- cgit v1.2.1 From fa700cc10864a6ec9df1f41062b210072f4926d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 1 May 2018 15:15:30 +0200 Subject: Revert "[android] - unwrap LatLngBounds for the shortest path when passing to core (#11759)" This reverts commit eb39c80 --- .../mapbox/mapboxsdk/geometry/LatLngBounds.java | 45 ++++------------------ .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 13 ++----- .../mapboxsdk/geometry/LatLngBoundsTest.java | 22 +---------- 3 files changed, 14 insertions(+), 66 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index eec0d566bb..05187cf333 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -28,7 +28,7 @@ public class LatLngBounds implements Parcelable { /** * Construct a new LatLngBounds based on its corners, given in NESW * order. - *

+ * * If eastern longitude is smaller than the western one, bounds will include antimeridian. * For example, if the NE point is (10, -170) and the SW point is (-10, 170), then bounds will span over 20 degrees * and cross the antimeridian. @@ -46,11 +46,6 @@ public class LatLngBounds implements Parcelable { this.longitudeWest = westLongitude; } - LatLngBounds(LatLngBounds latLngBounds) { - this(latLngBounds.latitudeNorth, latLngBounds.longitudeEast, - latLngBounds.latitudeSouth, latLngBounds.longitudeWest); - } - /** * Returns the world bounds. * @@ -80,6 +75,7 @@ public class LatLngBounds implements Parcelable { if (longCenter >= GeometryConstants.MAX_LONGITUDE) { longCenter = this.longitudeEast - halfSpan; } + return new LatLng(latCenter, longCenter); } return new LatLng(latCenter, longCenter); @@ -192,6 +188,7 @@ public class LatLngBounds implements Parcelable { return GeometryConstants.LONGITUDE_SPAN - longSpan; } + static double getLongitudeSpan(final double longEast, final double longWest) { double longSpan = Math.abs(longEast - longWest); if (longEast >= longWest) { @@ -202,25 +199,6 @@ public class LatLngBounds implements Parcelable { return GeometryConstants.LONGITUDE_SPAN - longSpan; } - /** - * If bounds cross the antimeridian, unwrap west longitude for the shortest path. - * - * @return unwrapped bounds - */ - public LatLngBounds unwrapBounds() { - double unwrapedLonWest = longitudeWest; - if (longitudeEast < longitudeWest) { - if (longitudeWest > 0 && longitudeEast < 0) { - unwrapedLonWest -= GeometryConstants.LONGITUDE_SPAN; - } else if (longitudeWest < 0 && longitudeEast > 0) { - unwrapedLonWest += GeometryConstants.LONGITUDE_SPAN; - } - return unwrapped(latitudeNorth, longitudeEast, latitudeSouth, unwrapedLonWest); - } else { - return new LatLngBounds(this); - } - } - /** * Validate if LatLngBounds is empty, determined if absolute distance is * @@ -301,11 +279,12 @@ public class LatLngBounds implements Parcelable { /** * Constructs a LatLngBounds from doubles representing a LatLng pair. - *

+ * * This values of latNorth and latSouth should be in the range of [-90, 90], * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, * otherwise IllegalArgumentException will be thrown. * latNorth should be greater or equal latSouth, otherwise IllegalArgumentException will be thrown. + * *

* This method doesn't recalculate most east or most west boundaries. * Note that lonEast and lonWest will be wrapped to be in the range of [-180, 180], @@ -339,20 +318,12 @@ public class LatLngBounds implements Parcelable { throw new IllegalArgumentException("LatSouth cannot be less than latNorth"); } - return wrapped(latNorth, lonEast, latSouth, lonWest); - } - - static LatLngBounds wrapped(double latNorth, double lonEast, double latSouth, double lonWest) { lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); return new LatLngBounds(latNorth, lonEast, latSouth, lonWest); } - static LatLngBounds unwrapped(double latNorth, double lonEast, double latSouth, double lonWest) { - return new LatLngBounds(latNorth, lonEast, latSouth, lonWest); - } - private static double lat_(int z, int y) { double n = Math.PI - 2.0 * Math.PI * y / Math.pow(2.0, z); return Math.toDegrees(Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))); @@ -364,14 +335,14 @@ public class LatLngBounds implements Parcelable { /** * Constructs a LatLngBounds from a Tile identifier. - *

+ * * Returned bounds will have latitude in the range of Mercator projection. + * @see GeometryConstants#MIN_MERCATOR_LATITUDE + * @see GeometryConstants#MAX_MERCATOR_LATITUDE * * @param z Tile zoom level. * @param x Tile X coordinate. * @param y Tile Y coordinate. - * @see GeometryConstants#MIN_MERCATOR_LATITUDE - * @see GeometryConstants#MAX_MERCATOR_LATITUDE */ public static LatLngBounds from(int z, int x, int y) { return new LatLngBounds(lat_(z, y), lon_(z, x + 1), lat_(z, y + 1), lon_(z, x)); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 745485e2d2..5e36dd0f78 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -1540,12 +1540,7 @@ public final class MapboxMap { * @param latLngBounds the bounds to constrain the map with */ public void setLatLngBoundsForCameraTarget(@Nullable LatLngBounds latLngBounds) { - if (latLngBounds == null) { - nativeMapView.setLatLngBounds(latLngBounds); - } else { - //unwrapping the bounds to generate the right convex hull in core - nativeMapView.setLatLngBounds(latLngBounds.unwrapBounds()); - } + nativeMapView.setLatLngBounds(latLngBounds); } /** @@ -1555,9 +1550,9 @@ public final class MapboxMap { * @param padding the padding to apply to the bounds * @return the camera position that fits the bounds and padding */ - public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, int[] padding) { - // get padded camera position from LatLngBounds, unwrapping the bounds to generate the right convex hull in core - return nativeMapView.getCameraForLatLngBounds(latLngBounds.unwrapBounds(), padding); + public CameraPosition getCameraForLatLngBounds(@Nullable LatLngBounds latLngBounds, int[] padding) { + // get padded camera position from LatLngBounds + return nativeMapView.getCameraForLatLngBounds(latLngBounds, padding); } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java index c1e497af32..e072f07fb9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java @@ -524,6 +524,7 @@ public class LatLngBoundsTest { LatLngBounds.from(0, Double.POSITIVE_INFINITY, -20, -20); } + @Test public void testConstructorChecksSouthLatitudeNaN() { exception.expect(IllegalArgumentException.class); @@ -542,7 +543,7 @@ public class LatLngBoundsTest { public void testConstructorChecksSouthLatitudeGreaterThan90() { exception.expect(IllegalArgumentException.class); exception.expectMessage("latitude must be between -90 and 90"); - LatLngBounds.from(20, 20, 95, 0); + LatLngBounds.from(20, 20,95, 0); } @Test @@ -565,23 +566,4 @@ public class LatLngBoundsTest { exception.expectMessage("LatSouth cannot be less than latNorth"); LatLngBounds.from(0, 20, 20, 0); } - - @Test - public void testCopyConstructor() { - LatLngBounds bounds = LatLngBounds.from(50, 10, -20, -30); - LatLngBounds copyBounds = new LatLngBounds(bounds); - assertEquals(bounds, copyBounds); - } - - @Test - public void testUnwrapBounds() { - LatLngBounds bounds = LatLngBounds.from(16.5, -172.8, -35.127709, 172.6); - LatLngBounds unwrappedBounds = bounds.unwrapBounds(); - assertEquals(bounds.getCenter().wrap(), unwrappedBounds.getCenter().wrap()); - assertEquals(bounds.getSpan(), unwrappedBounds.getSpan()); - assertTrue(unwrappedBounds.getLonEast() < 0 && unwrappedBounds.getLonWest() < 0); - - LatLngBounds bounds2 = LatLngBounds.from(16.5, -162.8, -35.127709, -177.4); - assertEquals(bounds2, bounds2.unwrapBounds()); - } } -- cgit v1.2.1 From 8bf1ff1b36b8575823c8f5612fb39070b4ab8e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 1 May 2018 15:33:33 +0200 Subject: [android] - unwrap LatLngBounds before creating core object --- .../com/mapbox/mapboxsdk/geometry/LatLngBounds.java | 13 +++++-------- .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 2 +- .../mapbox/mapboxsdk/geometry/LatLngBoundsTest.java | 3 +-- platform/android/src/geometry/lat_lng_bounds.cpp | 19 +++++++++++-------- 4 files changed, 18 insertions(+), 19 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index 05187cf333..90cb56f605 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -28,7 +28,7 @@ public class LatLngBounds implements Parcelable { /** * Construct a new LatLngBounds based on its corners, given in NESW * order. - * + *

* If eastern longitude is smaller than the western one, bounds will include antimeridian. * For example, if the NE point is (10, -170) and the SW point is (-10, 170), then bounds will span over 20 degrees * and cross the antimeridian. @@ -75,7 +75,6 @@ public class LatLngBounds implements Parcelable { if (longCenter >= GeometryConstants.MAX_LONGITUDE) { longCenter = this.longitudeEast - halfSpan; } - return new LatLng(latCenter, longCenter); } return new LatLng(latCenter, longCenter); @@ -188,7 +187,6 @@ public class LatLngBounds implements Parcelable { return GeometryConstants.LONGITUDE_SPAN - longSpan; } - static double getLongitudeSpan(final double longEast, final double longWest) { double longSpan = Math.abs(longEast - longWest); if (longEast >= longWest) { @@ -279,12 +277,11 @@ public class LatLngBounds implements Parcelable { /** * Constructs a LatLngBounds from doubles representing a LatLng pair. - * + *

* This values of latNorth and latSouth should be in the range of [-90, 90], * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, * otherwise IllegalArgumentException will be thrown. * latNorth should be greater or equal latSouth, otherwise IllegalArgumentException will be thrown. - * *

* This method doesn't recalculate most east or most west boundaries. * Note that lonEast and lonWest will be wrapped to be in the range of [-180, 180], @@ -335,14 +332,14 @@ public class LatLngBounds implements Parcelable { /** * Constructs a LatLngBounds from a Tile identifier. - * + *

* Returned bounds will have latitude in the range of Mercator projection. - * @see GeometryConstants#MIN_MERCATOR_LATITUDE - * @see GeometryConstants#MAX_MERCATOR_LATITUDE * * @param z Tile zoom level. * @param x Tile X coordinate. * @param y Tile Y coordinate. + * @see GeometryConstants#MIN_MERCATOR_LATITUDE + * @see GeometryConstants#MAX_MERCATOR_LATITUDE */ public static LatLngBounds from(int z, int x, int y) { return new LatLngBounds(lat_(z, y), lon_(z, x + 1), lat_(z, y + 1), lon_(z, x)); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 5e36dd0f78..cfa7143671 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -1550,7 +1550,7 @@ public final class MapboxMap { * @param padding the padding to apply to the bounds * @return the camera position that fits the bounds and padding */ - public CameraPosition getCameraForLatLngBounds(@Nullable LatLngBounds latLngBounds, int[] padding) { + public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, int[] padding) { // get padded camera position from LatLngBounds return nativeMapView.getCameraForLatLngBounds(latLngBounds, padding); } diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java index e072f07fb9..c66e4b6fda 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java @@ -524,7 +524,6 @@ public class LatLngBoundsTest { LatLngBounds.from(0, Double.POSITIVE_INFINITY, -20, -20); } - @Test public void testConstructorChecksSouthLatitudeNaN() { exception.expect(IllegalArgumentException.class); @@ -543,7 +542,7 @@ public class LatLngBoundsTest { public void testConstructorChecksSouthLatitudeGreaterThan90() { exception.expect(IllegalArgumentException.class); exception.expectMessage("latitude must be between -90 and 90"); - LatLngBounds.from(20, 20,95, 0); + LatLngBounds.from(20, 20, 95, 0); } @Test diff --git a/platform/android/src/geometry/lat_lng_bounds.cpp b/platform/android/src/geometry/lat_lng_bounds.cpp index ec1a32fed5..827ee52e95 100644 --- a/platform/android/src/geometry/lat_lng_bounds.cpp +++ b/platform/android/src/geometry/lat_lng_bounds.cpp @@ -9,14 +9,17 @@ jni::Object LatLngBounds::New(jni::JNIEnv& env, mbgl::LatLngBounds } mbgl::LatLngBounds LatLngBounds::getLatLngBounds(jni::JNIEnv& env, jni::Object bounds) { - static auto swLat = LatLngBounds::javaClass.GetField(env, "latitudeSouth"); - static auto swLon = LatLngBounds::javaClass.GetField(env, "longitudeWest"); - static auto neLat = LatLngBounds::javaClass.GetField(env, "latitudeNorth"); - static auto neLon = LatLngBounds::javaClass.GetField(env, "longitudeEast"); - return mbgl::LatLngBounds::hull( - { bounds.Get(env, swLat), bounds.Get(env, swLon) }, - { bounds.Get(env, neLat), bounds.Get(env, neLon) } - ); + static auto swLatField = LatLngBounds::javaClass.GetField(env, "latitudeSouth"); + static auto swLonField = LatLngBounds::javaClass.GetField(env, "longitudeWest"); + static auto neLatField = LatLngBounds::javaClass.GetField(env, "latitudeNorth"); + static auto neLonField = LatLngBounds::javaClass.GetField(env, "longitudeEast"); + + mbgl::LatLng sw = { bounds.Get(env, swLatField), bounds.Get(env, swLonField) }; + mbgl::LatLng ne = { bounds.Get(env, neLatField), bounds.Get(env, neLonField) }; + + sw.unwrapForShortestPath(ne); + + return mbgl::LatLngBounds::hull(sw, ne); } void LatLngBounds::registerNative(jni::JNIEnv& env) { -- cgit v1.2.1 From 9522674c42eb5fd41c3c09649bab33f5a043ad54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Fri, 27 Apr 2018 12:24:32 +0200 Subject: [android] - null check source before removing --- .../main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java | 6 +++++- .../mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 976277dcac..0e77910c3d 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -752,9 +752,13 @@ final class NativeMapView { return null; } Source source = getSource(sourceId); - return removeSource(source); + if (source != null) { + return removeSource(source); + } + return null; } + @Nullable public Source removeSource(@NonNull Source source) { if (isDestroyedOn("removeSource")) { return null; diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java index fc526176d4..23a75d1642 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java @@ -280,6 +280,20 @@ public class RuntimeStyleTests extends BaseActivityTest { }); } + @Test + public void testRemoveNonExistingSource() { + invoke(mapboxMap, (uiController, mapboxMap) -> mapboxMap.removeSource("source")); + } + + @Test + public void testRemoveNonExistingLayer() { + invoke(mapboxMap, (uiController, mapboxMap) -> { + mapboxMap.removeLayer("layer"); + mapboxMap.removeLayerAt(mapboxMap.getLayers().size() + 1); + mapboxMap.removeLayerAt(-1); + }); + } + /** * https://github.com/mapbox/mapbox-gl-native/issues/7973 */ -- cgit v1.2.1 From ba9b49cb997ba6cd119242be9209c7a16d53bd40 Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 2 May 2018 13:29:17 +0200 Subject: [android] - fix expression example that changes icon images dynamically --- .../activity/style/ZoomFunctionSymbolLayerActivity.java | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java index df06c9c42d..81fd2c6ff8 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java @@ -5,7 +5,6 @@ import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; - import com.google.gson.JsonObject; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; @@ -16,16 +15,13 @@ import com.mapbox.mapboxsdk.style.layers.Property; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import com.mapbox.mapboxsdk.testapp.R; - +import timber.log.Timber; import java.util.List; -import timber.log.Timber; - import static com.mapbox.mapboxsdk.style.expressions.Expression.get; -import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate; -import static com.mapbox.mapboxsdk.style.expressions.Expression.linear; import static com.mapbox.mapboxsdk.style.expressions.Expression.literal; +import static com.mapbox.mapboxsdk.style.expressions.Expression.step; import static com.mapbox.mapboxsdk.style.expressions.Expression.stop; import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase; import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom; @@ -44,7 +40,6 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity { private static final String BUS_MAKI_ICON_ID = "bus-11"; private static final String CAFE_MAKI_ICON_ID = "cafe-11"; private static final String KEY_PROPERTY_SELECTED = "selected"; - private static final float ZOOM_STOP_MIN_VALUE = 7.0f; private static final float ZOOM_STOP_MAX_VALUE = 12.0f; private MapView mapView; @@ -103,11 +98,9 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity { layer = new SymbolLayer(LAYER_ID, SOURCE_ID); layer.setProperties( iconImage( - interpolate( - linear(), zoom(), - stop(ZOOM_STOP_MIN_VALUE, BUS_MAKI_ICON_ID), - stop(ZOOM_STOP_MAX_VALUE, CAFE_MAKI_ICON_ID) - ) + step(zoom(), literal(BUS_MAKI_ICON_ID), + stop(ZOOM_STOP_MAX_VALUE, CAFE_MAKI_ICON_ID) + ) ), iconSize( switchCase( -- cgit v1.2.1 From a96fe6ad87d386f25a57a2a7a6632382951733f0 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 1 May 2018 13:05:51 -0700 Subject: [core] Don't copy TileLayerIndexes on every frame. Fixes issue #11811 (too much CPU time spent in CrossTileSymbolIndex). --- platform/android/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 246b5828c4..4df5e79ee7 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,8 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. + - Reduce per-frame render CPU time [#11811](https://github.com/mapbox/mapbox-gl-native/issues/11811) + ## 6.0.1 - April 17, 2018 - Bump telemetry version to 3.0.2 [#11710](https://github.com/mapbox/mapbox-gl-native/pull/11710) -- cgit v1.2.1 From ea59ba8209604c91b76abb31e6be15932bcb3430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Fri, 27 Apr 2018 12:07:28 -0700 Subject: [android, ios, macos] Added Korean localization --- platform/android/CHANGELOG.md | 2 ++ .../src/main/res/values-ko/strings.xml | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/values-ko/strings.xml (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 4df5e79ee7..8a98e78a71 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,7 +2,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 6.0.2 - Reduce per-frame render CPU time [#11811](https://github.com/mapbox/mapbox-gl-native/issues/11811) + - Add Korean localization [#11792](https://github.com/mapbox/mapbox-gl-native/pull/11792) ## 6.0.1 - April 17, 2018 - Bump telemetry version to 3.0.2 [#11710](https://github.com/mapbox/mapbox-gl-native/pull/11710) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-ko/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ko/strings.xml new file mode 100644 index 0000000000..a292e52517 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ko/strings.xml @@ -0,0 +1,16 @@ + + + 지도 나침반. 지도회전를 북쪽으로 재설정합니다. + 속성 정보. 속성 대화를 표시합니다. + 로케이션 뷰. 지도에서 현재 위치를 보여줍니다. + 맵박스로 생성된 지도 표시. 두 손가락으로 드래그하여 화면을 위 아래로 움직이세요. 두 손가락을 이용해 화면을 확대 축소 하세요. + 안드로이드를 위한 맵박스 맵 SDK + 더 나은 맵박스 지도 만들기 + 당신은 익명의 사용 데이터를 제공함으로써, 오픈스트리트맵과 맵박스 향상에 기여하고 있습니다. + 동의 + 비동의 + 추가정보 + 웹 브라우저가 설치 되어 있지 않아, 웹 페이지를 열 수 없습니다. + 제공된 오프라인지역정의가 월드바운즈에 적합하지 않습니다: %s + 원격 측정 설정 + -- cgit v1.2.1 From 4db617c7a9d78691d63d540adebea0fd62a641bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Fri, 27 Apr 2018 12:24:32 +0200 Subject: [android] - null check source before removing --- .../main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java | 6 +++++- .../mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index b2d7af7687..c84651da24 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -759,9 +759,13 @@ final class NativeMapView { return null; } Source source = getSource(sourceId); - return removeSource(source); + if (source != null) { + return removeSource(source); + } + return null; } + @Nullable public Source removeSource(@NonNull Source source) { if (isDestroyedOn("removeSource")) { return null; diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java index fc526176d4..23a75d1642 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java @@ -280,6 +280,20 @@ public class RuntimeStyleTests extends BaseActivityTest { }); } + @Test + public void testRemoveNonExistingSource() { + invoke(mapboxMap, (uiController, mapboxMap) -> mapboxMap.removeSource("source")); + } + + @Test + public void testRemoveNonExistingLayer() { + invoke(mapboxMap, (uiController, mapboxMap) -> { + mapboxMap.removeLayer("layer"); + mapboxMap.removeLayerAt(mapboxMap.getLayers().size() + 1); + mapboxMap.removeLayerAt(-1); + }); + } + /** * https://github.com/mapbox/mapbox-gl-native/issues/7973 */ -- cgit v1.2.1 From f0b5a56a4bfd9b2e2c057fe1501f432c36a65fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 1 May 2018 15:33:33 +0200 Subject: [android] - unwrap LatLngBounds before creating core object --- .../com/mapbox/mapboxsdk/geometry/LatLngBounds.java | 13 +++++-------- .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 2 +- .../mapbox/mapboxsdk/geometry/LatLngBoundsTest.java | 3 +-- platform/android/src/geometry/lat_lng_bounds.cpp | 19 +++++++++++-------- 4 files changed, 18 insertions(+), 19 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index 55494b72d8..2b56f5b326 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -28,7 +28,7 @@ public class LatLngBounds implements Parcelable { /** * Construct a new LatLngBounds based on its corners, given in NESW * order. - * + *

* If eastern longitude is smaller than the western one, bounds will include antimeridian. * For example, if the NE point is (10, -170) and the SW point is (-10, 170), then bounds will span over 20 degrees * and cross the antimeridian. @@ -75,7 +75,6 @@ public class LatLngBounds implements Parcelable { if (longCenter >= GeometryConstants.MAX_LONGITUDE) { longCenter = this.longitudeEast - halfSpan; } - return new LatLng(latCenter, longCenter); } return new LatLng(latCenter, longCenter); @@ -188,7 +187,6 @@ public class LatLngBounds implements Parcelable { return GeometryConstants.LONGITUDE_SPAN - longSpan; } - static double getLongitudeSpan(final double longEast, final double longWest) { double longSpan = Math.abs(longEast - longWest); if (longEast >= longWest) { @@ -278,12 +276,11 @@ public class LatLngBounds implements Parcelable { /** * Constructs a LatLngBounds from doubles representing a LatLng pair. - * + *

* This values of latNorth and latSouth should be in the range of [-90, 90], * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, * otherwise IllegalArgumentException will be thrown. * latNorth should be greater or equal latSouth, otherwise IllegalArgumentException will be thrown. - * *

* This method doesn't recalculate most east or most west boundaries. * Note that lonEast and lonWest will be wrapped to be in the range of [-180, 180], @@ -334,14 +331,14 @@ public class LatLngBounds implements Parcelable { /** * Constructs a LatLngBounds from a Tile identifier. - * + *

* Returned bounds will have latitude in the range of Mercator projection. - * @see GeometryConstants#MIN_MERCATOR_LATITUDE - * @see GeometryConstants#MAX_MERCATOR_LATITUDE * * @param z Tile zoom level. * @param x Tile X coordinate. * @param y Tile Y coordinate. + * @see GeometryConstants#MIN_MERCATOR_LATITUDE + * @see GeometryConstants#MAX_MERCATOR_LATITUDE */ public static LatLngBounds from(int z, int x, int y) { return new LatLngBounds(lat_(z, y), lon_(z, x + 1), lat_(z, y + 1), lon_(z, x)); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 5e36dd0f78..cfa7143671 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -1550,7 +1550,7 @@ public final class MapboxMap { * @param padding the padding to apply to the bounds * @return the camera position that fits the bounds and padding */ - public CameraPosition getCameraForLatLngBounds(@Nullable LatLngBounds latLngBounds, int[] padding) { + public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, int[] padding) { // get padded camera position from LatLngBounds return nativeMapView.getCameraForLatLngBounds(latLngBounds, padding); } diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java index e072f07fb9..c66e4b6fda 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java @@ -524,7 +524,6 @@ public class LatLngBoundsTest { LatLngBounds.from(0, Double.POSITIVE_INFINITY, -20, -20); } - @Test public void testConstructorChecksSouthLatitudeNaN() { exception.expect(IllegalArgumentException.class); @@ -543,7 +542,7 @@ public class LatLngBoundsTest { public void testConstructorChecksSouthLatitudeGreaterThan90() { exception.expect(IllegalArgumentException.class); exception.expectMessage("latitude must be between -90 and 90"); - LatLngBounds.from(20, 20,95, 0); + LatLngBounds.from(20, 20, 95, 0); } @Test diff --git a/platform/android/src/geometry/lat_lng_bounds.cpp b/platform/android/src/geometry/lat_lng_bounds.cpp index ec1a32fed5..827ee52e95 100644 --- a/platform/android/src/geometry/lat_lng_bounds.cpp +++ b/platform/android/src/geometry/lat_lng_bounds.cpp @@ -9,14 +9,17 @@ jni::Object LatLngBounds::New(jni::JNIEnv& env, mbgl::LatLngBounds } mbgl::LatLngBounds LatLngBounds::getLatLngBounds(jni::JNIEnv& env, jni::Object bounds) { - static auto swLat = LatLngBounds::javaClass.GetField(env, "latitudeSouth"); - static auto swLon = LatLngBounds::javaClass.GetField(env, "longitudeWest"); - static auto neLat = LatLngBounds::javaClass.GetField(env, "latitudeNorth"); - static auto neLon = LatLngBounds::javaClass.GetField(env, "longitudeEast"); - return mbgl::LatLngBounds::hull( - { bounds.Get(env, swLat), bounds.Get(env, swLon) }, - { bounds.Get(env, neLat), bounds.Get(env, neLon) } - ); + static auto swLatField = LatLngBounds::javaClass.GetField(env, "latitudeSouth"); + static auto swLonField = LatLngBounds::javaClass.GetField(env, "longitudeWest"); + static auto neLatField = LatLngBounds::javaClass.GetField(env, "latitudeNorth"); + static auto neLonField = LatLngBounds::javaClass.GetField(env, "longitudeEast"); + + mbgl::LatLng sw = { bounds.Get(env, swLatField), bounds.Get(env, swLonField) }; + mbgl::LatLng ne = { bounds.Get(env, neLatField), bounds.Get(env, neLonField) }; + + sw.unwrapForShortestPath(ne); + + return mbgl::LatLngBounds::hull(sw, ne); } void LatLngBounds::registerNative(jni::JNIEnv& env) { -- cgit v1.2.1 From 5388f9ea2c9826a45582343bc0b555fddf7ff28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 30 Apr 2018 18:32:37 +0200 Subject: [android] - checking is renderer is not destroyed before delivering the snapshot --- .../mapboxsdk/maps/renderer/MapRenderer.java | 8 ++------ platform/android/src/map_renderer.cpp | 23 +++++++--------------- platform/android/src/map_renderer.hpp | 6 +----- 3 files changed, 10 insertions(+), 27 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java index f1c70325a0..fcee5bd179 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java @@ -37,11 +37,11 @@ public abstract class MapRenderer implements MapRendererScheduler { } public void onPause() { - nativeOnPause(); + // Implement if needed } public void onResume() { - nativeOnResume(); + // Implement if needed } public void onStop() { @@ -124,10 +124,6 @@ public abstract class MapRenderer implements MapRendererScheduler { private native void nativeRender(); - private native void nativeOnResume(); - - private native void nativeOnPause(); - private long frames; private long timeElapsed; diff --git a/platform/android/src/map_renderer.cpp b/platform/android/src/map_renderer.cpp index f7e16b7091..ba6fdc63b0 100644 --- a/platform/android/src/map_renderer.cpp +++ b/platform/android/src/map_renderer.cpp @@ -29,6 +29,7 @@ MapRenderer::MapRenderer(jni::JNIEnv& _env, jni::Object obj, MapRenderer::~MapRenderer() = default; void MapRenderer::reset() { + destroyed = true; // Make sure to destroy the renderer on the GL Thread auto self = ActorRef(*this, mailbox); self.ask(&MapRenderer::resetRenderer).wait(); @@ -88,8 +89,10 @@ void MapRenderer::requestSnapshot(SnapshotCallback callback) { self.invoke( &MapRenderer::scheduleSnapshot, std::make_unique([&, callback=std::move(callback), runloop=util::RunLoop::Get()](PremultipliedImage image) { - runloop->invoke([callback=std::move(callback), image=std::move(image)]() mutable { - callback(std::move(image)); + runloop->invoke([callback=std::move(callback), image=std::move(image), renderer=std::move(this)]() mutable { + if (renderer && !renderer->destroyed) { + callback(std::move(image)); + } }); snapshotCallback.reset(); }) @@ -136,7 +139,7 @@ void MapRenderer::render(JNIEnv&) { renderer->render(*params); // Deliver the snapshot if requested - if (snapshotCallback && !paused) { + if (snapshotCallback) { snapshotCallback->operator()(backend->readFramebuffer()); snapshotCallback.reset(); } @@ -174,14 +177,6 @@ void MapRenderer::onSurfaceChanged(JNIEnv&, jint width, jint height) { requestRender(); } -void MapRenderer::onResume(JNIEnv&) { - paused = false; -} - -void MapRenderer::onPause(JNIEnv&) { - paused = true; -} - // Static methods // jni::Class MapRenderer::javaClass; @@ -200,11 +195,7 @@ void MapRenderer::registerNative(jni::JNIEnv& env) { METHOD(&MapRenderer::onSurfaceCreated, "nativeOnSurfaceCreated"), METHOD(&MapRenderer::onSurfaceChanged, - "nativeOnSurfaceChanged"), - METHOD(&MapRenderer::onResume, - "nativeOnResume"), - METHOD(&MapRenderer::onPause, - "nativeOnPause")); + "nativeOnSurfaceChanged")); } MapRenderer& MapRenderer::getNativePeer(JNIEnv& env, jni::Object jObject) { diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp index 5fb5ef1a61..97d2db4a91 100644 --- a/platform/android/src/map_renderer.hpp +++ b/platform/android/src/map_renderer.hpp @@ -98,10 +98,6 @@ private: void onSurfaceChanged(JNIEnv&, jint width, jint height); - void onResume(JNIEnv&); - - void onPause(JNIEnv&); - private: GenericUniqueWeakObject javaPeer; @@ -124,7 +120,7 @@ private: std::mutex updateMutex; bool framebufferSizeChanged = false; - std::atomic paused {false}; + std::atomic destroyed {false}; std::unique_ptr snapshotCallback; }; -- cgit v1.2.1 From 2f0475b061e5d7791481427d8b7250b39a6b8073 Mon Sep 17 00:00:00 2001 From: tobrun Date: Fri, 4 May 2018 14:31:58 +0200 Subject: [android] - update changelog for release v6.1.0 --- platform/android/CHANGELOG.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 8a98e78a71..9d9d22e1f9 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,10 +2,19 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## 6.0.2 +## 6.1.0 - May 4, 2018 + - Unwrap LatLngBounds during JNI conversion [#11807](https://github.com/mapbox/mapbox-gl-native/pull/11807) + - Check if renderer is not destroyed before delivering snapshot [#11800](https://github.com/mapbox/mapbox-gl-native/pull/11800) + - Null-check source before removing [#11789](https://github.com/mapbox/mapbox-gl-native/pull/11789) + - Flutter support: promote pixel-ratio to public API NativeMapView [#11772](https://github.com/mapbox/mapbox-gl-native/pull/11772) + - Unwrap LatLngBounds for the shortest path when requesting camera [#11759](https://github.com/mapbox/mapbox-gl-native/pull/11759) + - Flutter support: integrate view callback abstraction [#11706](https://github.com/mapbox/mapbox-gl-native/pull/11706) + - Match expression doc tweaks [#11691](https://github.com/mapbox/mapbox-gl-native/pull/11691) + - Improve stop javadoc to include interpolate [#11677](https://github.com/mapbox/mapbox-gl-native/pull/11677) - Reduce per-frame render CPU time [#11811](https://github.com/mapbox/mapbox-gl-native/issues/11811) - Add Korean localization [#11792](https://github.com/mapbox/mapbox-gl-native/pull/11792) - + - Add Danish localization; update Hungarian, Russian, Swedish translations [#11136](https://github.com/mapbox/mapbox-gl-native/pull/11136) + ## 6.0.1 - April 17, 2018 - Bump telemetry version to 3.0.2 [#11710](https://github.com/mapbox/mapbox-gl-native/pull/11710) -- cgit v1.2.1 From 4f0241c1afcf46370eb325e80c1d52a4b490df38 Mon Sep 17 00:00:00 2001 From: tobrun Date: Fri, 4 May 2018 14:35:10 +0200 Subject: [android] - bump snapshot version --- platform/android/MapboxGLAndroidSDK/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties index bdfc444454..a49ef47674 100644 --- a/platform/android/MapboxGLAndroidSDK/gradle.properties +++ b/platform/android/MapboxGLAndroidSDK/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.mapbox.mapboxsdk -VERSION_NAME=6.1.0-SNAPSHOT +VERSION_NAME=6.2.0-SNAPSHOT POM_DESCRIPTION=Mapbox GL Android SDK POM_URL=https://github.com/mapbox/mapbox-gl-native -- cgit v1.2.1 From 83b6c4405aba37f4125c3086aeec08aadb307837 Mon Sep 17 00:00:00 2001 From: tobrun Date: Fri, 4 May 2018 15:40:41 +0200 Subject: [android] - update changelog for v5.5.3 --- platform/android/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 246b5828c4..9943e3b316 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 5.5.3 - May 4, 2018 + - Check if renderer is not destroyed before delivering snapshot [#11800](https://github.com/mapbox/mapbox-gl-native/pull/11800) + ## 6.0.1 - April 17, 2018 - Bump telemetry version to 3.0.2 [#11710](https://github.com/mapbox/mapbox-gl-native/pull/11710) -- cgit v1.2.1 From bc7bed642e6bb1c26feedb5c04ec64c2ff7fdd2d Mon Sep 17 00:00:00 2001 From: tobrun Date: Fri, 4 May 2018 14:31:58 +0200 Subject: [android] - update changelog for release v6.1.0 --- platform/android/CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 9943e3b316..c35cde88e0 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,19 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 6.1.0 - May 4, 2018 + - Unwrap LatLngBounds during JNI conversion [#11807](https://github.com/mapbox/mapbox-gl-native/pull/11807) + - Check if renderer is not destroyed before delivering snapshot [#11800](https://github.com/mapbox/mapbox-gl-native/pull/11800) + - Null-check source before removing [#11789](https://github.com/mapbox/mapbox-gl-native/pull/11789) + - Flutter support: promote pixel-ratio to public API NativeMapView [#11772](https://github.com/mapbox/mapbox-gl-native/pull/11772) + - Unwrap LatLngBounds for the shortest path when requesting camera [#11759](https://github.com/mapbox/mapbox-gl-native/pull/11759) + - Flutter support: integrate view callback abstraction [#11706](https://github.com/mapbox/mapbox-gl-native/pull/11706) + - Match expression doc tweaks [#11691](https://github.com/mapbox/mapbox-gl-native/pull/11691) + - Improve stop javadoc to include interpolate [#11677](https://github.com/mapbox/mapbox-gl-native/pull/11677) + - Reduce per-frame render CPU time [#11811](https://github.com/mapbox/mapbox-gl-native/issues/11811) + - Add Korean localization [#11792](https://github.com/mapbox/mapbox-gl-native/pull/11792) + - Add Danish localization; update Hungarian, Russian, Swedish translations [#11136](https://github.com/mapbox/mapbox-gl-native/pull/11136) + ## 5.5.3 - May 4, 2018 - Check if renderer is not destroyed before delivering snapshot [#11800](https://github.com/mapbox/mapbox-gl-native/pull/11800) -- cgit v1.2.1 From a4892231544ccf6fcbe6dc233b5462f550cbbbcc Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 7 May 2018 16:11:00 +0200 Subject: [android] - update telemetry to 3.1.0 --- platform/android/gradle/dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index a5c6ad0da3..7b31cf9e4c 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -9,7 +9,7 @@ ext { versions = [ mapboxServices : '3.0.1', - mapboxTelemetry: '3.0.2', + mapboxTelemetry: '3.1.0', mapboxGestures : '0.2.0', supportLib : '25.4.0', espresso : '3.0.1', -- cgit v1.2.1 From 9c1e414981616e4a65ed0c3b632019178fd2e95a Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 7 May 2018 16:11:00 +0200 Subject: [android] - update telemetry to 3.1.0 --- platform/android/gradle/dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index 69b0c4b97f..07a9938915 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -9,7 +9,7 @@ ext { versions = [ mapboxServices : '3.0.1', - mapboxTelemetry: '3.0.2', + mapboxTelemetry: '3.1.0', mapboxGestures : '0.2.0', supportLib : '25.4.0', espresso : '3.0.1', -- cgit v1.2.1 From a24b8fd206265b597c6b12ee8f5b335a7027851e Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 7 May 2018 17:28:48 +0200 Subject: [android] - update changelog to v6.1.1 --- platform/android/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 9d9d22e1f9..384dcdf883 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 6.1.1 - May 7, 2018 + - Update telemetry to 3.1.0 [#11855](https://github.com/mapbox/mapbox-gl-native/pull/11855) + ## 6.1.0 - May 4, 2018 - Unwrap LatLngBounds during JNI conversion [#11807](https://github.com/mapbox/mapbox-gl-native/pull/11807) - Check if renderer is not destroyed before delivering snapshot [#11800](https://github.com/mapbox/mapbox-gl-native/pull/11800) -- cgit v1.2.1 From d1dff1d6e782bc6e9d7a7df27e566bf1f1cf862b Mon Sep 17 00:00:00 2001 From: tobrun Date: Fri, 4 May 2018 12:44:03 +0200 Subject: [android] - build release with debug signing --- platform/android/MapboxGLAndroidSDKTestApp/build.gradle | 1 + 1 file changed, 1 insertion(+) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle index edf860a946..80be26d3ae 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle +++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle @@ -41,6 +41,7 @@ android { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.debug } } -- cgit v1.2.1 From a4e2c1af1fd83b22ef4ee57ab19a15616224f8b8 Mon Sep 17 00:00:00 2001 From: Lucas Wojciechowski Date: Thu, 10 May 2018 12:37:14 -0700 Subject: [core] Convert "legacy" filters directly into expressions (#11610) Ports the specialized filter-* expressions from GL JS, adding them to src/mbgl/style/expression/compound_expression.cpp --- platform/android/src/style/layers/layer.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'platform/android') diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp index 6fe6e3cb29..c7a6bcd3a3 100644 --- a/platform/android/src/style/layers/layer.cpp +++ b/platform/android/src/style/layers/layer.cpp @@ -157,14 +157,12 @@ namespace android { using namespace mbgl::style::conversion; Filter filter = layer.accept(GetFilterEvaluator()); - - jni::Object converted; - if (filter.is()) { - ExpressionFilter filterExpression = filter.get(); - mbgl::Value expressionValue = filterExpression.expression.get()->serialize(); - converted = gson::JsonElement::New(env, expressionValue); + if (filter.expression) { + mbgl::Value expressionValue = (*filter.expression)->serialize(); + return gson::JsonElement::New(env, expressionValue); + } else { + return jni::Object(); } - return converted; } struct SetSourceLayerEvaluator { -- cgit v1.2.1 From b6f56db4fe0f3b40c13494e269855e57e4ed660c Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 7 May 2018 11:26:05 +0200 Subject: [android] - avoid rounding the pixelratio of the image addded through NativeMapView#addImage --- .../src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 0e77910c3d..305dd906dd 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -772,8 +772,9 @@ final class NativeMapView { return; } - // Determine pixel ratio - nativeAddImage(name, image, image.getDensity() / DisplayMetrics.DENSITY_DEFAULT); + // Determine pixel ratio, cast to float to avoid rounding, see mapbox-gl-native/issues/11809 + float pixelRatio = (float) image.getDensity() / DisplayMetrics.DENSITY_DEFAULT; + nativeAddImage(name, image, pixelRatio); } public void addImages(@NonNull HashMap bitmapHashMap) { -- cgit v1.2.1 From 36d30f13fcc6f4356e0d58318fc168c77d7dbecf Mon Sep 17 00:00:00 2001 From: Osana Babayan <32496536+osana@users.noreply.github.com> Date: Fri, 11 May 2018 16:00:45 -0400 Subject: [android] added more tests for LatLngBounds.union(), LatLngBounds.intersect() (#11777) fixed going over antimeridian for both --- .../mapbox/mapboxsdk/geometry/LatLngBounds.java | 226 ++++++++++++++++----- .../mapboxsdk/geometry/LatLngBoundsTest.java | 218 +++++++++++++++++++- 2 files changed, 391 insertions(+), 53 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index 90cb56f605..c639e49013 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -294,6 +294,20 @@ public class LatLngBounds implements Parcelable { @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latSouth, double lonWest) { + checkParams(latNorth, lonEast, latSouth, lonWest); + + lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); + lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); + + return new LatLngBounds(latNorth, lonEast, latSouth, lonWest); + } + + private static void checkParams( + @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latNorth, + double lonEast, + @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latSouth, + double lonWest) { + if (Double.isNaN(latNorth) || Double.isNaN(latSouth)) { throw new IllegalArgumentException("latitude must not be NaN"); } @@ -314,11 +328,6 @@ public class LatLngBounds implements Parcelable { if (latNorth < latSouth) { throw new IllegalArgumentException("LatSouth cannot be less than latNorth"); } - - lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); - lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); - - return new LatLngBounds(latNorth, lonEast, latSouth, lonWest); } private static double lat_(int z, int y) { @@ -395,7 +404,7 @@ public class LatLngBounds implements Parcelable { return (longitude <= eastLon) && (longitude >= westLon); } - return (longitude < eastLon) || (longitude > westLon); + return (longitude <= eastLon) || (longitude >= westLon); } /** @@ -426,36 +435,94 @@ public class LatLngBounds implements Parcelable { * @param bounds LatLngBounds to add * @return LatLngBounds */ - public LatLngBounds union(LatLngBounds bounds) { - return union(bounds.getLatNorth(), bounds.getLonEast(), bounds.getLatSouth(), bounds.getLonWest()); + public @NonNull LatLngBounds union(@NonNull LatLngBounds bounds) { + return unionNoParamCheck(bounds.getLatNorth(), bounds.getLonEast(), bounds.getLatSouth(), bounds.getLonWest()); } /** * Returns a new LatLngBounds that stretches to include another LatLngBounds, * given by corner points. + *

+ * This values of northLat and southLat should be in the range of [-90, 90], + * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, + * otherwise IllegalArgumentException will be thrown. + * northLat should be greater or equal southLat, otherwise IllegalArgumentException will be thrown. + *

+ * This method doesn't recalculate most east or most west boundaries. + * Note that eastLon and westLon will be wrapped to be in the range of [-180, 180], + * see {@link GeometryConstants#MIN_LONGITUDE} and {@link GeometryConstants#MAX_LONGITUDE} * - * @param latNorth Northern Latitude - * @param lonEast Eastern Longitude - * @param latSouth Southern Latitude - * @param lonWest Western Longitude - * @return BoundingBox - */ - public LatLngBounds union(final double latNorth, final double lonEast, final double latSouth, final double lonWest) { - double north = (this.latitudeNorth < latNorth) ? latNorth : this.latitudeNorth; - double south = (this.latitudeSouth > latSouth) ? latSouth : this.latitudeSouth; - - if (LatLngSpan.getLongitudeSpan(lonEast, this.longitudeWest) - < LatLngSpan.getLongitudeSpan(this.longitudeEast, lonWest)) { - return new LatLngBounds(north, - lonEast, - south, + * @param northLat Northern Latitude corner point + * @param eastLon Eastern Longitude corner point + * @param southLat Southern Latitude corner point + * @param westLon Western Longitude corner point + * @return LatLngBounds + */ + public @NonNull LatLngBounds union( + @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat, + double eastLon, + @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat, + double westLon) { + + checkParams(northLat, eastLon, southLat, westLon); + + return unionNoParamCheck(northLat, eastLon, southLat, westLon); + } + + private @NonNull LatLngBounds unionNoParamCheck( + @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat, + double eastLon, + @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat, + double westLon) { + + northLat = (this.latitudeNorth < northLat) ? northLat : this.latitudeNorth; + southLat = (this.latitudeSouth > southLat) ? southLat : this.latitudeSouth; + + eastLon = LatLng.wrap(eastLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); + westLon = LatLng.wrap(westLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); + + // longitudes match + if (this.longitudeEast == eastLon && this.longitudeWest == westLon) { + return new LatLngBounds(northLat, eastLon, southLat, westLon); + } + + boolean eastInThis = containsLongitude(this.longitudeEast, this.longitudeWest, eastLon); + boolean westInThis = containsLongitude(this.longitudeEast, this.longitudeWest, westLon); + boolean thisEastInside = containsLongitude(eastLon, westLon, this.longitudeEast); + boolean thisWestInside = containsLongitude(eastLon, westLon, this.longitudeWest); + + // two intersections on each end - covers entire longitude + if (eastInThis && westInThis && thisEastInside && thisWestInside) { + return new LatLngBounds(northLat, GeometryConstants.MAX_LONGITUDE, southLat, GeometryConstants.MIN_LONGITUDE); + } + + if (eastInThis) { + if (westInThis) { + return new LatLngBounds(northLat, this.longitudeEast, southLat, this.longitudeWest); + } + return new LatLngBounds(northLat, this.longitudeEast, southLat, westLon); + } + + if (thisEastInside) { + if (thisWestInside) { + return new LatLngBounds(northLat, eastLon, southLat, westLon); + } + return new LatLngBounds(northLat, eastLon, southLat, this.longitudeWest); + } + + // bounds do not intersect, find where they will form shortest union + if (LatLngSpan.getLongitudeSpan(eastLon, this.longitudeWest) + < LatLngSpan.getLongitudeSpan(this.longitudeEast, westLon)) { + return new LatLngBounds(northLat, + eastLon, + southLat, this.longitudeWest); } - return new LatLngBounds(north, + return new LatLngBounds(northLat, this.longitudeEast, - south, - lonWest); + southLat, + westLon); } /** @@ -464,32 +531,89 @@ public class LatLngBounds implements Parcelable { * @param box LatLngBounds to intersect with * @return LatLngBounds */ - @Nullable - public LatLngBounds intersect(LatLngBounds box) { - double minLonWest = Math.max(getLonWest(), box.getLonWest()); - double maxLonEast = Math.min(getLonEast(), box.getLonEast()); - if (maxLonEast > minLonWest) { - double minLatSouth = Math.max(getLatSouth(), box.getLatSouth()); - double maxLatNorth = Math.min(getLatNorth(), box.getLatNorth()); - if (maxLatNorth > minLatSouth) { - return new LatLngBounds(maxLatNorth, maxLonEast, minLatSouth, minLonWest); - } - } - return null; + public @Nullable LatLngBounds intersect(@NonNull LatLngBounds box) { + return intersectNoParamCheck(box.getLatNorth(), box.getLonEast(), box.getLatSouth(), box.getLonWest()); } /** * Returns a new LatLngBounds that is the intersection of this with another LatLngBounds + *

+ * This values of northLat and southLat should be in the range of [-90, 90], + * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, + * otherwise IllegalArgumentException will be thrown. + * northLat should be greater or equal southLat, otherwise IllegalArgumentException will be thrown. + *

+ * This method doesn't recalculate most east or most west boundaries. + * Note that eastLon and westLon will be wrapped to be in the range of [-180, 180], + * see {@link GeometryConstants#MIN_LONGITUDE} and {@link GeometryConstants#MAX_LONGITUDE} * - * @param northLatitude Northern Longitude - * @param eastLongitude Eastern Latitude - * @param southLatitude Southern Longitude - * @param westLongitude Western Latitude + * @param northLat Northern Latitude corner point + * @param eastLon Eastern Longitude corner point + * @param southLat Southern Latitude corner point + * @param westLon Western Longitude corner point * @return LatLngBounds */ - public LatLngBounds intersect(double northLatitude, double eastLongitude, double southLatitude, - double westLongitude) { - return intersect(new LatLngBounds(northLatitude, eastLongitude, southLatitude, westLongitude)); + public @Nullable LatLngBounds intersect( + @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat, + double eastLon, + @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat, + double westLon) { + + checkParams(northLat, eastLon, southLat, westLon); + + return intersectNoParamCheck(northLat, eastLon, southLat, westLon); + } + + private @Nullable LatLngBounds intersectNoParamCheck( + @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat, + double eastLon, + @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat, + double westLon) { + + double maxsouthLat = Math.max(getLatSouth(), Math.min(GeometryConstants.MAX_LATITUDE, southLat)); + double minnorthLat = Math.min(getLatNorth(), Math.max(GeometryConstants.MIN_LATITUDE, northLat)); + if (minnorthLat < maxsouthLat) { + return null; + } + + eastLon = LatLng.wrap(eastLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); + westLon = LatLng.wrap(westLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); + + // longitudes match + if (this.longitudeEast == eastLon && this.longitudeWest == westLon) { + return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, westLon); + } + + boolean eastInThis = containsLongitude(this.longitudeEast, this.longitudeWest, eastLon); + boolean westInThis = containsLongitude(this.longitudeEast, this.longitudeWest, westLon); + boolean thisEastInside = containsLongitude(eastLon, westLon, this.longitudeEast); + boolean thisWestInside = containsLongitude(eastLon, westLon, this.longitudeWest); + + // two intersections : find the one that has longest span + if (eastInThis && westInThis && thisEastInside && thisWestInside) { + + if (getLongitudeSpan(eastLon, this.longitudeWest) > getLongitudeSpan(this.longitudeEast, westLon)) { + return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, this.longitudeWest); + } + + return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, westLon); + } + + if (eastInThis) { + if (westInThis) { + return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, westLon); + } + return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, this.longitudeWest); + } + + if (thisEastInside) { + if (thisWestInside) { + return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, this.longitudeWest); + } + return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, westLon); + } + + return null; } /** @@ -518,7 +642,7 @@ public class LatLngBounds implements Parcelable { return (int) ((latitudeNorth + 90) + ((latitudeSouth + 90) * 1000) + ((longitudeEast + 180) * 1000000) - + ((longitudeEast + 180) * 1000000000)); + + ((longitudeWest + 180) * 1000000000)); } /** @@ -546,11 +670,11 @@ public class LatLngBounds implements Parcelable { } private static LatLngBounds readFromParcel(final Parcel in) { - final double lonNorth = in.readDouble(); - final double latEast = in.readDouble(); - final double lonSouth = in.readDouble(); - final double latWest = in.readDouble(); - return new LatLngBounds(lonNorth, latEast, lonSouth, latWest); + final double northLat = in.readDouble(); + final double eastLon = in.readDouble(); + final double southLat = in.readDouble(); + final double westLon = in.readDouble(); + return new LatLngBounds(northLat, eastLon, southLat, westLon); } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java index c66e4b6fda..789a1b2b37 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java @@ -356,6 +356,58 @@ public class LatLngBoundsTest { assertNull(latLngBounds.intersect(this.latLngBounds)); } + @Test + public void intersectNorthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds intersectLatLngBounds = + LatLngBounds.from(10, 10, 0, 0) + .intersect(200, 200, 0, 0); + } + + @Test + public void intersectSouthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds intersectLatLngBounds = + LatLngBounds.from(0, 0, -10, -10) + .intersect(0, 0, -200, -200); + } + + @Test + public void intersectSouthLessThanNorthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("LatSouth cannot be less than latNorth"); + + LatLngBounds intersectLatLngBounds = + LatLngBounds.from(10, 10, 0, 0) + .intersect(0, 200, 20, 0); + } + + + @Test + public void intersectEastWrapCheck() { + + LatLngBounds latLngBounds1 = LatLngBounds.from(10, -150, 0, 0); + LatLngBounds latLngBounds2 = LatLngBounds.from(90, 200, 0, 0); + + LatLngBounds intersectLatLngBounds = LatLngBounds.from(10, -160, 0, 0); + + assertEquals(latLngBounds1.intersect(latLngBounds2), intersectLatLngBounds); + assertEquals(latLngBounds2.intersect(latLngBounds1), intersectLatLngBounds); + } + + @Test + public void intersectWestWrapCheck() { + LatLngBounds latLngBounds1 = LatLngBounds.from(0, 0, -10, 150); + LatLngBounds latLngBounds2 = LatLngBounds.from(0, 0, -90, -200); + + LatLngBounds intersectLatLngBounds = LatLngBounds.from(0, 0, -10, 160); + + assertEquals(latLngBounds1.intersect(latLngBounds2), intersectLatLngBounds); + assertEquals(latLngBounds2.intersect(latLngBounds1), intersectLatLngBounds); + } + @Test public void innerUnion() { LatLngBounds latLngBounds = new LatLngBounds.Builder() @@ -391,14 +443,176 @@ public class LatLngBoundsTest { .include(new LatLng(-10, -160)) .build(); - assertEquals("outer union should match", - latLngBounds1.union(latLngBounds2), + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, + new LatLngBounds.Builder() + .include(new LatLng(10, 160)) + .include(new LatLng(-10, -160)) + .build()); + + assertEquals(union1, union2); + } + + @Test + public void unionOverDateLine2() { + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .include(new LatLng(10, 170)) + .include(new LatLng(0, 160)) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(new LatLng(0, 165)) + .include(new LatLng(-10, -160)) + .build(); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, + new LatLngBounds.Builder() + .include(new LatLng(10, 160)) + .include(new LatLng(-10, -160)) + .build()); + + assertEquals(union1, union2); + } + + @Test + public void unionOverDateLine3() { + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .include(new LatLng(10, -165)) + .include(new LatLng(0, 160)) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(new LatLng(0, -170)) + .include(new LatLng(-10, -160)) + .build(); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, + new LatLngBounds.Builder() + .include(new LatLng(10, 160)) + .include(new LatLng(-10, -160)) + .build()); + + assertEquals(union1, union2); + } + + @Test + public void unionOverDateLine4() { + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .include(new LatLng(10, -160)) + .include(new LatLng(0, 160)) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(new LatLng(0, -170)) + .include(new LatLng(-10, -175)) + .build(); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, new LatLngBounds.Builder() .include(new LatLng(10, 160)) .include(new LatLng(-10, -160)) .build()); + + assertEquals(union1, union2); } + @Test + public void unionOverDateLine5() { + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .include(new LatLng(10, -160)) + .include(new LatLng(0, 160)) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(new LatLng(0, 170)) + .include(new LatLng(-10, 175)) + .build(); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, + new LatLngBounds.Builder() + .include(new LatLng(10, 160)) + .include(new LatLng(-10, -160)) + .build()); + + assertEquals(union1, union2); + } + + @Test + public void unionOverDateLineReturnWorldLonSpan() { + LatLngBounds latLngBounds1 = LatLngBounds.from(10, -160, -10, -10); + LatLngBounds latLngBounds2 = LatLngBounds.from(10, 10, -10, 160); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, union2); + assertEquals(union1, LatLngBounds.from(10, 180, -10, -180)); + } + + @Test + public void unionNorthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds unionLatLngBounds = + LatLngBounds.from(10, 10, 0, 0) + .union(200, 200, 0, 0); + } + + @Test + public void unionSouthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds unionLatLngBounds = + LatLngBounds.from(0, 0, -10, -10) + .union(0, 0, -200, -200); + } + + @Test + public void unionSouthLessThanNorthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("LatSouth cannot be less than latNorth"); + + LatLngBounds unionLatLngBounds = + LatLngBounds.from(10, 10, 0, 0) + .union(0, 200, 20, 0); + } + + + @Test + public void unionEastWrapCheck() { + + LatLngBounds latLngBounds1 = LatLngBounds.from(10, 10, 0, 0); + LatLngBounds latLngBounds2 = LatLngBounds.from(90, 200, 0, 0); + LatLngBounds unionLatLngBounds = LatLngBounds.from(90, -160, 0, 0); + + assertEquals(latLngBounds1.union(latLngBounds2), unionLatLngBounds); + assertEquals(latLngBounds2.union(latLngBounds1), unionLatLngBounds); + } + + @Test + public void unionWestWrapCheck() { + LatLngBounds latLngBounds1 = LatLngBounds.from(0, 0, -10, -10); + LatLngBounds latLngBounds2 = LatLngBounds.from(0, 0, -90, -200); + + LatLngBounds unionLatLngBounds = LatLngBounds.from(0, 0, -90, 160); + + assertEquals(latLngBounds1.union(latLngBounds2), unionLatLngBounds); + assertEquals(latLngBounds2.union(latLngBounds1), unionLatLngBounds); + } @Test public void northWest() { -- cgit v1.2.1 From 7854dfa3a02a7c5425b1c5066012fb81028df967 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 17 Apr 2018 11:26:25 +0200 Subject: [android] - integrate view callback abstraction --- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 34 +++++----- .../com/mapbox/mapboxsdk/maps/NativeMapView.java | 73 +++++++++++++--------- 2 files changed, 57 insertions(+), 50 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 22d5dd8f19..4ccbc88375 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.maps; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.PointF; import android.opengl.GLSurfaceView; import android.os.Build; @@ -40,6 +41,7 @@ import com.mapbox.mapboxsdk.maps.renderer.textureview.TextureViewMapRenderer; import com.mapbox.mapboxsdk.maps.widgets.CompassView; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; import com.mapbox.mapboxsdk.storage.FileSource; +import com.mapbox.mapboxsdk.utils.BitmapUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -47,13 +49,10 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; -import timber.log.Timber; - import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION; import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE; @@ -71,13 +70,14 @@ import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE; * Warning: Please note that you are responsible for getting permission to use the map data, * and for ensuring your use adheres to the relevant terms of use. */ -public class MapView extends FrameLayout { +public class MapView extends FrameLayout implements NativeMapView.ViewCallback { private final MapCallback mapCallback = new MapCallback(); private MapboxMap mapboxMap; private NativeMapView nativeMapView; private MapboxMapOptions mapboxMapOptions; + private MapRenderer mapRenderer; private boolean destroyed; private boolean hasSurface; @@ -90,9 +90,6 @@ public class MapView extends FrameLayout { private MapKeyListener mapKeyListener; private MapZoomButtonController mapZoomButtonController; private Bundle savedInstanceState; - private final CopyOnWriteArrayList onMapChangedListeners = new CopyOnWriteArrayList<>(); - - private MapRenderer mapRenderer; @UiThread public MapView(@NonNull Context context) { @@ -307,7 +304,7 @@ public class MapView extends FrameLayout { addView(glSurfaceView, 0); } - nativeMapView = new NativeMapView(this, mapRenderer); + nativeMapView = new NativeMapView(getContext(), this, mapRenderer); nativeMapView.resizeView(getMeasuredWidth(), getMeasuredHeight()); } @@ -566,19 +563,18 @@ public class MapView extends FrameLayout { } // - // Map events + // ViewCallback // - void onMapChange(int rawChange) { - for (MapView.OnMapChangedListener onMapChangedListener : onMapChangedListeners) { - try { - onMapChangedListener.onMapChanged(rawChange); - } catch (RuntimeException err) { - Timber.e(err, "Exception in MapView.OnMapChangedListener"); - } - } + @Override + public Bitmap getViewContent() { + return BitmapUtils.createBitmapFromView(this); } + // + // Map events + // + /** *

* Add a callback that's invoked when the displayed map view changes. @@ -590,7 +586,7 @@ public class MapView extends FrameLayout { */ public void addOnMapChangedListener(@Nullable OnMapChangedListener listener) { if (listener != null) { - onMapChangedListeners.add(listener); + nativeMapView.addOnMapChangedListener(listener); } } @@ -602,7 +598,7 @@ public class MapView extends FrameLayout { */ public void removeOnMapChangedListener(@Nullable OnMapChangedListener listener) { if (listener != null) { - onMapChangedListeners.remove(listener); + nativeMapView.removeOnMapChangedListener(listener); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 305dd906dd..7cd1177523 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -5,6 +5,7 @@ import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; import android.os.AsyncTask; +import android.os.Handler; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -38,33 +39,36 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; import timber.log.Timber; // Class that wraps the native methods for convenience final class NativeMapView { - // Flag to indicating destroy was called - private boolean destroyed = false; - - // Holds the pointer to JNI NativeMapView - private long nativePtr = 0; - - // Used for callbacks - private MapView mapView; - //Hold a reference to prevent it from being GC'd as long as it's used on the native side private final FileSource fileSource; // Used to schedule work on the MapRenderer Thread - private MapRenderer mapRenderer; + private final MapRenderer mapRenderer; + + // Used for callbacks + private ViewCallback viewCallback; // Device density private final float pixelRatio; + // Flag to indicating destroy was called + private boolean destroyed = false; + + // Holds the pointer to JNI NativeMapView + private long nativePtr = 0; + // Listener invoked to return a bitmap of the map private MapboxMap.SnapshotReadyCallback snapshotReadyCallback; + private final CopyOnWriteArrayList onMapChangedListeners = new CopyOnWriteArrayList<>(); + static { LibraryLoader.load(); } @@ -73,14 +77,11 @@ final class NativeMapView { // Constructors // - public NativeMapView(final MapView mapView, MapRenderer mapRenderer) { + public NativeMapView(final Context context, final ViewCallback viewCallback, final MapRenderer mapRenderer) { this.mapRenderer = mapRenderer; - this.mapView = mapView; - - Context context = mapView.getContext(); - fileSource = FileSource.getInstance(context); - pixelRatio = context.getResources().getDisplayMetrics().density; - + this.viewCallback = viewCallback; + this.fileSource = FileSource.getInstance(context); + this.pixelRatio = context.getResources().getDisplayMetrics().density; nativeInitialize(this, fileSource, mapRenderer, pixelRatio); } @@ -100,7 +101,7 @@ final class NativeMapView { public void destroy() { nativeDestroy(); - mapView = null; + viewCallback = null; destroyed = true; } @@ -862,8 +863,12 @@ final class NativeMapView { // protected void onMapChanged(int rawChange) { - if (mapView != null) { - mapView.onMapChange(rawChange); + for (MapView.OnMapChangedListener onMapChangedListener : onMapChangedListeners) { + try { + onMapChangedListener.onMapChanged(rawChange); + } catch (RuntimeException err) { + Timber.e(err, "Exception in MapView.OnMapChangedListener"); + } } } @@ -872,7 +877,7 @@ final class NativeMapView { return; } - Bitmap viewContent = BitmapUtils.createBitmapFromView(mapView); + Bitmap viewContent = viewCallback.getViewContent(); if (snapshotReadyCallback != null && mapContent != null && viewContent != null) { snapshotReadyCallback.onSnapshotReady(BitmapUtils.mergeBitmap(mapContent, viewContent)); } @@ -1070,14 +1075,14 @@ final class NativeMapView { if (isDestroyedOn("")) { return 0; } - return mapView.getWidth(); + return viewCallback.getWidth(); } int getHeight() { if (isDestroyedOn("")) { return 0; } - return mapView.getHeight(); + return viewCallback.getHeight(); } // @@ -1085,13 +1090,13 @@ final class NativeMapView { // void addOnMapChangedListener(@NonNull MapView.OnMapChangedListener listener) { - if (mapView != null) { - mapView.addOnMapChangedListener(listener); - } + onMapChangedListeners.add(listener); } void removeOnMapChangedListener(@NonNull MapView.OnMapChangedListener listener) { - mapView.removeOnMapChangedListener(listener); + if (onMapChangedListeners.contains(listener)) { + onMapChangedListeners.remove(listener); + } } // @@ -1107,15 +1112,15 @@ final class NativeMapView { } public void setOnFpsChangedListener(final MapboxMap.OnFpsChangedListener listener) { + final Handler handler = new Handler(); mapRenderer.queueEvent(new Runnable() { @Override public void run() { mapRenderer.setOnFpsChangedListener(new MapboxMap.OnFpsChangedListener() { - @Override public void onFpsChanged(final double fps) { - mapView.post(new Runnable() { + handler.post(new Runnable() { @Override public void run() { @@ -1124,14 +1129,12 @@ final class NativeMapView { }); } - }); } }); } - // // Image conversion // @@ -1181,4 +1184,12 @@ final class NativeMapView { } } } + + public interface ViewCallback { + int getWidth(); + + int getHeight(); + + Bitmap getViewContent(); + } } -- cgit v1.2.1 From 5380d80c88087f20238592aaa19e8b48fc383a5e Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 24 Apr 2018 11:39:40 +0200 Subject: [android] - allow early callback registration --- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 4ccbc88375..9227aabdf3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -49,6 +49,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; @@ -73,9 +74,10 @@ import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE; public class MapView extends FrameLayout implements NativeMapView.ViewCallback { private final MapCallback mapCallback = new MapCallback(); - private MapboxMap mapboxMap; + private final CopyOnWriteArrayList onMapChangedListeners = new CopyOnWriteArrayList<>(); private NativeMapView nativeMapView; + private MapboxMap mapboxMap; private MapboxMapOptions mapboxMapOptions; private MapRenderer mapRenderer; private boolean destroyed; @@ -137,7 +139,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { private void initialiseMap() { Context context = getContext(); - addOnMapChangedListener(mapCallback); + nativeMapView.addOnMapChangedListener(mapCallback); // callback for focal point invalidation final FocalPointInvalidator focalPointInvalidator = new FocalPointInvalidator(); @@ -305,6 +307,17 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { } nativeMapView = new NativeMapView(getContext(), this, mapRenderer); + nativeMapView.addOnMapChangedListener(new OnMapChangedListener() { + @Override + public void onMapChanged(int change) { + // dispatch events to external listeners + if (!onMapChangedListeners.isEmpty()) { + for (OnMapChangedListener onMapChangedListener : onMapChangedListeners) { + onMapChangedListener.onMapChanged(change); + } + } + } + }); nativeMapView.resizeView(getMeasuredWidth(), getMeasuredHeight()); } @@ -586,7 +599,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { */ public void addOnMapChangedListener(@Nullable OnMapChangedListener listener) { if (listener != null) { - nativeMapView.addOnMapChangedListener(listener); + onMapChangedListeners.add(listener); } } @@ -597,8 +610,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { * @see MapView#addOnMapChangedListener(OnMapChangedListener) */ public void removeOnMapChangedListener(@Nullable OnMapChangedListener listener) { - if (listener != null) { - nativeMapView.removeOnMapChangedListener(listener); + if (listener != null && onMapChangedListeners.contains(listener)) { + onMapChangedListeners.remove(listener); } } -- cgit v1.2.1 From 5653b340bc2de15b1d17661784bbb451b47bcece Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 24 Apr 2018 14:01:48 +0200 Subject: [android] - clear map change listeners when map is destroyed --- .../src/main/java/com/mapbox/mapboxsdk/maps/MapView.java | 1 + .../src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 9227aabdf3..4ecd7c9246 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -410,6 +410,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { @UiThread public void onDestroy() { destroyed = true; + onMapChangedListeners.clear(); mapCallback.clearOnMapReadyCallbacks(); if (nativeMapView != null && hasSurface) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 7cd1177523..ae18f741d4 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -100,9 +100,10 @@ final class NativeMapView { } public void destroy() { - nativeDestroy(); - viewCallback = null; destroyed = true; + onMapChangedListeners.clear(); + viewCallback = null; + nativeDestroy(); } public void update() { -- cgit v1.2.1 From 65743769a4fa7740eaffd91534577fe39014a13b Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 13 Apr 2018 15:43:42 +0200 Subject: [android] - improve stop javadoc to include interpolate --- .../java/com/mapbox/mapboxsdk/style/expressions/Expression.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index bd5b40c6ce..44ad5e83ed 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -2878,7 +2878,11 @@ public class Expression { } /** - * Produces a stop value to be used as part of the step expression. + * Produces a stop value. + *

+ * Can be used for {@link #stop(Object, Object)} as part of varargs parameter in + * {@link #step(Number, Expression, Stop...)} or {@link #interpolate(Interpolator, Expression, Stop...)}. + *

*

* Example usage: *

-- cgit v1.2.1 From 28da56465e59702b4ae0219f1c7494a9271f6227 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 25 Apr 2018 14:35:05 +0200 Subject: [android] - promote pixel ratio to public api of NativeMapview. --- .../src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index ae18f741d4..d258064908 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -78,10 +78,15 @@ final class NativeMapView { // public NativeMapView(final Context context, final ViewCallback viewCallback, final MapRenderer mapRenderer) { + this(context, context.getResources().getDisplayMetrics().density, viewCallback, mapRenderer); + } + + public NativeMapView(final Context context, float pixelRatio, + final ViewCallback viewCallback, final MapRenderer mapRenderer) { this.mapRenderer = mapRenderer; this.viewCallback = viewCallback; this.fileSource = FileSource.getInstance(context); - this.pixelRatio = context.getResources().getDisplayMetrics().density; + this.pixelRatio = pixelRatio; nativeInitialize(this, fileSource, mapRenderer, pixelRatio); } -- cgit v1.2.1 From 62c875e01b07197024e3806e8b2882160ce1195c Mon Sep 17 00:00:00 2001 From: Lauren Budorick Date: Mon, 14 May 2018 12:38:14 -0700 Subject: [core] Rework spec function/expression taxonomy Ports https://github.com/mapbox/mapbox-gl-js/pull/6521, updating codegen scripts to parse new expression taxonomy. --- .../mapboxsdk/testapp/style/BackgroundLayerTest.java | 2 +- .../mapboxsdk/testapp/style/CircleLayerTest.java | 2 +- .../testapp/style/FillExtrusionLayerTest.java | 2 +- .../mapbox/mapboxsdk/testapp/style/FillLayerTest.java | 2 +- .../mapboxsdk/testapp/style/HeatmapLayerTest.java | 2 +- .../mapboxsdk/testapp/style/HillshadeLayerTest.java | 2 +- .../mapbox/mapboxsdk/testapp/style/LineLayerTest.java | 2 +- .../mapboxsdk/testapp/style/RasterLayerTest.java | 2 +- .../mapboxsdk/testapp/style/SymbolLayerTest.java | 2 +- .../com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs | 4 ++-- platform/android/scripts/generate-style-code.js | 18 ++++++++---------- 11 files changed, 19 insertions(+), 21 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java index 2d16291832..2a8ac36507 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java @@ -160,4 +160,4 @@ public class BackgroundLayerTest extends BaseActivityTest { assertEquals((Float) layer.getBackgroundOpacity().getValue(), (Float) 0.3f); }); } -} \ No newline at end of file +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java index a851fde6dd..101d22a531 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java @@ -518,4 +518,4 @@ public class CircleLayerTest extends BaseActivityTest { }); } -} \ No newline at end of file +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java index f22956072d..84b3e7bd68 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java @@ -354,4 +354,4 @@ public class FillExtrusionLayerTest extends BaseActivityTest { }); } -} \ No newline at end of file +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java index bdbd8958d2..3e1cbf666d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java @@ -353,4 +353,4 @@ public class FillLayerTest extends BaseActivityTest { assertEquals((String) layer.getFillPattern().getValue(), (String) "pedestrian-polygon"); }); } -} \ No newline at end of file +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java index 549f309e4f..3a81786df4 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java @@ -237,4 +237,4 @@ public class HeatmapLayerTest extends BaseActivityTest { assertEquals((Float) layer.getHeatmapOpacity().getValue(), (Float) 0.3f); }); } -} \ No newline at end of file +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java index 1fdc6d6dab..e0121a704a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java @@ -252,4 +252,4 @@ public class HillshadeLayerTest extends BaseActivityTest { assertEquals(layer.getHillshadeAccentColorAsInt(), Color.RED); }); } -} \ No newline at end of file +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java index 40cf0f2927..e35f0edcc4 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java @@ -545,4 +545,4 @@ public class LineLayerTest extends BaseActivityTest { assertEquals((String) layer.getLinePattern().getValue(), (String) "pedestrian-polygon"); }); } -} \ No newline at end of file +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java index 0410d09369..6e5afdb479 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java @@ -254,4 +254,4 @@ public class RasterLayerTest extends BaseActivityTest { assertEquals((Float) layer.getRasterFadeDuration().getValue(), (Float) 0.3f); }); } -} \ No newline at end of file +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java index 62f73b1507..fe38fef253 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java @@ -1392,4 +1392,4 @@ public class SymbolLayerTest extends BaseActivityTest { assertEquals((String) layer.getTextTranslateAnchor().getValue(), (String) TEXT_TRANSLATE_ANCHOR_MAP); }); } -} \ No newline at end of file +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs index 935813899f..575f64e809 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs @@ -150,7 +150,7 @@ public class <%- camelize(type) %>LayerTest extends BaseActivityTest { assertEquals((<%- propertyType(property) %>) layer.get<%- camelize(property.name) %>().getValue(), (<%- propertyType(property) %>) <%- defaultValueJava(property) %>); }); } -<% if (isDataDriven(property)) { -%> +<% if (property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven') { -%> <% if (!(property.name.endsWith("-font")||property.name.endsWith("-offset"))) { -%> @Test @@ -188,4 +188,4 @@ public class <%- camelize(type) %>LayerTest extends BaseActivityTest { <% } -%> <% } -%> <% } -%> -} \ No newline at end of file +} diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js index 3b0363cc19..05ca957974 100755 --- a/platform/android/scripts/generate-style-code.js +++ b/platform/android/scripts/generate-style-code.js @@ -267,19 +267,17 @@ global.propertyValueDoc = function (property, value) { return doc; }; -global.isDataDriven = function (property) { - return property['property-function'] === true; -}; - global.isLightProperty = function (property) { return property['light-property'] === true; }; global.propertyValueType = function (property) { - if (isDataDriven(property)) { - return `DataDrivenPropertyValue<${evaluatedType(property)}>`; - } else { - return `PropertyValue<${evaluatedType(property)}>`; + switch (property['property-type']) { + case 'data-driven': + case 'cross-faded-data-driven': + return `DataDrivenPropertyValue<${evaluatedType(property)}>`; + default: + return `PropertyValue<${evaluatedType(property)}>`; } }; @@ -318,11 +316,11 @@ global.evaluatedType = function (property) { }; global.supportsZoomFunction = function (property) { - return property['zoom-function'] === true; + return property.expression && property.expression.parameters.indexOf('zoom') > -1; }; global.supportsPropertyFunction = function (property) { - return property['property-function'] === true; + return property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven'; }; // Template processing // -- cgit v1.2.1 From 4b1530ff422d9ba77ddb9ef34d64c2e04f356380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Mon, 14 May 2018 12:18:13 -0700 Subject: =?UTF-8?q?[core]=20Convert=20null=20to=20empty=20string,=20not=20?= =?UTF-8?q?=E2=80=9Cnull=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- platform/android/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 384dcdf883..6da01aacf3 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 6.1.2 + - `"to-string"` expression operator converts `null` to empty string rather than to `"null"` [#11904](https://github.com/mapbox/mapbox-gl-native/pull/11904) + ## 6.1.1 - May 7, 2018 - Update telemetry to 3.1.0 [#11855](https://github.com/mapbox/mapbox-gl-native/pull/11855) -- cgit v1.2.1 From 5af104bfa5bd7ebd55b05843a2d77d1df06ec93f Mon Sep 17 00:00:00 2001 From: Osana Babayan <32496536+osana@users.noreply.github.com> Date: Wed, 16 May 2018 08:18:21 -0400 Subject: bumped mapbox-java to 3.1.0 (#11916) --- platform/android/gradle/dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index 07a9938915..d50f6cef08 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -8,7 +8,7 @@ ext { ] versions = [ - mapboxServices : '3.0.1', + mapboxServices : '3.1.0', mapboxTelemetry: '3.1.0', mapboxGestures : '0.2.0', supportLib : '25.4.0', -- cgit v1.2.1 From 4f2002b856346a2de4673b94a140c9b2677cefae Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 16 May 2018 16:24:18 +0200 Subject: [android] - expose MapView#setOfflineRegionDefinition --- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 39 +++++++++++++++++++--- .../activity/offline/UpdateMetadataActivity.java | 30 +++++++++++++++-- .../main/res/layout/activity_metadata_update.xml | 1 + 3 files changed, 64 insertions(+), 6 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 4ecd7c9246..452f6a615d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -23,7 +23,6 @@ import android.view.ViewTreeObserver; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ZoomButtonsController; - import com.mapbox.android.gestures.AndroidGesturesManager; import com.mapbox.android.telemetry.AppUserTurnstile; import com.mapbox.android.telemetry.Event; @@ -33,6 +32,8 @@ import com.mapbox.mapboxsdk.BuildConfig; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.MarkerViewManager; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; @@ -40,9 +41,13 @@ import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.GLSurfaceViewMapRenderer import com.mapbox.mapboxsdk.maps.renderer.textureview.TextureViewMapRenderer; import com.mapbox.mapboxsdk.maps.widgets.CompassView; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; +import com.mapbox.mapboxsdk.offline.OfflineRegionDefinition; +import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition; import com.mapbox.mapboxsdk.storage.FileSource; import com.mapbox.mapboxsdk.utils.BitmapUtils; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; @@ -51,9 +56,6 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; - import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION; import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE; @@ -535,6 +537,35 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { nativeMapView.setStyleUrl(url); } + /** + * Loads a new style from the specified offline region definition and moves the map camera to that region. + * + * @param definition the offline region definition + * @see OfflineRegionDefinition + */ + public void setOfflineRegionDefinition(OfflineRegionDefinition definition) { + if (destroyed) { + return; + } + + OfflineTilePyramidRegionDefinition regionDefinition = (OfflineTilePyramidRegionDefinition) definition; + setStyleUrl(regionDefinition.getStyleURL()); + CameraPosition cameraPosition = new CameraPosition.Builder() + .target(regionDefinition.getBounds().getCenter()) + .zoom(regionDefinition.getMinZoom()) + .build(); + + if (!isMapInitialized()) { + mapboxMapOptions.camera(cameraPosition); + mapboxMapOptions.minZoomPreference(regionDefinition.getMinZoom()); + mapboxMapOptions.maxZoomPreference(regionDefinition.getMaxZoom()); + return; + } + mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); + mapboxMap.setMinZoomPreference(regionDefinition.getMinZoom()); + mapboxMap.setMaxZoomPreference(regionDefinition.getMaxZoom()); + } + // // Rendering // diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java index c5ad467673..e1a524790d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java @@ -14,7 +14,7 @@ import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; - +import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.offline.OfflineManager; import com.mapbox.mapboxsdk.offline.OfflineRegion; import com.mapbox.mapboxsdk.testapp.R; @@ -27,10 +27,13 @@ import java.util.List; /** * Test activity showing integration of updating metadata of an OfflineRegion. */ -public class UpdateMetadataActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { +public class UpdateMetadataActivity extends AppCompatActivity implements AdapterView.OnItemClickListener, + AdapterView.OnItemLongClickListener { private OfflineRegionMetadataAdapter adapter; + private MapView mapView; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -40,6 +43,7 @@ public class UpdateMetadataActivity extends AppCompatActivity implements Adapter listView.setAdapter(adapter = new OfflineRegionMetadataAdapter(this)); listView.setEmptyView(findViewById(android.R.id.empty)); listView.setOnItemClickListener(this); + listView.setOnItemLongClickListener(this); } @Override @@ -64,6 +68,18 @@ public class UpdateMetadataActivity extends AppCompatActivity implements Adapter builder.show(); } + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + ViewGroup container = (ViewGroup) findViewById(R.id.container); + container.removeAllViews(); + container.addView(mapView = new MapView(view.getContext())); + mapView.setOfflineRegionDefinition(adapter.getItem(position).getDefinition()); + mapView.onCreate(null); + mapView.onStart(); + mapView.onResume(); + return true; + } + private void updateMetadata(OfflineRegion region, byte[] metadata) { region.updateMetadata(metadata, new OfflineRegion.OfflineRegionUpdateMetadataCallback() { @Override @@ -104,6 +120,16 @@ public class UpdateMetadataActivity extends AppCompatActivity implements Adapter }); } + @Override + protected void onDestroy() { + super.onDestroy(); + if (mapView != null) { + mapView.onPause(); + mapView.onStop(); + mapView.onDestroy(); + } + } + private static class OfflineRegionMetadataAdapter extends BaseAdapter { private Context context; diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml index 1eb999caf5..501bc55743 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml @@ -1,5 +1,6 @@ Date: Wed, 16 May 2018 17:37:04 +0200 Subject: [android] - add nullability annotations to public api for kotlin language integration --- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 18 ++-- .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 103 ++++++++++++--------- .../java/com/mapbox/mapboxsdk/maps/Projection.java | 13 ++- .../java/com/mapbox/mapboxsdk/maps/UiSettings.java | 6 +- 4 files changed, 81 insertions(+), 59 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 452f6a615d..23fb3c22dd 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -629,10 +629,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { * @param listener The callback that's invoked on every frame rendered to the map view. * @see MapView#removeOnMapChangedListener(OnMapChangedListener) */ - public void addOnMapChangedListener(@Nullable OnMapChangedListener listener) { - if (listener != null) { - onMapChangedListeners.add(listener); - } + public void addOnMapChangedListener(@NonNull OnMapChangedListener listener) { + onMapChangedListeners.add(listener); } /** @@ -641,8 +639,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { * @param listener The previously added callback to remove. * @see MapView#addOnMapChangedListener(OnMapChangedListener) */ - public void removeOnMapChangedListener(@Nullable OnMapChangedListener listener) { - if (listener != null && onMapChangedListeners.contains(listener)) { + public void removeOnMapChangedListener(@NonNull OnMapChangedListener listener) { + if (onMapChangedListeners.contains(listener)) { onMapChangedListeners.remove(listener); } } @@ -653,13 +651,11 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { * @param callback The callback object that will be triggered when the map is ready to be used. */ @UiThread - public void getMapAsync(final OnMapReadyCallback callback) { - if (!mapCallback.isInitialLoad() && callback != null) { + public void getMapAsync(final @NonNull OnMapReadyCallback callback) { + if (!mapCallback.isInitialLoad()) { callback.onMapReady(mapboxMap); } else { - if (callback != null) { - mapCallback.addOnMapReadyCallback(callback); - } + mapCallback.addOnMapReadyCallback(callback); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index cfa7143671..aed918cb79 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -120,7 +120,7 @@ public final class MapboxMap { * * @param outState the bundle to save the state to. */ - void onSaveInstanceState(Bundle outState) { + void onSaveInstanceState(@NonNull Bundle outState) { outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, transform.getCameraPosition()); outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, nativeMapView.getDebug()); outState.putString(MapboxConstants.STATE_STYLE_URL, nativeMapView.getStyleUrl()); @@ -132,7 +132,7 @@ public final class MapboxMap { * * @param savedInstanceState the bundle containing the saved state */ - void onRestoreInstanceState(Bundle savedInstanceState) { + void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { final CameraPosition cameraPosition = savedInstanceState.getParcelable(MapboxConstants.STATE_CAMERA_POSITION); uiSettings.onRestoreInstanceState(savedInstanceState); @@ -266,6 +266,7 @@ public final class MapboxMap { * * @return all the layers in the current style */ + @NonNull public List getLayers() { return nativeMapView.getLayers(); } @@ -377,6 +378,7 @@ public final class MapboxMap { * * @return all the sources in the current style */ + @NonNull public List getSources() { return nativeMapView.getSources(); } @@ -463,10 +465,11 @@ public final class MapboxMap { * * @param name the name of the image to remove */ - public void removeImage(String name) { + public void removeImage(@NonNull String name) { nativeMapView.removeImage(name); } + @Nullable public Bitmap getImage(@NonNull String name) { return nativeMapView.getImage(name); } @@ -537,6 +540,7 @@ public final class MapboxMap { * * @return the UiSettings associated with this map */ + @NonNull public UiSettings getUiSettings() { return uiSettings; } @@ -551,6 +555,7 @@ public final class MapboxMap { * * @return the Projection associated with this map */ + @NonNull public Projection getProjection() { return projection; } @@ -564,7 +569,7 @@ public final class MapboxMap { * * @return the global light source */ - @Nullable + @NonNull public Light getLight() { return nativeMapView.getLight(); } @@ -590,6 +595,7 @@ public final class MapboxMap { * * @return The current position of the Camera. */ + @NonNull public final CameraPosition getCameraPosition() { return transform.getCameraPosition(); } @@ -612,7 +618,7 @@ public final class MapboxMap { * * @param update The change that should be applied to the camera. */ - public final void moveCamera(CameraUpdate update) { + public final void moveCamera(@NonNull CameraUpdate update) { moveCamera(update, null); } @@ -624,7 +630,8 @@ public final class MapboxMap { * @param update The change that should be applied to the camera * @param callback the callback to be invoked when an animation finishes or is canceled */ - public final void moveCamera(final CameraUpdate update, final MapboxMap.CancelableCallback callback) { + public final void moveCamera(@NonNull final CameraUpdate update, + @Nullable final MapboxMap.CancelableCallback callback) { transform.moveCamera(MapboxMap.this, update, callback); } @@ -650,7 +657,7 @@ public final class MapboxMap { * positive, otherwise an IllegalArgumentException will be thrown. * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - public final void easeCamera(CameraUpdate update, int durationMs) { + public final void easeCamera(@NonNull CameraUpdate update, int durationMs) { easeCamera(update, durationMs, null); } @@ -673,7 +680,8 @@ public final class MapboxMap { * Do not update or ease the camera from within onCancel(). * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - public final void easeCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) { + public final void easeCamera(@NonNull CameraUpdate update, int durationMs, + @Nullable final MapboxMap.CancelableCallback callback) { easeCamera(update, durationMs, true, callback); } @@ -691,7 +699,7 @@ public final class MapboxMap { * positive, otherwise an IllegalArgumentException will be thrown. * @param easingInterpolator True for easing interpolator, false for linear. */ - public final void easeCamera(CameraUpdate update, int durationMs, boolean easingInterpolator) { + public final void easeCamera(@NonNull CameraUpdate update, int durationMs, boolean easingInterpolator) { easeCamera(update, durationMs, easingInterpolator, null); } @@ -711,8 +719,10 @@ public final class MapboxMap { * by a later camera movement or a user gesture, onCancel() will be called. * Do not update or ease the camera from within onCancel(). */ - public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator, - final MapboxMap.CancelableCallback callback) { + public final void easeCamera(@NonNull final CameraUpdate update, + final int durationMs, + final boolean easingInterpolator, + @Nullable final MapboxMap.CancelableCallback callback) { easeCamera(update, durationMs, easingInterpolator, callback, false); } @@ -733,8 +743,9 @@ public final class MapboxMap { * Do not update or ease the camera from within onCancel(). * @param isDismissable true will allow animated camera changes dismiss a tracking mode. */ - public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator, - final MapboxMap.CancelableCallback callback, final boolean isDismissable) { + public final void easeCamera(@NonNull final CameraUpdate update, final int durationMs, + final boolean easingInterpolator, @Nullable final MapboxMap.CancelableCallback callback, + final boolean isDismissable) { if (durationMs <= 0) { throw new IllegalArgumentException("Null duration passed into easeCamera"); @@ -751,7 +762,7 @@ public final class MapboxMap { * @param update The change that should be applied to the camera. * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - public final void animateCamera(CameraUpdate update) { + public final void animateCamera(@NonNull CameraUpdate update) { animateCamera(update, MapboxConstants.ANIMATION_DURATION, null); } @@ -767,7 +778,7 @@ public final class MapboxMap { * called. Do not update or animate the camera from within onCancel(). * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - public final void animateCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) { + public final void animateCamera(@NonNull CameraUpdate update, @Nullable MapboxMap.CancelableCallback callback) { animateCamera(update, MapboxConstants.ANIMATION_DURATION, callback); } @@ -782,7 +793,7 @@ public final class MapboxMap { * positive, otherwise an IllegalArgumentException will be thrown. * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - public final void animateCamera(CameraUpdate update, int durationMs) { + public final void animateCamera(@NonNull CameraUpdate update, int durationMs) { animateCamera(update, durationMs, null); } @@ -804,8 +815,8 @@ public final class MapboxMap { * isn't required, leave it as null. * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - public final void animateCamera(final CameraUpdate update, final int durationMs, - final MapboxMap.CancelableCallback callback) { + public final void animateCamera(@NonNull final CameraUpdate update, final int durationMs, + @Nullable final MapboxMap.CancelableCallback callback) { if (durationMs <= 0) { throw new IllegalArgumentException("Null duration passed into animageCamera"); } @@ -1069,6 +1080,7 @@ public final class MapboxMap { * * @return The json of the map style */ + @NonNull public String getStyleJson() { return nativeMapView.getStyleJson(); } @@ -1232,7 +1244,7 @@ public final class MapboxMap { * * @param polyline An updated polyline object. */ - public void updatePolyline(Polyline polyline) { + public void updatePolyline(@NonNull Polyline polyline) { annotationManager.updatePolyline(polyline); } @@ -1263,7 +1275,7 @@ public final class MapboxMap { * * @param polygon An updated polygon object */ - public void updatePolygon(Polygon polygon) { + public void updatePolygon(@NonNull Polygon polygon) { annotationManager.updatePolygon(polygon); } @@ -1468,6 +1480,7 @@ public final class MapboxMap { * * @return The currently selected marker. */ + @NonNull public List getSelectedMarkers() { return annotationManager.getSelectedMarkers(); } @@ -1477,6 +1490,7 @@ public final class MapboxMap { * * @return the associated MarkerViewManager */ + @NonNull public MarkerViewManager getMarkerViewManager() { return annotationManager.getMarkerViewManager(); } @@ -1550,6 +1564,7 @@ public final class MapboxMap { * @param padding the padding to apply to the bounds * @return the camera position that fits the bounds and padding */ + @NonNull public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, int[] padding) { // get padded camera position from LatLngBounds return nativeMapView.getCameraForLatLngBounds(latLngBounds, padding); @@ -1563,6 +1578,7 @@ public final class MapboxMap { * @param padding the padding to apply to the bounds * @return the camera position that fits the bounds and padding */ + @NonNull public CameraPosition getCameraForGeometry(Geometry geometry, double bearing, int[] padding) { // get padded camera position from Geometry return nativeMapView.getCameraForGeometry(geometry, bearing, padding); @@ -1591,11 +1607,7 @@ public final class MapboxMap { * @param bottom The bottom margin in pixels. */ public void setPadding(int left, int top, int right, int bottom) { - setPadding(new int[] {left, top, right, bottom}); - } - - private void setPadding(int[] padding) { - projection.setContentPadding(padding); + projection.setContentPadding(new int[] {left, top, right, bottom}); uiSettings.invalidate(); } @@ -1604,6 +1616,7 @@ public final class MapboxMap { * * @return An array with length 4 in the LTRB order. */ + @NonNull public int[] getPadding() { return projection.getContentPadding(); } @@ -1755,6 +1768,7 @@ public final class MapboxMap { } // used by MapView + @Nullable OnFpsChangedListener getOnFpsChangedListener() { return onFpsChangedListener; } @@ -1902,7 +1916,7 @@ public final class MapboxMap { * will be added to the passed gestures manager. * @see mapbox-gestures-android library */ - public void setGesturesManager(AndroidGesturesManager androidGesturesManager, boolean attachDefaultListeners, + public void setGesturesManager(@NonNull AndroidGesturesManager androidGesturesManager, boolean attachDefaultListeners, boolean setDefaultMutuallyExclusives) { onGesturesManagerInteractionListener.setGesturesManager( androidGesturesManager, attachDefaultListeners, setDefaultMutuallyExclusives); @@ -1914,6 +1928,7 @@ public final class MapboxMap { * * @return Current gestures manager. */ + @NonNull public AndroidGesturesManager getGesturesManager() { return onGesturesManagerInteractionListener.getGesturesManager(); } @@ -2000,6 +2015,7 @@ public final class MapboxMap { * * @return Current active InfoWindow Click Listener */ + @Nullable public OnInfoWindowClickListener getOnInfoWindowClickListener() { return annotationManager.getInfoWindowManager().getOnInfoWindowClickListener(); } @@ -2020,6 +2036,7 @@ public final class MapboxMap { * * @return Current active InfoWindow long Click Listener */ + @Nullable public OnInfoWindowLongClickListener getOnInfoWindowLongClickListener() { return annotationManager.getInfoWindowManager().getOnInfoWindowLongClickListener(); } @@ -2038,6 +2055,7 @@ public final class MapboxMap { * * @return Current active InfoWindow Close Listener */ + @Nullable public OnInfoWindowCloseListener getOnInfoWindowCloseListener() { return annotationManager.getInfoWindowManager().getOnInfoWindowCloseListener(); } @@ -2147,11 +2165,11 @@ public final class MapboxMap { * @see MapboxMap#addOnMoveListener(OnMoveListener) */ public interface OnMoveListener { - void onMoveBegin(MoveGestureDetector detector); + void onMoveBegin(@NonNull MoveGestureDetector detector); - void onMove(MoveGestureDetector detector); + void onMove(@NonNull MoveGestureDetector detector); - void onMoveEnd(MoveGestureDetector detector); + void onMoveEnd(@NonNull MoveGestureDetector detector); } /** @@ -2160,11 +2178,11 @@ public final class MapboxMap { * @see MapboxMap#addOnRotateListener(OnRotateListener) */ public interface OnRotateListener { - void onRotateBegin(RotateGestureDetector detector); + void onRotateBegin(@NonNull RotateGestureDetector detector); - void onRotate(RotateGestureDetector detector); + void onRotate(@NonNull RotateGestureDetector detector); - void onRotateEnd(RotateGestureDetector detector); + void onRotateEnd(@NonNull RotateGestureDetector detector); } /** @@ -2173,11 +2191,11 @@ public final class MapboxMap { * @see MapboxMap#addOnScaleListener(OnScaleListener) */ public interface OnScaleListener { - void onScaleBegin(StandardScaleGestureDetector detector); + void onScaleBegin(@NonNull StandardScaleGestureDetector detector); - void onScale(StandardScaleGestureDetector detector); + void onScale(@NonNull StandardScaleGestureDetector detector); - void onScaleEnd(StandardScaleGestureDetector detector); + void onScaleEnd(@NonNull StandardScaleGestureDetector detector); } /** @@ -2186,11 +2204,11 @@ public final class MapboxMap { * @see MapboxMap#addOnShoveListener(OnShoveListener) */ public interface OnShoveListener { - void onShoveBegin(ShoveGestureDetector detector); + void onShoveBegin(@NonNull ShoveGestureDetector detector); - void onShove(ShoveGestureDetector detector); + void onShove(@NonNull ShoveGestureDetector detector); - void onShoveEnd(ShoveGestureDetector detector); + void onShoveEnd(@NonNull ShoveGestureDetector detector); } /** @@ -2442,7 +2460,7 @@ public final class MapboxMap { * * @param marker The marker were the info window is attached to */ - void onInfoWindowLongClick(Marker marker); + void onInfoWindowLongClick(@NonNull Marker marker); } /** @@ -2457,7 +2475,7 @@ public final class MapboxMap { * * @param marker The marker of the info window that was closed. */ - void onInfoWindowClose(Marker marker); + void onInfoWindowClose(@NonNull Marker marker); } /** @@ -2637,7 +2655,7 @@ public final class MapboxMap { * * @param snapshot the snapshot bitmap */ - void onSnapshotReady(Bitmap snapshot); + void onSnapshotReady(@NonNull Bitmap snapshot); } /** @@ -2649,12 +2667,13 @@ public final class MapboxMap { * * @param style the style that has been loaded */ - void onStyleLoaded(String style); + void onStyleLoaded(@NonNull String style); } // // Used for instrumentation testing // + @NonNull Transform getTransform() { return transform; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java index f35355533d..d5166c17b0 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java @@ -43,14 +43,16 @@ public class Projection { /** * Returns the spherical Mercator projected meters for a LatLng. */ - public ProjectedMeters getProjectedMetersForLatLng(LatLng latLng) { + @NonNull + public ProjectedMeters getProjectedMetersForLatLng(@NonNull LatLng latLng) { return nativeMapView.projectedMetersForLatLng(latLng); } /** * Returns the LatLng for a spherical Mercator projected meters. */ - public LatLng getLatLngForProjectedMeters(ProjectedMeters projectedMeters) { + @NonNull + public LatLng getLatLngForProjectedMeters(@NonNull ProjectedMeters projectedMeters) { return nativeMapView.latLngForProjectedMeters(projectedMeters); } @@ -77,7 +79,8 @@ public class Projection { * @return The LatLng corresponding to the point on the screen, or null if the ray through * the given screen point does not intersect the ground plane. */ - public LatLng fromScreenLocation(PointF point) { + @NonNull + public LatLng fromScreenLocation(@NonNull PointF point) { return nativeMapView.latLngForPixel(point); } @@ -87,6 +90,7 @@ public class Projection { * * @return The projection of the viewing frustum in its current state. */ + @NonNull public VisibleRegion getVisibleRegion() { float left = 0; float right = nativeMapView.getWidth(); @@ -151,7 +155,8 @@ public class Projection { * @param location A LatLng on the map to convert to a screen location. * @return A Point representing the screen location in screen pixels. */ - public PointF toScreenLocation(LatLng location) { + @NonNull + public PointF toScreenLocation(@NonNull LatLng location) { return nativeMapView.pixelForLatLng(location); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index c1daebbe52..100787fbf0 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -332,7 +332,7 @@ public final class UiSettings { * * @param compass the drawable to show as image compass */ - public void setCompassImage(Drawable compass) { + public void setCompassImage(@NonNull Drawable compass) { compassView.setCompassImage(compass); } @@ -409,6 +409,7 @@ public final class UiSettings { * * @return the drawable used as compass image */ + @NonNull public Drawable getCompassImage() { return compassView.getCompassImage(); } @@ -544,7 +545,7 @@ public final class UiSettings { * * @param attributionDialogManager the manager class used for showing attribution */ - public void setAttributionDialogManager(AttributionDialogManager attributionDialogManager) { + public void setAttributionDialogManager(@NonNull AttributionDialogManager attributionDialogManager) { this.attributionDialogManager = attributionDialogManager; } @@ -553,6 +554,7 @@ public final class UiSettings { * * @return the active manager class used for showing attribution */ + @NonNull public AttributionDialogManager getAttributionDialogManager() { return attributionDialogManager; } -- cgit v1.2.1 From 4ceb687f6c7bdb4cd768310eeae558d826dcf506 Mon Sep 17 00:00:00 2001 From: tobrun Date: Thu, 17 May 2018 18:26:28 +0200 Subject: [android] - expose MapView created callbacks on MapFragment and MapSupportFragment --- .../com/mapbox/mapboxsdk/maps/MapFragment.java | 44 +++++++++++- .../mapbox/mapboxsdk/maps/SupportMapFragment.java | 19 +++++ .../activity/fragment/MapFragmentActivity.java | 79 +++++++++++++-------- .../fragment/SupportMapFragmentActivity.java | 82 ++++++++++++++-------- 4 files changed, 160 insertions(+), 64 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java index 5fcf206a5a..280877d61a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java @@ -8,7 +8,6 @@ import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - import com.mapbox.mapboxsdk.utils.MapFragmentUtils; import java.util.ArrayList; @@ -31,6 +30,7 @@ import java.util.List; public final class MapFragment extends Fragment implements OnMapReadyCallback { private final List mapReadyCallbackList = new ArrayList<>(); + private OnMapViewReadyCallback mapViewReadyCallback; private MapboxMap mapboxMap; private MapView map; @@ -55,6 +55,19 @@ public final class MapFragment extends Fragment implements OnMapReadyCallback { return mapFragment; } + /** + * Called when the context attaches to this fragment. + * + * @param context the context attaching + */ + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof OnMapViewReadyCallback) { + mapViewReadyCallback = (OnMapViewReadyCallback) context; + } + } + /** * Creates the fragment view hierarchy. * @@ -75,15 +88,25 @@ public final class MapFragment extends Fragment implements OnMapReadyCallback { * Called when the fragment view hierarchy is created. * * @param view The content view of the fragment - * @param savedInstanceState THe saved instance state of the framgnt + * @param savedInstanceState The saved instance state of the fragment */ @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); map.onCreate(savedInstanceState); map.getMapAsync(this); + + // notify listeners about mapview creation + if (mapViewReadyCallback != null) { + mapViewReadyCallback.onMapViewReady(map); + } } + /** + * Called when the style of the map has successfully loaded. + * + * @param mapboxMap The public api controller of the map + */ @Override public void onMapReady(MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; @@ -170,4 +193,21 @@ public final class MapFragment extends Fragment implements OnMapReadyCallback { onMapReadyCallback.onMapReady(mapboxMap); } } + + /** + * Callback to be invoked when the map fragment has inflated its MapView. + *

+ * To use this interface the context hosting the fragment must implement this interface. + * That instance will be set as part of Fragment#onAttach(Context context). + *

+ */ + public interface OnMapViewReadyCallback { + + /** + * Called when the map has been created. + * + * @param mapView The created mapview + */ + void onMapViewReady(MapView mapView); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java index 8aa4c7fd09..307b33b0c7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java @@ -31,6 +31,7 @@ import java.util.List; public class SupportMapFragment extends Fragment implements OnMapReadyCallback { private final List mapReadyCallbackList = new ArrayList<>(); + private MapFragment.OnMapViewReadyCallback mapViewReadyCallback; private MapboxMap mapboxMap; private MapView map; @@ -55,6 +56,19 @@ public class SupportMapFragment extends Fragment implements OnMapReadyCallback { return mapFragment; } + /** + * Called when the context attaches to this fragment. + * + * @param context the context attaching + */ + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof MapFragment.OnMapViewReadyCallback) { + mapViewReadyCallback = (MapFragment.OnMapViewReadyCallback) context; + } + } + /** * Creates the fragment view hierarchy. * @@ -82,6 +96,11 @@ public class SupportMapFragment extends Fragment implements OnMapReadyCallback { super.onViewCreated(view, savedInstanceState); map.onCreate(savedInstanceState); map.getMapAsync(this); + + // notify listeners about MapView creation + if (mapViewReadyCallback != null) { + mapViewReadyCallback.onMapViewReady(map); + } } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java index 930626078d..f5e0371aad 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java @@ -1,14 +1,13 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment; -import android.app.FragmentTransaction; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; - import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapFragment; +import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.MapboxMapOptions; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; @@ -20,53 +19,71 @@ import com.mapbox.mapboxsdk.testapp.R; * Uses MapboxMapOptions to initialise the Fragment. *

*/ -public class MapFragmentActivity extends AppCompatActivity implements OnMapReadyCallback { +public class MapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback, + OnMapReadyCallback, MapView.OnMapChangedListener { private MapboxMap mapboxMap; + private MapView mapView; + private boolean initialCameraAnimation = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map_fragment); - - MapFragment mapFragment; if (savedInstanceState == null) { - final FragmentTransaction transaction = getFragmentManager().beginTransaction(); + MapFragment mapFragment = MapFragment.newInstance(createFragmentOptions()); + getFragmentManager() + .beginTransaction() + .add(R.id.fragment_container,mapFragment, "com.mapbox.map") + .commit(); + mapFragment.getMapAsync(this); + } + } - MapboxMapOptions options = new MapboxMapOptions(); - options.styleUrl(Style.OUTDOORS); + private MapboxMapOptions createFragmentOptions() { + MapboxMapOptions options = new MapboxMapOptions(); + options.styleUrl(Style.OUTDOORS); - options.scrollGesturesEnabled(false); - options.zoomGesturesEnabled(false); - options.tiltGesturesEnabled(false); - options.rotateGesturesEnabled(false); + options.scrollGesturesEnabled(false); + options.zoomGesturesEnabled(false); + options.tiltGesturesEnabled(false); + options.rotateGesturesEnabled(false); + options.debugActive(false); - options.debugActive(false); + LatLng dc = new LatLng(38.90252, -77.02291); - LatLng dc = new LatLng(38.90252, -77.02291); + options.minZoomPreference(9); + options.maxZoomPreference(11); + options.camera(new CameraPosition.Builder() + .target(dc) + .zoom(11) + .build()); + return options; + } - options.minZoomPreference(9); - options.maxZoomPreference(11); - options.camera(new CameraPosition.Builder() - .target(dc) - .zoom(11) - .build()); + @Override + public void onMapViewReady(MapView map) { + mapView = map; + mapView.addOnMapChangedListener(this); + } - mapFragment = MapFragment.newInstance(options); + @Override + public void onMapReady(MapboxMap map) { + mapboxMap = map; + } - transaction.add(R.id.fragment_container, mapFragment, "com.mapbox.map"); - transaction.commit(); - } else { - mapFragment = (MapFragment) getFragmentManager().findFragmentByTag("com.mapbox.map"); + @Override + public void onMapChanged(int change) { + if (initialCameraAnimation && change == MapView.DID_FINISH_RENDERING_MAP_FULLY_RENDERED) { + mapboxMap.animateCamera( + CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 5000); + initialCameraAnimation = false; } - - mapFragment.getMapAsync(this); } @Override - public void onMapReady(MapboxMap map) { - mapboxMap = map; - mapboxMap.animateCamera( - CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 10000); + protected void onDestroy() { + super.onDestroy(); + mapView.removeOnMapChangedListener(this); } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java index 4f828060ee..f494a9231e 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java @@ -1,13 +1,13 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment; import android.os.Bundle; -import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; - import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.MapFragment; +import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.MapboxMapOptions; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; @@ -20,51 +20,71 @@ import com.mapbox.mapboxsdk.testapp.R; * Uses MapboxMapOptions to initialise the Fragment. *

*/ -public class SupportMapFragmentActivity extends AppCompatActivity implements OnMapReadyCallback { +public class SupportMapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback, + OnMapReadyCallback, MapView.OnMapChangedListener { private MapboxMap mapboxMap; + private MapView mapView; + private boolean initialCameraAnimation = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map_fragment); - - SupportMapFragment mapFragment; if (savedInstanceState == null) { - final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - - MapboxMapOptions options = new MapboxMapOptions(); - options.styleUrl(Style.SATELLITE_STREETS); - - options.debugActive(false); - options.compassEnabled(false); - options.attributionEnabled(false); - options.logoEnabled(false); + SupportMapFragment mapFragment = SupportMapFragment.newInstance(createFragmentOptions()); + getSupportFragmentManager() + .beginTransaction() + .add(R.id.fragment_container, mapFragment, "com.mapbox.map") + .commit(); + mapFragment.getMapAsync(this); + } + } - LatLng dc = new LatLng(38.90252, -77.02291); + private MapboxMapOptions createFragmentOptions() { + MapboxMapOptions options = new MapboxMapOptions(); + options.styleUrl(Style.MAPBOX_STREETS); - options.minZoomPreference(9); - options.maxZoomPreference(11); - options.camera(new CameraPosition.Builder() - .target(dc) - .zoom(11) - .build()); + options.scrollGesturesEnabled(false); + options.zoomGesturesEnabled(false); + options.tiltGesturesEnabled(false); + options.rotateGesturesEnabled(false); + options.debugActive(false); - mapFragment = SupportMapFragment.newInstance(options); + LatLng dc = new LatLng(38.90252, -77.02291); - transaction.add(R.id.fragment_container, mapFragment, "com.mapbox.map"); - transaction.commit(); - } else { - mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentByTag("com.mapbox.map"); - } + options.minZoomPreference(9); + options.maxZoomPreference(11); + options.camera(new CameraPosition.Builder() + .target(dc) + .zoom(11) + .build()); + return options; + } - mapFragment.getMapAsync(this); + @Override + public void onMapViewReady(MapView map) { + mapView = map; + mapView.addOnMapChangedListener(this); } @Override public void onMapReady(MapboxMap map) { mapboxMap = map; - mapboxMap.animateCamera( - CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 10000); } -} + + @Override + public void onMapChanged(int change) { + if (initialCameraAnimation && change == MapView.DID_FINISH_RENDERING_MAP_FULLY_RENDERED) { + mapboxMap.animateCamera( + CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 5000); + initialCameraAnimation = false; + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mapView.removeOnMapChangedListener(this); + } +} \ No newline at end of file -- cgit v1.2.1 From e1f89bf369dc9ef88ce19f737a01ff247830a46a Mon Sep 17 00:00:00 2001 From: tobrun Date: Thu, 17 May 2018 19:42:55 +0200 Subject: [android] - add changelog for 6.2.0-alpha.1 --- platform/android/CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index a25656012b..d96957a07b 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,8 +2,13 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## 6.1.2 +## 6.2.0-alpha.1 - May 17, 2018 + - `"to-string"` expression operator converts `null` to empty string rather than to `"null"` [#11904](https://github.com/mapbox/mapbox-gl-native/pull/11904) + - Expose MapView#setOfflineRegion [#1922](https://github.com/mapbox/mapbox-gl-native/pull/11922) + - Add nullability annotations to public API for kotlin language integration [#11925](https://github.com/mapbox/mapbox-gl-native/pull/11925) + - Expose MapView created callbacks on MapFragment and SupportMapFragment [#11934](https://github.com/mapbox/mapbox-gl-native/pull/11934) + - Update mapbox-java to 3.1.0 [#11916](https://github.com/mapbox/mapbox-gl-native/pull/11916) ## 6.1.1 - May 7, 2018 - Update telemetry to 3.1.0 [#11855](https://github.com/mapbox/mapbox-gl-native/pull/11855) -- cgit v1.2.1 From e70c73249bcb2a47f976b5b7a6592d84adbda7ae Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 18 May 2018 10:23:10 +0200 Subject: [android] - bump telemetry to v3.1.1 --- platform/android/CHANGELOG.md | 22 ++++++++++++---------- platform/android/gradle/dependencies.gradle | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index d96957a07b..7b8d2a82ef 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,8 +2,10 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## 6.2.0-alpha.1 - May 17, 2018 +## 6.1.2 - May 18, 2018 + - Update telemetry to 3.1.1 [#11942](https://github.com/mapbox/mapbox-gl-native/pull/11942) +## 6.2.0-alpha.1 - May 17, 2018 - `"to-string"` expression operator converts `null` to empty string rather than to `"null"` [#11904](https://github.com/mapbox/mapbox-gl-native/pull/11904) - Expose MapView#setOfflineRegion [#1922](https://github.com/mapbox/mapbox-gl-native/pull/11922) - Add nullability annotations to public API for kotlin language integration [#11925](https://github.com/mapbox/mapbox-gl-native/pull/11925) @@ -105,9 +107,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Update javadoc configuration for Gradle 4.4 [#11384](https://github.com/mapbox/mapbox-gl-native/pull/11384) - Rework zoomIn and zoomOut to use ValueAnimators [#11382](https://github.com/mapbox/mapbox-gl-native/pull/11382) - Delete LocalRef when converting Image.java [#11350](https://github.com/mapbox/mapbox-gl-native/pull/11350) - - Use float for pixelratio when creating a snapshotter [#11367](https://github.com/mapbox/mapbox-gl-native/pull/11367) + - Use float for pixelratio when creating a snapshotter [#11367](https://github.com/mapbox/mapbox-gl-native/pull/11367) - Validate width/height when creating a snapshot [#11364](https://github.com/mapbox/mapbox-gl-native/pull/11364) - + ## 6.0.0-beta.3 - March 2, 2018 - Added missing local reference deletes [#11243](https://github.com/mapbox/mapbox-gl-native/pull/11243), [#11272](https://github.com/mapbox/mapbox-gl-native/pull/11272) - Remove obsolete camera api [#11201](https://github.com/mapbox/mapbox-gl-native/pull/11201) @@ -130,7 +132,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Add missing DeleteLocalRefs [#11272](https://github.com/mapbox/mapbox-gl-native/pull/11272) - Continue loading style even if we mutate it [#11294](https://github.com/mapbox/mapbox-gl-native/pull/11294) - Update telemetry version for OkHttp [#11338](https://github.com/mapbox/mapbox-gl-native/pull/11338) - + ## 6.0.0-beta.2 - February 13, 2018 - Deprecate LocationEngine [#11185](https://github.com/mapbox/mapbox-gl-native/pull/11185) - Remove LOST from SDK [11186](https://github.com/mapbox/mapbox-gl-native/pull/11186) @@ -140,7 +142,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - AddImage performance improvement [#11111](https://github.com/mapbox/mapbox-gl-native/pull/11111) - Migrate MAS to 3.0.0, refactor GeoJson integration [#11149](https://github.com/mapbox/mapbox-gl-native/pull/11149) - Remove @jar and @aar dependency suffixes [#11161](https://github.com/mapbox/mapbox-gl-native/pull/11161) - + ## 5.4.1 - February 9, 2018 - Don't recreate TextureView surface as part of view resizing, solves OOM crashes [#11148](https://github.com/mapbox/mapbox-gl-native/pull/11148) - Don't invoke OnLowMemory before map is ready, solves startup crash on low memory devices [#11109](https://github.com/mapbox/mapbox-gl-native/pull/11109) @@ -175,7 +177,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Custom library loader [#10733](https://github.com/mapbox/mapbox-gl-native/pull/10733) - Inconsistent parameters for LatLngBounds.union [#10728](https://github.com/mapbox/mapbox-gl-native/pull/10728) - Gradle 4.1 / AS 3.0 [#10549](https://github.com/mapbox/mapbox-gl-native/pull/10549) - + ## 5.3.2 - January 22, 2018 - Validate surface creation before destroying [#10890](https://github.com/mapbox/mapbox-gl-native/pull/10890) - Add filesource activation ot OfflineRegion [#10904](https://github.com/mapbox/mapbox-gl-native/pull/10904) @@ -185,7 +187,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Allow changing the used OkHttpClient [#10948](https://github.com/mapbox/mapbox-gl-native/pull/10948) - Validate zoom level before creating telemetry event [#10959](https://github.com/mapbox/mapbox-gl-native/pull/10959) - Handle null call instances in HttpRequest [#10987](https://github.com/mapbox/mapbox-gl-native/pull/10987) - + ## 5.3.1 - January 10, 2018 - Blacklist binary program loading for Vivante GC4000 GPUs [#10862](https://github.com/mapbox/mapbox-gl-native/pull/10862) - Support Genymotion [#10841](https://github.com/mapbox/mapbox-gl-native/pull/10841) @@ -196,11 +198,11 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Allow configuring Http url logging when a request fails [#10830](https://github.com/mapbox/mapbox-gl-native/pull/10830) - Don't send double tap event multiple times for telemetry [#10854](https://github.com/mapbox/mapbox-gl-native/pull/10854) - Fix code generation [#10856](https://github.com/mapbox/mapbox-gl-native/pull/10856) - - Use the correct cancelable callback after posting cancel [#10871](https://github.com/mapbox/mapbox-gl-native/pull/10871) - + - Use the correct cancelable callback after posting cancel [#10871](https://github.com/mapbox/mapbox-gl-native/pull/10871) + ## 5.3.0 - December 20, 2017 - Add support for TinySDF [#10706](https://github.com/mapbox/mapbox-gl-native/pull/10706) - - Save restore MyLocationViewSettings [#10746](https://github.com/mapbox/mapbox-gl-native/pull/10746) + - Save restore MyLocationViewSettings [#10746](https://github.com/mapbox/mapbox-gl-native/pull/10746) - Post animation callback invocation [#10664](https://github.com/mapbox/mapbox-gl-native/pull/10664) - Allow configuring Http logging [#10681](https://github.com/mapbox/mapbox-gl-native/pull/10681) - Fix reverse scale gesture [#10688](https://github.com/mapbox/mapbox-gl-native/pull/10688) diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index d50f6cef08..b9744a61ef 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -9,7 +9,7 @@ ext { versions = [ mapboxServices : '3.1.0', - mapboxTelemetry: '3.1.0', + mapboxTelemetry: '3.1.1', mapboxGestures : '0.2.0', supportLib : '25.4.0', espresso : '3.0.1', -- cgit v1.2.1 From a84ac4c8d79952fa3031f5414b10a560fdef2e1d Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 18 May 2018 15:02:26 -0700 Subject: [core] Align URL token replacement behavior with GL JS I.e. preserve unknown tokens in URLs rather than replacing them with an empty string. --- platform/android/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) (limited to 'platform/android') diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 7b8d2a82ef..3fbfc32a76 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## master +- Unknown tokens in URLs are now preserved, rather than replaced with an empty string [#11787](https://github.com/mapbox/mapbox-gl-native/issues/11787) + ## 6.1.2 - May 18, 2018 - Update telemetry to 3.1.1 [#11942](https://github.com/mapbox/mapbox-gl-native/pull/11942) -- cgit v1.2.1 From cce72e2d36c5efe53bb026a0d98f835d16440ffa Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 22 May 2018 11:50:44 +0200 Subject: [android] - change MapView#initialize modifier to allow subclasses to override this method to provide alternate configurations to MapboxMapOptions --- .../src/main/java/com/mapbox/mapboxsdk/maps/MapView.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 23fb3c22dd..0f19965224 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -98,28 +98,30 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { @UiThread public MapView(@NonNull Context context) { super(context); - initialise(context, MapboxMapOptions.createFromAttributes(context, null)); + initialize(context, MapboxMapOptions.createFromAttributes(context, null)); } @UiThread public MapView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); - initialise(context, MapboxMapOptions.createFromAttributes(context, attrs)); + initialize(context, MapboxMapOptions.createFromAttributes(context, attrs)); } @UiThread public MapView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - initialise(context, MapboxMapOptions.createFromAttributes(context, attrs)); + initialize(context, MapboxMapOptions.createFromAttributes(context, attrs)); } @UiThread public MapView(@NonNull Context context, @Nullable MapboxMapOptions options) { super(context); - initialise(context, options == null ? MapboxMapOptions.createFromAttributes(context, null) : options); + initialize(context, options == null ? MapboxMapOptions.createFromAttributes(context, null) : options); } - private void initialise(@NonNull final Context context, @NonNull final MapboxMapOptions options) { + @CallSuper + @UiThread + protected void initialize(@NonNull final Context context, @NonNull final MapboxMapOptions options) { if (isInEditMode()) { // in IDE layout editor, just return return; -- cgit v1.2.1 From 60505b03174b5ec02ae723beafa7683f6ed54a62 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 15 Mar 2018 13:07:46 +0100 Subject: [android] - remove mips and armeabi as supported ABIs [android] - bump CI image to NDK 17 compatible [core] - remove setting edgeDistance to 0, comparison 'const short' > 32767 is always false [android] - remove throwing in desructor, undefined behaviour [android] - bump dependency versions of project --- platform/android/MapboxGLAndroidSDK/build.gradle | 12 ++++++++---- platform/android/build.gradle | 2 +- platform/android/config.cmake | 2 +- platform/android/gradle/dependencies.gradle | 22 ++++++++++------------ .../gradle/wrapper/gradle-wrapper.properties | 3 ++- platform/android/src/bitmap.cpp | 3 ++- platform/android/src/run_loop.cpp | 6 ++++-- 7 files changed, 28 insertions(+), 22 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index c43bc9112b..21ed25e2c2 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -1,9 +1,13 @@ apply plugin: 'com.android.library' dependencies { - api dependenciesList.mapboxAndroidTelemetry + api (dependenciesList.mapboxAndroidTelemetry) { + exclude group: 'com.android.support', module: 'appcompat-v7' + } api dependenciesList.mapboxJavaGeoJSON - api dependenciesList.mapboxAndroidGestures + api (dependenciesList.mapboxAndroidGestures) { + exclude group: 'com.android.support', module: 'appcompat-v7' + } implementation dependenciesList.supportAnnotations implementation dependenciesList.supportFragmentV4 implementation dependenciesList.timber @@ -87,7 +91,7 @@ android { if (abi != 'all') { abiFilters abi.split(' ') } else { - abiFilters "armeabi", "armeabi-v7a", "mips", "x86", "arm64-v8a", "x86_64" + abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" } } } @@ -111,7 +115,7 @@ android { } lintOptions { - disable 'MissingTranslation', 'TypographyQuotes', 'ObsoleteLintCustomCheck', 'MissingPermission' + disable 'MissingTranslation', 'TypographyQuotes', 'ObsoleteLintCustomCheck', 'MissingPermission', 'WrongThreadInterprocedural' checkAllWarnings true warningsAsErrors false } diff --git a/platform/android/build.gradle b/platform/android/build.gradle index 16238f41c1..45cddd9688 100644 --- a/platform/android/build.gradle +++ b/platform/android/build.gradle @@ -5,7 +5,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.2' } } diff --git a/platform/android/config.cmake b/platform/android/config.cmake index 77074dc82c..c25e48de05 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -10,7 +10,7 @@ set(CMAKE_C_ARCHIVE_APPEND " ruT ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections") -if ((ANDROID_ABI STREQUAL "armeabi") OR (ANDROID_ABI STREQUAL "armeabi-v7a") OR (ANDROID_ABI STREQUAL "arm64-v8a") OR +if ((ANDROID_ABI STREQUAL "armeabi-v7a") OR (ANDROID_ABI STREQUAL "arm64-v8a") OR (ANDROID_ABI STREQUAL "x86") OR (ANDROID_ABI STREQUAL "x86_64")) # Use Identical Code Folding on platforms that support the gold linker. set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=gold -Wl,--icf=safe ${CMAKE_EXE_LINKER_FLAGS}") diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index b9744a61ef..ff61b1d074 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -2,24 +2,23 @@ ext { androidVersions = [ minSdkVersion : 14, - targetSdkVersion : 25, - compileSdkVersion: 25, - buildToolsVersion: '26.0.3' + targetSdkVersion : 27, + compileSdkVersion: 27, + buildToolsVersion: '27.0.3' ] versions = [ mapboxServices : '3.1.0', mapboxTelemetry: '3.1.1', mapboxGestures : '0.2.0', - supportLib : '25.4.0', - espresso : '3.0.1', - testRunner : '1.0.1', - leakCanary : '1.5.1', - lost : '3.0.4', + supportLib : '27.1.1', + espresso : '3.0.2', + testRunner : '1.0.2', + leakCanary : '1.5.4', junit : '4.12', - mockito : '2.10.0', - robolectric : '3.5.1', - timber : '4.5.1', + mockito : '2.18.3', + robolectric : '3.8', + timber : '4.7.0', okhttp : '3.10.0' ] @@ -48,7 +47,6 @@ ext { supportDesign : "com.android.support:design:${versions.supportLib}", supportRecyclerView : "com.android.support:recyclerview-v7:${versions.supportLib}", - lost : "com.mapzen.android:lost:${versions.lost}", gmsLocation : 'com.google.android.gms:play-services-location:11.0.4', timber : "com.jakewharton.timber:timber:${versions.timber}", okhttp3 : "com.squareup.okhttp3:okhttp:${versions.okhttp}", diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties index bf1b63c346..84af82d181 100644 --- a/platform/android/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Mon May 14 12:12:39 CEST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/platform/android/src/bitmap.cpp b/platform/android/src/bitmap.cpp index 46e7253050..0d3670b666 100644 --- a/platform/android/src/bitmap.cpp +++ b/platform/android/src/bitmap.cpp @@ -1,6 +1,7 @@ #include "bitmap.hpp" #include +#include namespace mbgl { namespace android { @@ -17,7 +18,7 @@ public: ~PixelGuard() { const int result = AndroidBitmap_unlockPixels(&env, jni::Unwrap(*bitmap)); if (result != ANDROID_BITMAP_RESULT_SUCCESS) { - throw std::runtime_error("bitmap decoding: could not unlock pixels"); + Log::Warning(mbgl::Event::General, "Bitmap decoding: could not unlock pixels"); } } diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp index 34366d836a..f655f13ea8 100644 --- a/platform/android/src/run_loop.cpp +++ b/platform/android/src/run_loop.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -17,6 +18,7 @@ #include #include +#include #define PIPE_OUT 0 #define PIPE_IN 1 @@ -119,11 +121,11 @@ RunLoop::Impl::~Impl() { alarm.reset(); if (ALooper_removeFd(loop, fds[PIPE_OUT]) != 1) { - throw std::runtime_error("Failed to remove file descriptor from Looper."); + Log::Error(mbgl::Event::General, "Failed to remove file descriptor from Looper"); } if (close(fds[PIPE_IN]) || close(fds[PIPE_OUT])) { - throw std::runtime_error("Failed to close file descriptor."); + Log::Error(mbgl::Event::General, "Failed to close file descriptor."); } ALooper_release(loop); -- cgit v1.2.1